class frmMainEPANET(frmMain):
    """Main form for EPANET user interface, based on frmMain which is shared with SWMM."""

    # Variables used to populate the tree control
    # Each item is a list: label plus either editing form for this section or a child list.
    # Special cases may just have a label and no editing form or children.
    # *_items are a lists of items in a section
    tree_options_Hydraulics = ["Hydraulics", frmHydraulicsOptions]
    tree_options_Quality = ["Quality", frmQualityOptions]
    tree_options_Reactions = ["Reactions", frmReactionsOptions]
    tree_options_Times = ["Times", frmTimesOptions]
    tree_options_Energy = ["Energy", frmEnergyOptions]
    tree_options_Report = ["Report", frmReportOptions]
    tree_options_MapBackdrop = ["Map/Backdrop", frmMapBackdropOptions]
    tree_options_items = [
        tree_options_Hydraulics, tree_options_Quality, tree_options_Reactions,
        tree_options_Times, tree_options_Energy, tree_options_Report,
        tree_options_MapBackdrop
    ]

    tree_controls_Simple = [
        "Simple", frmControls, ["EPANET Simple Controls", "CONTROLS"]
    ]
    tree_controls_RuleBased = [
        "Rule-Based", frmControls, ["EPANET Rule-Based Controls", "RULES"]
    ]
    tree_controls_items = [tree_controls_Simple, tree_controls_RuleBased]

    tree_TitleNotes = ["Title/Notes", frmTitle]
    tree_Options = ["Options", tree_options_items]
    tree_Junctions = ["Junctions", frmJunction]
    tree_Reservoirs = ["Reservoirs", frmReservior]
    tree_Tanks = ["Tanks", frmTank]
    tree_Pipes = ["Pipes", frmPipe]
    tree_Pumps = ["Pumps", frmPump]
    tree_Valves = ["Valves", frmValve]
    tree_Labels = ["Labels", None]
    tree_Patterns = ["Patterns", frmPatternEditor]
    tree_Curves = ["Curves", frmCurveEditor]
    tree_Controls = ["Controls", tree_controls_items]
    tree_top_items = [
        tree_TitleNotes, tree_Options, tree_Junctions, tree_Reservoirs,
        tree_Tanks, tree_Pipes, tree_Pumps, tree_Valves, tree_Labels,
        tree_Patterns, tree_Curves, tree_Controls
    ]

    def __init__(self, q_application):
        self.model = "EPANET"
        self.program_settings = QtCore.QSettings(QtCore.QSettings.IniFormat,
                                                 QtCore.QSettings.UserScope,
                                                 "EPA", self.model)
        print("Read program settings from " + self.program_settings.fileName())
        self.model_path = ''  # Set this only if needed later when running model
        self.output = None  # Set this when model output is available
        self.status_suffix = "_status.txt"
        self.status_file_name = ''  # Set this when model status is available
        self.output_filename = ''  # Set this when model output is available
        self.project_type = Project  # Use the model-specific Project as defined in core.epanet.project
        self.project_reader_type = ProjectReader
        self.project_writer_type = ProjectWriter
        self.project = Project()
        self.assembly_path = os.path.dirname(os.path.abspath(__file__))
        frmMain.__init__(self, q_application)
        self.on_load(tree_top_item_list=self.tree_top_items)
        self.tree_types = {
            self.tree_Patterns[0]: Pattern,
            self.tree_Curves[0]: Curve,
            self.tree_Junctions[0]: Junction,
            self.tree_Reservoirs[0]: Reservoir,
            self.tree_Tanks[0]: Tank,
            self.tree_Pipes[0]: Pipe,
            self.tree_Pumps[0]: Pump,
            self.tree_Valves[0]: Valve,
            self.tree_Labels[0]: Label
        }

        self.section_types = {
            Pattern: "patterns",
            Curve: "curves",
            Junction: "junctions",
            Reservoir: "reservoirs",
            Tank: "tanks",
            Pipe: "pipes",
            Pump: "pumps",
            Valve: "valves",
            Label: "labels"
        }

        if self.map_widget:  # initialize empty model map layers, ready to have model elements added
            self.model_layers = ModelLayersEPANET(self.map_widget)

        HelpHandler.init_class(os.path.join(self.assembly_path, "epanet.qhc"))
        self.help_topic = ""  # TODO: specify topic to open when Help key is pressed on main form
        self.helper = HelpHandler(self)

        self.actionStdProjSummary.triggered.connect(
            lambda: self.show_edit_window(self.get_editor("Title/Notes")))
        self.actionStatus_ReportMenu = QtGui.QAction(self)
        self.actionStatus_ReportMenu.setObjectName(
            from_utf8("actionStatus_ReportMenu"))
        self.actionStatus_ReportMenu.setText(transl8("frmMain", "Status",
                                                     None))
        self.actionStatus_ReportMenu.setToolTip(
            transl8("frmMain", "Display Simulation Status", None))
        self.menuReport.addAction(self.actionStatus_ReportMenu)
        QtCore.QObject.connect(self.actionStatus_ReportMenu,
                               QtCore.SIGNAL('triggered()'),
                               self.report_status)
        self.actionProjStatus.triggered.connect(self.report_status)

        self.actionEnergy_ReportMenu = QtGui.QAction(self)
        self.actionEnergy_ReportMenu.setObjectName(
            from_utf8("actionEnergy_ReportMenu"))
        self.actionEnergy_ReportMenu.setText(transl8("frmMain", "Energy",
                                                     None))
        self.actionEnergy_ReportMenu.setToolTip(
            transl8("frmMain", "Display Simulation Energy", None))
        self.menuReport.addAction(self.actionEnergy_ReportMenu)
        QtCore.QObject.connect(self.actionEnergy_ReportMenu,
                               QtCore.SIGNAL('triggered()'),
                               self.report_energy)

        self.actionCalibration_ReportMenu = QtGui.QAction(self)
        self.actionCalibration_ReportMenu.setObjectName(
            from_utf8("actionCalibration_ReportMenu"))
        self.actionCalibration_ReportMenu.setText(
            transl8("frmMain", "Calibration", None))
        self.actionCalibration_ReportMenu.setToolTip(
            transl8("frmMain", "Display Simulation Calibration", None))
        self.menuReport.addAction(self.actionCalibration_ReportMenu)
        QtCore.QObject.connect(self.actionCalibration_ReportMenu,
                               QtCore.SIGNAL('triggered()'),
                               self.report_calibration)

        self.actionReaction_ReportMenu = QtGui.QAction(self)
        self.actionReaction_ReportMenu.setObjectName(
            from_utf8("actionReaction_ReportMenu"))
        self.actionReaction_ReportMenu.setText(
            transl8("frmMain", "Reaction", None))
        self.actionReaction_ReportMenu.setToolTip(
            transl8("frmMain", "Display Simulation Reaction", None))
        self.menuReport.addAction(self.actionReaction_ReportMenu)
        QtCore.QObject.connect(self.actionReaction_ReportMenu,
                               QtCore.SIGNAL('triggered()'),
                               self.report_reaction)

        self.actionFull_ReportMenu = QtGui.QAction(self)
        self.actionFull_ReportMenu.setObjectName(
            from_utf8("actionFull_ReportMenu"))
        self.actionFull_ReportMenu.setText(transl8("frmMain", "Full...", None))
        self.actionFull_ReportMenu.setToolTip(
            transl8("frmMain", "Save full report as text file", None))
        self.menuReport.addAction(self.actionFull_ReportMenu)
        QtCore.QObject.connect(self.actionFull_ReportMenu,
                               QtCore.SIGNAL('triggered()'), self.report_full)

        self.actionGraph_ReportMenu = QtGui.QAction(self)
        self.actionGraph_ReportMenu.setObjectName(
            from_utf8("actionGraph_ReportMenu"))
        self.actionGraph_ReportMenu.setText(
            transl8("frmMain", "Graph...", None))
        self.actionGraph_ReportMenu.setToolTip(
            transl8("frmMain", "Display graph selection options", None))
        self.menuReport.addAction(self.actionGraph_ReportMenu)
        QtCore.QObject.connect(self.actionGraph_ReportMenu,
                               QtCore.SIGNAL('triggered()'), self.report_graph)
        self.actionProjPlotTimeseries.triggered.connect(self.report_graph)
        self.actionProjPlotScatter.triggered.connect(self.report_graph)
        self.actionProjPlotProfile.triggered.connect(self.report_graph)

        self.actionTable_ReportMenu = QtGui.QAction(self)
        self.actionTable_ReportMenu.setObjectName(
            from_utf8("actionTable_ReportMenu"))
        self.actionTable_ReportMenu.setText(
            transl8("frmMain", "Table...", None))
        self.actionTable_ReportMenu.setToolTip(
            transl8("frmMain", "Display table selection options", None))
        self.menuReport.addAction(self.actionTable_ReportMenu)
        QtCore.QObject.connect(self.actionTable_ReportMenu,
                               QtCore.SIGNAL('triggered()'), self.report_table)
        self.actionProjTableTimeseries.triggered.connect(self.report_table)

        self.Help_Topics_Menu = QtGui.QAction(self)
        self.Help_Topics_Menu.setObjectName(from_utf8("Help_Topics_Menu"))
        self.Help_Topics_Menu.setText(transl8("frmMain", "Help Topics", None))
        self.Help_Topics_Menu.setToolTip(
            transl8("frmMain", "Display Help Topics", None))
        self.menuHelp.addAction(self.Help_Topics_Menu)
        QtCore.QObject.connect(self.Help_Topics_Menu,
                               QtCore.SIGNAL('triggered()'), self.help_topics)

        self.Help_About_Menu = QtGui.QAction(self)
        self.Help_About_Menu.setObjectName(from_utf8("Help_About_Menu"))
        self.Help_About_Menu.setText(transl8("frmMain", "About", None))
        self.Help_About_Menu.setToolTip(
            transl8("frmMain", "About EPANET", None))
        self.menuHelp.addAction(self.Help_About_Menu)
        QtCore.QObject.connect(self.Help_About_Menu,
                               QtCore.SIGNAL('triggered()'), self.help_about)

        self.cbFlowUnits.clear()
        self.cbFlowUnits.addItems([
            'Flow Units: CFS', 'Flow Units: GPM', 'Flow Units: MGD',
            'Flow Units: IMGD', 'Flow Units: AFD', 'Flow Units: LPS',
            'Flow Units: LPM', 'Flow Units: MLD', 'Flow Units: CMH',
            'Flow Units: CMD'
        ])
        self.cbFlowUnits.currentIndexChanged.connect(
            self.cbFlowUnits_currentIndexChanged)
        self.cbOffset.setVisible(False)

        if self.map_widget:
            self.map_widget.applyLegend()
            self.map_widget.LegendDock.setVisible(False)
            self.cboMapSubcatchments.setVisible(False)
            self.lblMapSubcatchments.setVisible(False)
            self.set_thematic_controls()
            self.cboMapNodes.currentIndexChanged.connect(
                self.update_thematic_map)
            self.cboMapLinks.currentIndexChanged.connect(
                self.update_thematic_map)
            self.signalTimeChanged.connect(self.update_thematic_map_time)

    def set_thematic_controls(self):
        self.allow_thematic_update = False
        self.cboMapNodes.clear()
        self.cboMapNodes.addItems(
            ['None', 'Elevation', 'Base Demand', 'Initial Quality'])
        self.cboMapLinks.clear()
        self.cboMapLinks.addItems([
            'None', 'Length', 'Diameter', 'Roughness', 'Bulk Coeff.',
            'Wall Coeff.'
        ])
        if self.output:
            # Add object type labels to map combos if there are any of each type in output
            object_type = ENO.ENR_node_type
            if object_type:
                attribute_names = [
                    attribute.name for attribute in object_type.Attributes
                ]
                for item in attribute_names:
                    self.cboMapNodes.addItem(item)
            object_type = ENO.ENR_link_type
            if object_type:
                attribute_names = [
                    attribute.name for attribute in object_type.Attributes
                ]
                for item in attribute_names:
                    self.cboMapLinks.addItem(item)
            self.horizontalTimeSlider.setMaximum(self.output.num_periods - 1)

        self.allow_thematic_update = True
        self.update_thematic_map()

    def update_thematic_map(self):
        if not self.allow_thematic_update or not self.map_widget:
            return

        enable_time_widget = False

        if self.model_layers.nodes_layers:
            selected_attribute = self.cboMapNodes.currentText()
            attribute = None
            setting_index = self.cboMapNodes.currentIndex()
            if setting_index < 4:
                meta_item = Junction.metadata.meta_item_of_label(
                    selected_attribute)
                attribute = meta_item.attribute
            color_by = {}
            self.thematic_node_min = None
            self.thematic_node_max = None
            if attribute:  # Found an attribute of the node class to color by
                for item in self.project.all_nodes():
                    value = float(getattr(item, attribute, 0))
                    color_by[item.name] = value
                    if self.thematic_node_min is None or value < self.thematic_node_min:
                        self.thematic_node_min = value
                    if self.thematic_node_max is None or value > self.thematic_node_max:
                        self.thematic_node_max = value

            elif self.output:  # Look for attribute to color by in the output
                attribute = ENO.ENR_node_type.get_attribute_by_name(
                    selected_attribute)
                if attribute:
                    enable_time_widget = True
                    # find min and max values over entire run
                    for time_increment in range(0,
                                                self.output.num_periods - 1):
                        values = ENO.ENR_node_type.get_attribute_for_all_at_time(
                            self.output, attribute, time_increment)
                        for value in values:
                            if self.thematic_node_min is None or value < self.thematic_node_min:
                                self.thematic_node_min = value
                            if self.thematic_node_max is None or value > self.thematic_node_max:
                                self.thematic_node_max = value
                    values = ENO.ENR_node_type.get_attribute_for_all_at_time(
                        self.output, attribute, self.time_index)
                    index = 0
                    for node in self.output.nodes.values():
                        color_by[node.name] = values[index]
                        index += 1

            for layer in self.model_layers.nodes_layers:
                if layer.isValid():
                    if color_by:
                        self.map_widget.applyGraduatedSymbologyStandardMode(
                            layer, color_by, self.thematic_node_min,
                            self.thematic_node_max)
                    else:
                        self.map_widget.set_default_point_renderer(layer)
                    layer.triggerRepaint()

        if self.model_layers.links_layers:
            selected_attribute = self.cboMapLinks.currentText()
            attribute = None
            setting_index = self.cboMapLinks.currentIndex()
            if setting_index < 6:
                meta_item = Pipe.metadata.meta_item_of_label(
                    selected_attribute)
                attribute = meta_item.attribute
            color_by = {}
            self.thematic_link_min = None
            self.thematic_link_max = None
            if attribute:  # Found an attribute of the pipe class to color by
                for link in self.project.all_links():
                    try:
                        if attribute == 'max_depth':
                            pass
                            # for value in self.project.xsections.value:
                            #     if value.link == conduit.name:
                            #         color_by[conduit.name] = float(value.geometry1)
                        else:
                            color_by[link.name] = float(
                                getattr(link, attribute, 0))
                        if self.thematic_link_min is None or color_by[
                                link.name] < self.thematic_link_min:
                            self.thematic_link_min = color_by[link.name]
                        if self.thematic_link_max is None or color_by[
                                link.name] > self.thematic_link_max:
                            self.thematic_link_max = color_by[link.name]
                    except Exception as exLinkAtt:
                        print("update_thematic_map: link attribute: " +
                              link.name + ': ' + str(exLinkAtt))

            elif self.output:  # Look for attribute to color by in the output
                attribute = ENO.ENR_link_type.get_attribute_by_name(
                    selected_attribute)
                if attribute:
                    enable_time_widget = True
                    # find min and max values over entire run
                    for time_increment in range(0,
                                                self.output.num_periods - 1):
                        values = ENO.ENR_link_type.get_attribute_for_all_at_time(
                            self.output, attribute, time_increment)
                        for value in values:
                            if self.thematic_link_min is None or value < self.thematic_link_min:
                                self.thematic_link_min = value
                            if self.thematic_link_max is None or value > self.thematic_link_max:
                                self.thematic_link_max = value
                    values = ENO.ENR_link_type.get_attribute_for_all_at_time(
                        self.output, attribute, self.time_index)
                    index = 0
                    for link in self.output.links.values():
                        color_by[link.name] = values[index]
                        index += 1
            for layer in self.model_layers.links_layers:
                if layer.isValid():
                    if color_by:
                        self.map_widget.applyGraduatedSymbologyStandardMode(
                            layer, color_by, self.thematic_link_min,
                            self.thematic_link_max)
                    else:
                        self.map_widget.set_default_line_renderer(layer)
                    layer.triggerRepaint()
        self.time_widget.setVisible(enable_time_widget)
        if enable_time_widget:
            self.update_thematic_map_time()

    def update_thematic_map_time(self):
        """
            Update thematic map for the current self.time_index.
            Depends on update_thematic_map having been called since last change to thematic map options.
        """
        try:
            if not self.allow_thematic_update or not self.map_widget:
                return

            if self.model_layers.nodes_layers:
                selected_attribute = self.cboMapNodes.currentText()
                setting_index = self.cboMapNodes.currentIndex()
                color_by = {}
                if setting_index >= 4 and self.output:  # Look for attribute to color by in the output
                    attribute = ENO.ENR_node_type.get_attribute_by_name(
                        selected_attribute)
                    if attribute:
                        values = ENO.ENR_node_type.get_attribute_for_all_at_time(
                            self.output, attribute, self.time_index)
                        index = 0
                        for node in self.output.nodes.values():
                            color_by[node.name] = values[index]
                            index += 1

                for layer in self.model_layers.nodes_layers:
                    if layer.isValid():
                        if color_by:
                            self.map_widget.applyGraduatedSymbologyStandardMode(
                                layer, color_by, self.thematic_node_min,
                                self.thematic_node_max)
                        else:
                            self.map_widget.set_default_point_renderer(layer)
                        layer.triggerRepaint()

            if self.model_layers.links_layers:
                selected_attribute = self.cboMapLinks.currentText()
                setting_index = self.cboMapLinks.currentIndex()
                color_by = {}
                if setting_index >= 6 and self.output:  # Look for attribute to color by in the output
                    attribute = ENO.ENR_link_type.get_attribute_by_name(
                        selected_attribute)
                    if attribute:
                        values = ENO.ENR_link_type.get_attribute_for_all_at_time(
                            self.output, attribute, self.time_index)
                        index = 0
                        for link in self.output.links.values():
                            color_by[link.name] = values[index]
                            index += 1
                for layer in self.model_layers.links_layers:
                    if layer.isValid():
                        if color_by:
                            self.map_widget.applyGraduatedSymbologyStandardMode(
                                layer, color_by, self.thematic_link_min,
                                self.thematic_link_max)
                        else:
                            self.map_widget.set_default_line_renderer(layer)
                        layer.triggerRepaint()
        except Exception as exBig:
            print("Exception in update_thematic_map_time: " + str(exBig))

    def cboMap_currentIndexChanged(self):
        pass

    def cbFlowUnits_currentIndexChanged(self):
        import core.epanet.options.hydraulics
        self.project.options.hydraulics.flow_units = core.epanet.options.hydraulics.FlowUnits[
            self.cbFlowUnits.currentText()[12:]]
        self.project.metric = self.project.options.hydraulics.flow_units in core.epanet.options.hydraulics.flow_units_metric

    def report_status(self):
        print "report_status"
        if not os.path.isfile(self.status_file_name):
            prefix, extension = os.path.splitext(self.project.file_name)
            if os.path.isfile(prefix + self.status_suffix):
                self.status_file_name = prefix + self.status_suffix
        if os.path.isfile(self.status_file_name):
            webbrowser.open_new_tab(self.status_file_name)
        else:
            QMessageBox.information(
                None, self.model, "Model status not found.\n"
                "Run the model to generate model status.", QMessageBox.Ok)

    def report_energy(self):
        if self.output:
            self._frmEnergyReport = frmEnergyReport(self)
            self._frmEnergyReport.set_data(self.project, self.output)
            self._frmEnergyReport.show()
        else:
            QMessageBox.information(
                None, self.model, "Model output not found.\n"
                "Run the model to generate output.", QMessageBox.Ok)

    def report_calibration(self):
        if self.output:
            self._frmCalibrationReportOptions = frmCalibrationReportOptions(
                self, self.project, self.output)
            self._frmCalibrationReportOptions.show()
        else:
            QMessageBox.information(
                None, self.model, "Model output not found.\n"
                "Run the model to generate output.", QMessageBox.Ok)

    def report_reaction(self):
        self.reaction_report()
        pass

    def report_full(self):
        if self.output:
            directory = os.path.dirname(self.project.file_name)
            report_file_name = QtGui.QFileDialog.getSaveFileName(
                self, "Save Full Report As...", directory,
                "Text files (*.txt)")
            if report_file_name:
                try:
                    reporter = reports.Reports(self.project, self.output)
                    reporter.write_report(report_file_name)
                    webbrowser.open_new_tab(report_file_name)
                except Exception as e1:
                    msg = str(e1) + '\n' + str(traceback.print_exc())
                    print(msg)
                    QMessageBox.information(
                        None, self.model, "Error writing report to \n" +
                        report_file_name + '\n' + msg, QMessageBox.Ok)

        else:
            QMessageBox.information(
                None, self.model, "There is no model output currently open.\n"
                "Model output is automatically opened after model is run.",
                QMessageBox.Ok)

    def report_graph(self):
        if self.output:
            self._frmGraph = frmGraph(self)
            self._frmGraph.set_from(self.project, self.output)
            self._frmGraph.show()
        else:
            QMessageBox.information(
                None, self.model, "Model output not found.\n"
                "Run the model to generate output.", QMessageBox.Ok)

    def report_table(self):
        if self.output:
            self._frmTable = frmTable(self)
            self._frmTable.set_from(self.project, self.output)
            self._frmTable.show()
        else:
            QMessageBox.information(
                None, self.model, "Model output not found.\n"
                "Run the model to generate output.", QMessageBox.Ok)

    def reaction_report(self):
        # Reaction Report'
        if self.output:
            # Find conversion factor to kilograms/day
            ucf = 1.0e6 / 24
            quality_options = self.project.options.quality
            if 'ug' in str(quality_options.mass_units):
                ucf = 1.0e9 / 24

            # Get average reaction rates from output file
            bulk, wall, tank, source = self.output.get_reaction_summary()
            bulk /= ucf
            wall /= ucf
            tank /= ucf
            source /= ucf

            if bulk > 0 or wall > 0 or tank > 0 or source > 0:
                footer_text = "Inflow Rate = " + format(source, '0.1f')
            else:
                footer_text = 'No reactions occurred'

            import matplotlib.pyplot as plt

            labels = "%10.1f Tanks" % tank, "%10.1f Bulk" % bulk, "%10.1f Wall" % wall
            sum_reaction = bulk + wall + tank
            size_bulk = bulk / sum_reaction
            size_wall = wall / sum_reaction
            size_tank = tank / sum_reaction
            sizes = [size_tank, size_bulk, size_wall]
            colors = ['green', 'blue', 'red']
            explode = (0, 0, 0)

            plt.figure("Reaction Report")

            plt.pie(sizes,
                    explode=explode,
                    labels=labels,
                    colors=colors,
                    autopct='%1.2f%%',
                    shadow=True,
                    startangle=180)

            plt.axis('equal')
            plt.suptitle("Average Reaction Rates (kg/day)", fontsize=16)
            plt.text(0.9, -0.9, footer_text)

            plt.show()
        else:
            QMessageBox.information(
                None, self.model, "Model output not found.\n"
                "Run the model to generate output.", QMessageBox.Ok)

    def calibration_data(self):
        self._frmCalibrationData = frmCalibrationData(self)
        self._frmCalibrationData.show()
        pass

    def get_editor(self, edit_name):
        frm = None
        # First handle special cases where forms need more than simply being created

        # the following items will respond to a click on a node form, not the tree diagram
        if edit_name == 'Labels':
            edit_these = []
            if self.project and self.project.labels:
                if not isinstance(self.project.labels.value, basestring):
                    if isinstance(self.project.labels.value, list):
                        edit_these.extend(self.project.labels.value)
                if len(edit_these) == 0:
                    new_item = Label()
                    new_item.name = "NewLabel"
                    edit_these.append(new_item)
                    self.project.labels.value = edit_these
                else:
                    self.new_item = False
            frm = frmGenericPropertyEditor(self, edit_these, new_item,
                                           "EPANET Map Label Editor")
            frm.helper = HelpHandler(frm)
            frm.help_topic = "epanet/src/src/maplabeleditordialog.htm"
        elif edit_name == 'Patterns' or edit_name == 'Curves':
            # in these cases the click on the tree diagram populates the lower left list, not directly to an editor
            return None
        elif edit_name == self.tree_Junctions[0] and len(
                self.project.junctions.value) == 0:
            return None
        elif edit_name == self.tree_Reservoirs[0] and len(
                self.project.reservoirs.value) == 0:
            return None
        elif edit_name == self.tree_Tanks[0] and len(
                self.project.tanks.value) == 0:
            return None
        elif edit_name == self.tree_Pipes[0] and len(
                self.project.pipes.value) == 0:
            return None
        elif edit_name == self.tree_Pumps[0] and len(
                self.project.pumps.value) == 0:
            return None
        elif edit_name == self.tree_Valves[0] and len(
                self.project.valves.value) == 0:
            return None
        elif edit_name == self.tree_Labels[0] and len(
                self.project.labels.value) == 0:
            return None
        else:  # General-purpose case finds most editors from tree information
            frm = self.make_editor_from_tree(edit_name, self.tree_top_items)
        return frm

    def get_editor_with_selected_items(self, edit_name, selected_items):
        return self.make_editor_from_tree(edit_name, self.tree_top_items,
                                          selected_items)

    def get_object_list(self, category):
        section = self.project.find_section(category)
        if category == 'Quality' or category == 'Controls' or category == 'Reactions':
            return None
        if section and isinstance(section.value, list):
            return [item.name for item in section.value]
        else:
            return None

    def add_object(self, tree_text):
        item_type = self.tree_types[tree_text]
        new_item = item_type()
        new_item.name = self.new_item_name(item_type)
        self.show_edit_window(
            self.make_editor_from_tree(self.tree_section, self.tree_top_items,
                                       [], new_item))

    def delete_named_object(self, tree_text, item_name):
        item_type = self.tree_types[tree_text]
        section_field_name = self.section_types[item_type]

        if hasattr(self.project, section_field_name):
            section = getattr(self.project, section_field_name)
        else:
            raise Exception("Section not found in project: " +
                            section_field_name)
        item = section.value[item_name]
        self.delete_item(item)

    def run_simulation(self):
        # Find input file to run
        # TODO: decide whether to automatically save to temp location as previous version did.
        use_existing = self.project and self.project.file_name
        if use_existing:
            self.save_project(self.project.file_name)
        elif self.project.all_nodes():
            # unsaved changes to a new project have been made, prompt to save
            if self.save_project_as():
                use_existing = True
            else:
                return None
        else:
            self.open_project()

        inp_file_name = ''
        if self.project:
            inp_file_name = self.project.file_name

        if os.path.exists(inp_file_name):
            current_directory = os.getcwd()
            if not os.path.exists(self.model_path):
                if 'darwin' in sys.platform:
                    lib_name = 'libepanet.dylib.dylib'
                elif 'win' in sys.platform:
                    lib_name = 'epanet2_amd64.dll'
                else:  # Linux
                    lib_name = 'libepanet2_amd64.so'
                self.model_path = self.find_external(lib_name)
            if os.path.exists(self.model_path):
                try:
                    prefix, extension = os.path.splitext(inp_file_name)
                    self.status_file_name = prefix + self.status_suffix
                    self.output_filename = prefix + '.out'
                    working_dir = os.path.abspath(
                        os.path.dirname(inp_file_name))
                    if os.path.isdir(working_dir):
                        print(
                            "Changing into directory containing input file: " +
                            working_dir)
                        os.chdir(working_dir)
                    else:
                        try:
                            import tempfile
                            working_dir = tempfile.gettempdir()
                            print("Changing into temporary directory: " +
                                  working_dir)
                            os.chdir(working_dir)
                        except Exception as err_temp:
                            print(
                                "Could not change into temporary directory: " +
                                str(err_temp))

                    if self.output:
                        self.output.close()
                        self.output = None
                    model_api = ENepanet(inp_file_name, self.status_file_name,
                                         self.output_filename, self.model_path)
                    frmRun = frmRunEPANET(model_api, self.project, self)
                    self._forms.append(frmRun)
                    frmRun.Execute()
                    # self.report_status()
                    try:
                        self.output = ENOutputWrapper.OutputObject(
                            self.output_filename)
                        self.set_thematic_controls()
                        return
                    except Exception as e1:
                        print(str(e1) + '\n' + str(traceback.print_exc()))
                        QMessageBox.information(
                            None, self.model,
                            "Error opening model output:\n {0}\n{1}\n{2}".
                            format(self.output_filename, str(e1),
                                   str(traceback.print_exc())), QMessageBox.Ok)
                except Exception as e1:
                    print(str(e1) + '\n' + str(traceback.print_exc()))
                    QMessageBox.information(
                        None, self.model,
                        "Error running model with library:\n {0}\n{1}\n{2}".
                        format(self.model_path, str(e1),
                               str(traceback.print_exc())), QMessageBox.Ok)
                finally:
                    try:
                        os.chdir(current_directory)
                        if model_api and model_api.isOpen():
                            model_api.ENclose()
                    except:
                        pass
                    return

            # # Could not run with library, try running with executable
            # # Run executable with StatusMonitor0
            # args = []
            # self.modelenv1 = 'EXE_EPANET'
            # program = os.environ[self.modelenv1]
            #
            # exe_name = "epanet2d.exe"
            # exe_path = os.path.join(self.assembly_path, exe_name)
            # if not os.path.exists(exe_path):
            #     pp = os.path.dirname(os.path.dirname(self.assembly_path))
            #     exe_path = os.path.join(pp, "Externals", exe_name)
            # if not os.path.exists(exe_path):
            #     exe_path = QFileDialog.getOpenFileName(self, 'Locate EPANET Executable', '/',
            #                                              'exe files (*.exe)')
            # if os.path.exists(exe_path):
            #     os.environ[self.modelenv1] = exe_path
            # else:
            #     os.environ[self.modelenv1] = ''
            #
            # if not os.path.exists(program):
            #     QMessageBox.information(None, "EPANET", "EPANET Executable not found", QMessageBox.Ok)
            #     return -1
            #
            # args.append(file_name)
            # args.append(prefix + '.txt')
            # args.append(prefix + '.out')
            # status = model_utility.StatusMonitor0(program, args, self, model='EPANET')
            # status.show()
            # os.chdir(current_directory)
        else:
            QMessageBox.information(None, self.model,
                                    self.model + " input file not found",
                                    QMessageBox.Ok)

    def help_topics(self):
        self.helper.show_help()

    def help_about(self):
        self._frmAbout = frmAbout(self)
        self._frmAbout.show()

    def open_project_quiet(self, file_name):
        """ Set wait cursor during open to show operation is in progress.
            Open project from file_name using frmMain.open_project_quiet.
            Create model layers on map and set UI controls from opened project. """
        self.setWaitCursor()
        if file_name:
            self.setWindowTitle("Reading " + file_name)
        if self.map_widget:
            self.map_widget.setVisible(False)
        self.repaint()
        frmMain.open_project_quiet(self, file_name)
        ui.convenience.set_combo(
            self.cbFlowUnits,
            'Flow Units: ' + self.project.options.hydraulics.flow_units.name)

        if self.time_widget:
            self.labelStartTime.setText('0:00')
            self.labelEndTime.setText(self.project.times.duration)
        if self.map_widget:
            try:
                self.model_layers.create_layers_from_project(self.project)
                self.map_widget.zoomfull()
                self.setQgsMapTool(
                )  # Reset any active tool that still has state from old project
            except Exception as ex:
                print(str(ex) + '\n' + str(traceback.print_exc()))
            self.map_widget.setVisible(True)
        self.restoreCursor()
class frmMapDimensions(QDialog):
    def __init__(self, main_form=None, *args):
        QDialog.__init__(self)
        self.helper = HelpHandler(self)
        if main_form.model == "SWMM":
            self.help_topic = "swmm/src/src/mapdimensionsdialog.htm"
        elif main_form.model == "EPANET":
            self.help_topic = "epanet/src/src/Map_Dime.htm"
        self.ui = Ui_frmMapDimensionsDesigner()
        self.ui.setupUi(self)
        self.session = main_form
        self.icon = main_form.windowIcon()
        self.map_widget = self.session.map_widget
        self.options = None
        if args is not None and len(args) > 0:
            self.options = args[0]
        self.ui.rdoUnitDegrees.toggled.connect(self.changeLinearMapUnit)
        self.ui.rdoUnitNone.toggled.connect(self.changeLinearMapUnit)
        self.ui.rdoUnitFeet.toggled.connect(self.changeLinearMapUnit)
        self.ui.rdoUnitMeters.toggled.connect(self.changeLinearMapUnit)
        self.ui.txtLLx.textChanged.connect(
            lambda: self.checkCoords(self.ui.txtLLx.text()))
        self.ui.txtLLy.textChanged.connect(
            lambda: self.checkCoords(self.ui.txtLLy.text()))
        self.ui.txtURx.textChanged.connect(
            lambda: self.checkCoords(self.ui.txtURx.text()))
        self.ui.txtURy.textChanged.connect(
            lambda: self.checkCoords(self.ui.txtURy.text()))
        self.ui.btnAutoSize.clicked.connect(self.autoSetMapDimensions)
        self.ui.buttonBox.accepted.connect(self.setExtent)
        self.ui.btnHelp.clicked.connect(self.show_help)
        self.setupOptions()

    def autoSetMapDimensions(self):
        # Determines map dimensions based on range of vertices' coordinates
        MAXDEGDIGITS = 4  # Max.decimal digits for lat - long degrees pass
        sigDigit = 2
        if self.ui.rdoUnitDegrees.isChecked():
            sigDigit = MAXDEGDIGITS
        self.display_layers_extent()

    def setExtent(self):
        if self.session is None:
            return
        if self.map_widget is None:
            return
        val1, is_val_good1 = self.floatTryParse(self.ui.txtLLx.text())
        val2, is_val_good2 = self.floatTryParse(self.ui.txtLLy.text())
        val3, is_val_good3 = self.floatTryParse(self.ui.txtURx.text())
        val4, is_val_good4 = self.floatTryParse(self.ui.txtURy.text())

        if is_val_good1 and is_val_good2 and is_val_good3 and is_val_good4:
            if val1 == val3 or val2 == val4:
                #MSG_ILLEGAL_MAP_LIMITS
                #LLXEdit.SetFocus
                return
            else:
                self.map_widget.coord_origin.x = val1
                self.map_widget.coord_origin.y = val2
                self.map_widget.coord_fext.x = val3
                self.map_widget.coord_fext.y = val4
                if self.session.project is not None:
                    if self.session.project.map is not None:
                        self.session.project.map.dimensions = (val1, val2,
                                                               val3, val4)
                        self.session.map_widget.set_extent_by_corners(
                            self.session.project.map.dimensions)
                if self.session.project is not None:
                    if self.session.project.backdrop is not None:
                        self.session.project.backdrop.dimensions = (
                            self.ui.txtLLx.text(), self.ui.txtLLy.text(),
                            self.ui.txtURx.text(), self.ui.txtURy.text())
                        if self.ui.rdoUnitFeet.isChecked():
                            if not isinstance(
                                    self.session.project.backdrop.units, str):
                                self.session.project.backdrop.units = self.session.project.backdrop.units.FEET
                            else:
                                self.session.project.backdrop.units = "FEET"
                        elif self.ui.rdoUnitMeters.isChecked():
                            if not isinstance(
                                    self.session.project.backdrop.units, str):
                                self.session.project.backdrop.units = self.session.project.backdrop.units.METERS
                            else:
                                self.session.project.backdrop.units = "METERS"
                        elif self.ui.rdoUnitDegrees.isChecked():
                            if not isinstance(
                                    self.session.project.backdrop.units, str):
                                self.session.project.backdrop.units = self.session.project.backdrop.units.DEGREES
                            else:
                                self.session.project.backdrop.units = "DEGREES"
                        else:
                            if not isinstance(
                                    self.session.project.backdrop.units, str):
                                self.session.project.backdrop.units = self.session.project.backdrop.units.NONE
                            else:
                                self.session.project.backdrop.units = ""
        pass

    def setupOptions(self):
        if self.session is None:
            return
        if self.map_widget is None:
            return

        model_dim = self.session.project.backdrop.dimensions
        if model_dim and model_dim[0] is not None and model_dim[
                1] is not None and model_dim[2] is not None and model_dim[
                    3] is not None:
            #self.ui.txtLLx.setText('{:.3f}'.format(self._main_form.map_widget.coord_origin.x))
            #self.ui.txtLLy.setText('{:.3f}'.format(self._main_form.map_widget.coord_origin.y))
            #self.ui.txtURx.setText('{:.3f}'.format(self._main_form.map_widget.coord_fext.x))
            #self.ui.txtURy.setText('{:.3f}'.format(self._main_form.map_widget.coord_fext.x))
            self.ui.txtLLx.setText(str(model_dim[0]))
            self.ui.txtLLy.setText(str(model_dim[1]))
            self.ui.txtURx.setText(str(model_dim[2]))
            self.ui.txtURy.setText(str(model_dim[3]))
        else:
            self.display_layers_extent()

        if not isinstance(self.session.project.backdrop.units, str):
            units = self.session.project.backdrop.units.name
        else:
            units = self.session.project.backdrop.units.upper()

        if units == "FEET":  # feet
            self.ui.rdoUnitFeet.setChecked(True)
        elif units == "METERS":  # meters
            self.ui.rdoUnitMeters.setChecked(True)
        elif units == "DEGREES":  # degrees
            self.ui.rdoUnitDegrees.setChecked(True)
        else:
            self.ui.rdoUnitNone.setChecked(True)

        self.setWindowIcon(self.icon)

    def display_layers_extent(self):
        if self.session.model_layers:
            llx = 0
            lly = 0
            urx = 10000
            ury = 10000
            layers = []
            for mlyr in self.session.model_layers.all_layers:
                lyr_name = mlyr.name()
                if lyr_name and \
                        (lyr_name.lower().startswith("label") or
                             lyr_name.lower().startswith("subcentroid") or
                             lyr_name.lower().startswith("sublink")):
                    continue
                layers.append(mlyr)
            r = self.session.map_widget.get_extent(layers)
            llx = r.xMinimum()
            lly = r.yMinimum()
            urx = r.xMaximum()
            ury = r.yMaximum()
            self.ui.txtLLx.setText(str(llx))
            self.ui.txtLLy.setText(str(lly))
            self.ui.txtURx.setText(str(urx))
            self.ui.txtURy.setText(str(ury))

    def floatTryParse(self, value):
        try:
            return float(value), True
        except ValueError:
            return value, False

    def changeLinearMapUnit(self):
        if self.session is None:
            return
        if self.map_widget is None:
            return
        if self.ui.rdoUnitDegrees.isChecked():
            self.map_widget.map_linear_unit = self.map_widget.map_unit_names[
                6]  # Degrees
        elif self.ui.rdoUnitMeters.isChecked():
            self.map_widget.map_linear_unit = self.map_widget.map_unit_names[
                0]  # Meters
        elif self.ui.rdoUnitNone.isChecked():
            self.map_widget.map_linear_unit = self.map_widget.map_unit_names[
                7]  # Unknown
        elif self.ui.rdoUnitFeet.isChecked():
            self.map_widget.map_linear_unit = self.map_widget.map_unit_names[
                2]  # Feet

        if self.session.project is not None:
            if self.session.project.map is not None:
                self.session.project.map.setMapUnits(
                    self.session.map_widget.map_linear_unit)
        return

    def checkCoords(self, avalue):
        if len(avalue) == 0:
            return
        if len(avalue) == 1 and avalue[0] == '-':
            return
        val, value_is_good = self.floatTryParse(avalue)
        if not value_is_good:
            msg = QMessageBox()
            msg.setWindowTitle('Map Dimension')
            msg.setText('Coordinate value is not valid numeric value.')
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
            del msg
        pass

    def coordsInGoodFormat(self):
        val1, is_val_good1 = self.floatTryParse(self.ui.txtLLx.text())
        val2, is_val_good2 = self.floatTryParse(self.ui.txtLLy.text())
        val3, is_val_good3 = self.floatTryParse(self.ui.txtURx.text())
        val4, is_val_good4 = self.floatTryParse(self.ui.txtURy.text())
        if is_val_good1 and is_val_good2 and is_val_good3 and is_val_good4:
            if val1 == val3 or val2 == val4:
                #MSG_ILLEGAL_MAP_LIMITS
                #LLXEdit.SetFocus
                return False
            else:
                return True
        else:
            return False

    def show_help(self):
        self.helper.show_help()
Esempio n. 3
0
class frmMainSWMM(frmMain):
    """Main form for SWMM user interface, based on frmMain which is shared with EPANET."""

    # Variables used to populate the tree control
    # Each item is a list: label plus either editing form for this section or a child list of tree variables.
    # If an editing form takes additional arguments, they follow the editing form as a list.
    # Special cases may just have a label and no editing form or children.
    # *_items are a lists of items in a section
    tree_options_General        = ["General",         frmGeneralOptions]
    tree_options_Dates          = ["Dates",           frmDates]
    tree_options_TimeSteps      = ["Time Steps",      frmTimeSteps]
    tree_options_DynamicWave    = ["Dynamic Wave",    frmDynamicWave]
    tree_options_InterfaceFiles = ["Interface Files", frmInterfaceFiles]
    tree_options_Reporting      = ["Reporting",       frmReportOptions]
    tree_options_MapBackdrop    = ["Map/Backdrop",    frmMapBackdropOptions]
    tree_options_items = [
        tree_options_General,
        tree_options_Dates,
        tree_options_TimeSteps,
        tree_options_DynamicWave,
        tree_options_InterfaceFiles,
        tree_options_Reporting,
        tree_options_MapBackdrop]

    tree_climatology_Temperature    = ["Temperature",     frmClimatology, ["Temperature"]]
    tree_climatology_Evaporation    = ["Evaporation",     frmClimatology, ["Evaporation"]]
    tree_climatology_WindSpeed      = ["Wind Speed",      frmClimatology, ["Wind Speed"]]
    tree_climatology_SnowMelt       = ["Snow Melt",       frmClimatology, ["Snow Melt"]]
    tree_climatology_ArealDepletion = ["Areal Depletion", frmClimatology, ["Areal Depletion"]]
    tree_climatology_Adjustment     = ["Adjustment",      frmClimatology, ["Adjustment"]]
    tree_climatology_items = [
        tree_climatology_Temperature,
        tree_climatology_Evaporation,
        tree_climatology_WindSpeed,
        tree_climatology_SnowMelt,
        tree_climatology_ArealDepletion,
        tree_climatology_Adjustment]

    tree_hydrology_RainGages       = ["Rain Gages",       None]
    tree_hydrology_Subcatchments   = ["Subcatchments",    frmSubcatchments]
    tree_hydrology_Aquifers        = ["Aquifers",         frmAquifers]
    tree_hydrology_SnowPacks       = ["Snow Packs",       frmSnowPack]
    tree_hydrology_UnitHydrographs = ["Unit Hydrographs", frmUnitHydrograph]
    tree_hydrology_LIDControls     = ["LID Controls",     frmLID]
    tree_hydrology_items = [
        tree_hydrology_RainGages,
        tree_hydrology_Subcatchments,
        tree_hydrology_Aquifers,
        tree_hydrology_SnowPacks,
        tree_hydrology_UnitHydrographs,
        tree_hydrology_LIDControls]

    tree_nodes_Junctions    = ["Junctions",     frmJunction]
    tree_nodes_Outfalls     = ["Outfalls",      None, "1"]
    tree_nodes_Dividers     = ["Dividers",      None, "1"]
    tree_nodes_StorageUnits = ["Storage Units", None, "1"]
    tree_nodes_items = [
        tree_nodes_Junctions,
        tree_nodes_Outfalls,
        tree_nodes_Dividers,
        tree_nodes_StorageUnits]

    tree_links_Conduits = ["Conduits", frmCrossSection]
    tree_links_Pumps    = ["Pumps",    None]
    tree_links_Orifices = ["Orifices", None]
    tree_links_Weirs    = ["Weirs",    None]
    tree_links_Outlets  = ["Outlets",  None]
    tree_links_items = [
        tree_links_Conduits,
        tree_links_Pumps,
        tree_links_Orifices,
        tree_links_Weirs,
        tree_links_Outlets]

    tree_hydraulics_Nodes     = ["Nodes",     tree_nodes_items]
    tree_hydraulics_Links     = ["Links",     tree_links_items]
    tree_hydraulics_Transects = ["Transects", frmTransect]
    tree_hydraulics_Controls  = ["Controls",  frmControls]
    tree_hydraulics_items = [
        tree_hydraulics_Nodes,
        tree_hydraulics_Links,
        tree_hydraulics_Transects,
        tree_hydraulics_Controls]

    tree_quality_Pollutants = ["Pollutants", None]
    tree_quality_LandUses   = ["Land Uses",  frmLandUses]
    tree_quality_items = [
        tree_quality_Pollutants,
        tree_quality_LandUses]

    tree_curves_ControlCurves   = ["Control Curves",   frmCurveEditor, ["SWMM Control Curves",   "CONTROL"]]
    tree_curves_DiversionCurves = ["Diversion Curves", frmCurveEditor, ["SWMM Diversion Curves", "DIVERSION"]]
    tree_curves_PumpCurves      = ["Pump Curves",      frmCurveEditor, ["SWMM Pump Curves",      "PUMP"]]
    tree_curves_RatingCurves    = ["Rating Curves",    frmCurveEditor, ["SWMM Rating Curves",    "RATING"]]
    tree_curves_ShapeCurves     = ["Shape Curves",     frmCurveEditor, ["SWMM Shape Curves",     "SHAPE"]]
    tree_curves_StorageCurves   = ["Storage Curves",   frmCurveEditor, ["SWMM Storage Curves",   "STORAGE"]]
    tree_curves_TidalCurves     = ["Tidal Curves",     frmCurveEditor, ["SWMM Tidal Curves",     "TIDAL"]]
    tree_curves_items = [
        tree_curves_ControlCurves,
        tree_curves_DiversionCurves,
        tree_curves_PumpCurves,
        tree_curves_RatingCurves,
        tree_curves_ShapeCurves,
        tree_curves_StorageCurves,
        tree_curves_TidalCurves]

    tree_TitleNotes   = ["Title/Notes",   frmTitle]
    tree_Options      = ["Options",       tree_options_items]
    tree_Climatology  = ["Climatology",   tree_climatology_items]
    tree_Hydrology    = ["Hydrology",     tree_hydrology_items]
    tree_Hydraulics   = ["Hydraulics",    tree_hydraulics_items]
    tree_Quality      = ["Quality",       tree_quality_items]
    tree_Curves       = ["Curves",        tree_curves_items]
    tree_TimeSeries   = ["Time Series",   frmTimeseries]
    tree_TimePatterns = ["Time Patterns", frmPatternEditor]
    tree_MapLabels    = ["Map Labels",    None]
    tree_top_items = [
        tree_TitleNotes,
        tree_Options,
        tree_Climatology,
        tree_Hydrology,
        tree_Hydraulics,
        tree_Quality,
        tree_Curves,
        tree_TimeSeries,
        tree_TimePatterns,
        tree_MapLabels]

    tree_items_using_id = (tree_hydrology_LIDControls,
                           tree_hydrology_UnitHydrographs,
                           tree_hydrology_SnowPacks,
                           tree_hydraulics_Transects,
                           tree_quality_LandUses,
                           tree_TimeSeries,
                           tree_TimePatterns,
                           tree_curves_ControlCurves,
                           tree_curves_DiversionCurves,
                           tree_curves_PumpCurves,
                           tree_curves_RatingCurves,
                           tree_curves_ShapeCurves,
                           tree_curves_StorageCurves,
                           tree_curves_TidalCurves)

    def __init__(self, q_application):
        frmMain.__init__(self, q_application)
        self.model = "SWMM"
        self.model_path = ''  # Set this only if needed later when running model
        self.output = None    # Set this when model output is available
        self.status_suffix = "_status.txt"
        self.status_file_name = ''  # Set this when model status is available
        self.output_filename = ''  # Set this when model output is available
        self.project_type = Project  # Use the model-specific Project as defined in core.swmm.project
        self.project = Project()
        self.assembly_path = os.path.dirname(os.path.abspath(__file__))
        self.on_load(tree_top_item_list=self.tree_top_items)
        HelpHandler.init_class(os.path.join(self.assembly_path, "swmm.qhc"))
        self.helper = HelpHandler(self)
        self.help_topic = "swmm/src/src/swmmsmainwindow.htm"

        self.actionStatus_ReportMenu = QtGui.QAction(self)
        self.actionStatus_ReportMenu.setObjectName(from_utf8("actionStatus_ReportMenu"))
        self.actionStatus_ReportMenu.setText(transl8("frmMain", "Status", None))
        self.actionStatus_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Status", None))
        self.menuReport.addAction(self.actionStatus_ReportMenu)
        QtCore.QObject.connect(self.actionStatus_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_status)

        self.actionSummary_ReportMenu = QtGui.QAction(self)
        self.actionSummary_ReportMenu.setObjectName(from_utf8("actionSummary_ReportMenu"))
        self.actionSummary_ReportMenu.setText(transl8("frmMain", "Summary", None))
        self.actionSummary_ReportMenu.setToolTip(transl8("frmMain", "Display Results Summary", None))
        self.menuReport.addAction(self.actionSummary_ReportMenu)
        QtCore.QObject.connect(self.actionSummary_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_summary)

        menu = QtGui.QMenu()
        submenuGraph = QtGui.QMenu(self.menuReport)
        submenuGraph.setTitle("Graph")
        self.menuReport.addMenu(submenuGraph)

        self.actionGraph_ProfileMenu = QtGui.QAction(self)
        self.actionGraph_ProfileMenu.setObjectName(from_utf8("actionGraph_ProfileMenu"))
        self.actionGraph_ProfileMenu.setText(transl8("frmMain", "Profile", None))
        self.actionGraph_ProfileMenu.setToolTip(transl8("frmMain", "Display Profile Plot", None))
        submenuGraph.addAction(self.actionGraph_ProfileMenu)
        QtCore.QObject.connect(self.actionGraph_ProfileMenu, QtCore.SIGNAL('triggered()'), self.report_profile)

        self.actionGraph_TimeSeriesMenu = QtGui.QAction(self)
        self.actionGraph_TimeSeriesMenu.setObjectName(from_utf8("actionGraph_TimeSeriesMenu"))
        self.actionGraph_TimeSeriesMenu.setText(transl8("frmMain", "Time Series", None))
        self.actionGraph_TimeSeriesMenu.setToolTip(transl8("frmMain", "Display Time Series Plot", None))
        submenuGraph.addAction(self.actionGraph_TimeSeriesMenu)
        QtCore.QObject.connect(self.actionGraph_TimeSeriesMenu, QtCore.SIGNAL('triggered()'), self.report_timeseries)

        self.actionGraph_ScatterMenu = QtGui.QAction(self)
        self.actionGraph_ScatterMenu.setObjectName(from_utf8("actionGraph_ScatterMenu"))
        self.actionGraph_ScatterMenu.setText(transl8("frmMain", "Scatter", None))
        self.actionGraph_ScatterMenu.setToolTip(transl8("frmMain", "Display Scatter Plot", None))
        submenuGraph.addAction(self.actionGraph_ScatterMenu)
        QtCore.QObject.connect(self.actionGraph_ScatterMenu, QtCore.SIGNAL('triggered()'), self.report_scatter)

        self.actionTable_VariableMenu = QtGui.QAction(self)
        self.actionTable_VariableMenu.setObjectName(from_utf8("actionTable_VariableMenu"))
        self.actionTable_VariableMenu.setText(transl8("frmMain", "Table", None))
        self.actionTable_VariableMenu.setToolTip(transl8("frmMain", "Display Table", None))
        self.menuReport.addAction(self.actionTable_VariableMenu)
        QtCore.QObject.connect(self.actionTable_VariableMenu, QtCore.SIGNAL('triggered()'), self.report_variable)

        self.actionStatistics_ReportMenu = QtGui.QAction(self)
        self.actionStatistics_ReportMenu.setObjectName(from_utf8("actionStatistics_ReportMenu"))
        self.actionStatistics_ReportMenu.setText(transl8("frmMain", "Statistics", None))
        self.actionStatistics_ReportMenu.setToolTip(transl8("frmMain", "Display Results Statistics", None))
        self.menuReport.addAction(self.actionStatistics_ReportMenu)
        QtCore.QObject.connect(self.actionStatistics_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_statistics)

        self.Help_Topics_Menu = QtGui.QAction(self)
        self.Help_Topics_Menu.setObjectName(from_utf8("Help_Topics_Menu"))
        self.Help_Topics_Menu.setText(transl8("frmMain", "Help Topics", None))
        self.Help_Topics_Menu.setToolTip(transl8("frmMain", "Display Help Topics", None))
        self.menuHelp.addAction(self.Help_Topics_Menu)
        QtCore.QObject.connect(self.Help_Topics_Menu, QtCore.SIGNAL('triggered()'), self.help_topics)

        self.Help_About_Menu = QtGui.QAction(self)
        self.Help_About_Menu.setObjectName(from_utf8("Help_About_Menu"))
        self.Help_About_Menu.setText(transl8("frmMain", "About", None))
        self.Help_About_Menu.setToolTip(transl8("frmMain", "About SWMM", None))
        self.menuHelp.addAction(self.Help_About_Menu)
        QtCore.QObject.connect(self.Help_About_Menu, QtCore.SIGNAL('triggered()'), self.help_about)

    def get_output(self):
        if not self.output:
            if os.path.isfile(self.output_filename):
                self.output = SMOutputWrapper.OutputObject(self.output_filename)
        return self.output

    def report_status(self):
        print "report_status"
        if not os.path.isfile(self.status_file_name):
            prefix, extension = os.path.splitext(self.project.file_name)
            if os.path.isfile(prefix + self.status_suffix):
                self.status_file_name = prefix + self.status_suffix
        if os.path.isfile(self.status_file_name):
            webbrowser.open_new_tab(self.status_file_name)
        else:
            QMessageBox.information(None, self.model,
                                    "Model status not found.\n"
                                    "Run the model to generate model status.",
                                    QMessageBox.Ok)

    def report_profile(self):
        if self.get_output():
            self._frmProfilePlot = frmProfilePlot(self)
            self._frmProfilePlot.set_from(self.project, self.get_output())
            self._frmProfilePlot.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_timeseries(self):
        if self.get_output():
            self._frmTimeSeriesPlot = frmTimeSeriesPlot(self)
            self._frmTimeSeriesPlot.set_from(self.project, self.get_output())
            self._frmTimeSeriesPlot.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_scatter(self):
        if self.get_output():
            self._frmScatterPlot = frmScatterPlot(self)
            self._frmScatterPlot.set_from(self.project, self.get_output())
            self._frmScatterPlot.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_variable(self):
        if self.get_output():
            self._frmTableSelection = frmTableSelection(self)
            self._frmTableSelection.set_from(self.project, self.get_output())
            self._frmTableSelection.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_statistics(self):
        if self.get_output():
            self._frmStatisticsReportSelection = frmStatisticsReportSelection(self)
            self._frmStatisticsReportSelection.set_from(self.project, self.get_output())
            self._frmStatisticsReportSelection.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_summary(self):
        if not os.path.isfile(self.status_file_name):
            prefix, extension = os.path.splitext(self.project.file_name)
            if os.path.isfile(prefix + self.status_suffix):
                self.status_file_name = prefix + self.status_suffix
        if os.path.isfile(self.status_file_name):
            self._frmSummaryReport = frmSummaryReport(self)
            self._frmSummaryReport.set_from(self.project, self.status_file_name)
            self._frmSummaryReport.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model status not found.\n"
                                    "Run the model to generate model status.",
                                    QMessageBox.Ok)

    def calibration_data(self):
        self._frmCalibrationData = frmCalibrationData(self)
        self._frmCalibrationData.show()
        pass

    def get_editor(self, edit_name):
        frm = None
        # First handle special cases where forms need more than simply being created

        if edit_name == self.tree_quality_Pollutants[0]:
            edit_these = []
            if self.project and self.project.pollutants:
                if not isinstance(self.project.pollutants.value, basestring):
                    if isinstance(self.project.pollutants.value, list):
                        edit_these.extend(self.project.pollutants.value)
                if len(edit_these) == 0:
                    new_item = Pollutant()
                    new_item.name = "NewPollutant"
                    edit_these.append(new_item)
                    self.project.pollutants.value = edit_these
            frm = frmGenericPropertyEditor(self, edit_these, "SWMM Pollutant Editor")
            frm.helper = HelpHandler(frm)
            frm.help_topic = "swmm/src/src/pollutanteditordialog.htm"
        elif edit_name in [item[0] for item in self.tree_items_using_id]:
            # in these cases the click on the tree diagram populates the lower left list, not directly to an editor
            return None
        # the following items will respond to a click on a conduit form, not the tree diagram
        # elif edit_name == tree_links_Conduits[0]:
        #     frm = frmCrossSection(self)

        # the following items will respond to a click on a node form, not the tree diagram
        # elif edit_name == "Outfalls" or edit_name == "Dividers" or edit_name == "Storage Units":
        #     frm = frmInflows(self)
        else:  # General-purpose case finds most editors from tree information
            frm = self.make_editor_from_tree(edit_name, self.tree_top_items)

        return frm

    def get_editor_with_selected_item(self, edit_name, selected_item):
        frm = None
        # First handle special cases where forms need more than simply being created

        if edit_name == "Pollutants":
            edit_these = []
            if self.project and self.project.pollutants:
                if not isinstance(self.project.pollutants.value, basestring):
                    if isinstance(self.project.pollutants.value, list):
                        for value in self.project.pollutants.value:
                            if value.name == selected_item:
                                edit_these.append(value)
            frm = frmGenericPropertyEditor(self, edit_these, "SWMM Pollutant Editor")
        elif edit_name == "Aquifers":
            # do all of these for now, will want to restrict to only selected one
            frm = self.make_editor_from_tree(edit_name, self.tree_top_items)
        # the following items will respond to a click on a conduit form, not the tree diagram
        elif edit_name == "Conduits":
            frm = frmCrossSection(self)

        # the following items will respond to a click on a node form, not the tree diagram
        # elif edit_name == "Outfalls" or edit_name == "Dividers" or edit_name == "Storage Units":
        #     frm = frmInflows(self)
        else:  # General-purpose case finds most editors from tree information
            frm = self.make_editor_from_tree(edit_name, self.tree_top_items)
            frm.set_from(self.project, selected_item)
        return frm

    def get_object_list(self, category):
        ids = []
        if category == self.tree_hydrology_Subcatchments[0]:
            for i in range(0, len(self.project.subcatchments.value)):
                ids.append(self.project.subcatchments.value[i].name)
        # elif category.lower() == self.tree_hydrology_RainGages[0]:
            # for i in range(0, len(self.project.raingages.value)):
            #     ids.append(self.project.raingages.value[i].name)
        elif category == self.tree_hydrology_Aquifers[0]:
            for i in range(0, len(self.project.aquifers.value)):
                ids.append(self.project.aquifers.value[i].name)
        elif category == self.tree_hydrology_SnowPacks[0]:
            for i in range(0, len(self.project.snowpacks.value)):
                ids.append(self.project.snowpacks.value[i].name)
        elif category == self.tree_hydrology_UnitHydrographs[0]:
            for i in range(0, len(self.project.hydrographs.value)):
                ids.append(self.project.hydrographs.value[i].group_name)
        elif category == self.tree_hydrology_LIDControls[0]:
            for i in range(0, len(self.project.lid_controls.value)):
                ids.append(self.project.lid_controls.value[i].control_name)
        elif category == self.tree_nodes_Junctions[0]:
            for i in range(0, len(self.project.junctions.value)):
                ids.append(self.project.junctions.value[i].name)
        # elif category == self.tree_nodes_Outfalls[0]:
            # for i in range(0, len(self.project.outfalls.value)):
            #     ids.append(self.project.outfalls.value[i].name)
        # elif category == self.tree_nodes_Dividers[0]:
            # for i in range(0, len(self.project.dividers.value)):
            #     ids.append(self.project.dividers.value[i].name)
        # elif category == self.tree_nodes_StorageUnits[0]:
            # for i in range(0, len(self.project.storage.value)):
            #     ids.append(self.project.storage.value[i].name)
        elif category == self.tree_links_Conduits[0]:
            for i in range(0, len(self.project.conduits.value)):
                ids.append(self.project.conduits.value[i].name)
        elif category == self.tree_links_Pumps:
            for i in range(0, len(self.project.pumps.value)):
                ids.append(self.project.pumps.value[i].name)
        # elif category == self.tree_links_Orifices[0]:
            # for i in range(0, len(self.project.orifices.value)):
            #     ids.append(self.project.orifices.value[i].name)
        # elif category == self.tree_links_Weirs[0]:
            # for i in range(0, len(self.project.weirs.value)):
            #     ids.append(self.project.weirs.value[i].name)
        # elif category == self.tree_links_Outlets[0]:
            # for i in range(0, len(self.project.outlets.value)):
            #     ids.append(self.project.outlets.value[i].name)
        elif category == self.tree_hydraulics_Transects[0]:
            for i in range(0, len(self.project.transects.value)):
                ids.append(self.project.transects.value[i].name)
        elif category == self.tree_quality_Pollutants[0]:
            for i in range(0, len(self.project.pollutants.value)):
                ids.append(self.project.pollutants.value[i].name)
        elif category == self.tree_quality_LandUses[0]:
            for i in range(0, len(self.project.landuses.value)):
                ids.append(self.project.landuses.value[i].land_use_name)
        elif category == self.tree_curves_ControlCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                if self.project.curves.value[i].curve_type == CurveType.CONTROL:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_curves_DiversionCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                if self.project.curves.value[i].curve_type == CurveType.DIVERSION:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_curves_PumpCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                curve_type = self.project.curves.value[i].curve_type
                if curve_type == CurveType.PUMP1 or curve_type == CurveType.PUMP2 or \
                    curve_type == CurveType.PUMP3 or curve_type == CurveType.PUMP4:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_curves_RatingCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                if self.project.curves.value[i].curve_type == CurveType.RATING:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_curves_ShapeCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                if self.project.curves.value[i].curve_type == CurveType.SHAPE:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_curves_StorageCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                if self.project.curves.value[i].curve_type == CurveType.STORAGE:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_curves_TidalCurves[0]:
            for i in range(0, len(self.project.curves.value)):
                if self.project.curves.value[i].curve_type == CurveType.TIDAL:
                    ids.append(self.project.curves.value[i].curve_id)
        elif category == self.tree_TimeSeries[0]:
            for i in range(0, len(self.project.timeseries.value)):
                ids.append(self.project.timeseries.value[i].name)
        elif category == self.tree_TimePatterns[0]:
            for i in range(0, len(self.project.patterns.value)):
                ids.append(self.project.patterns.value[i].name)
        # elif category == self.tree_MapLabels[0]:
            # for i in range(0, len(self.project.labels.value)):
            #     ids.append(self.project.labels.value[i].label_text)
        else:
            ids = None
        return ids

    def add_object_clicked(self, section_name):
        if section_name == self.tree_hydrology_Subcatchments[0]:
            new_item = Subcatchment()
            new_item.name = "New"
            if len(self.project.subcatchments.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.subcatchments.value = edit_these
            else:
                self.project.subcatchments.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        # elif section_name == self.tree_hydrology_RainGages[0]:
        elif section_name == self.tree_hydrology_Aquifers[0]:
            new_item = Aquifer()
            new_item.name = "New"
            if len(self.project.aquifers.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.aquifers.value = edit_these
            else:
                self.project.aquifers.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        elif section_name == self.tree_hydrology_SnowPacks[0]:
            new_item = SnowPack()
            new_item.name = "New"
            if len(self.project.snowpacks.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.snowpacks.value = edit_these
            else:
                self.project.snowpacks.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        elif section_name == self.tree_hydrology_UnitHydrographs[0]:
            new_item = UnitHydrograph()
            new_item.group_name = "New"
            if len(self.project.hydrographs.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.hydrographs.value = edit_these
            else:
                self.project.hydrographs.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.group_name))
        elif section_name == self.tree_hydrology_LIDControls[0]:
            new_item = LIDControl()
            new_item.control_name = "New"
            if len(self.project.lid_controls.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.lid_controls.value = edit_these
            else:
                self.project.lid_controls.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.control_name))
        elif section_name == self.tree_nodes_Junctions[0]:
            new_item = Junction()
            new_item.name = "New"
            if len(self.project.junctions.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.junctions.value = edit_these
            else:
                self.project.junctions.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        # elif section_name == self.tree_nodes_Outfalls[0]:
        # elif section_name == self.tree_nodes_Dividers[0]:
        # elif section_name == self.tree_nodes_StorageUnits[0]:
        elif section_name == self.tree_links_Conduits[0]:
            new_item = Conduit()
            new_item.name = "New"
            if len(self.project.conduits.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.conduits.value = edit_these
            else:
                self.project.conduits.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        elif section_name == self.tree_links_Pumps:
            new_item = Pump()
            new_item.name = "New"
            if len(self.project.pumps.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.pumps.value = edit_these
            else:
                self.project.pumps.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        # elif section_name == self.tree_links_Orifices[0]:
        # elif section_name == self.tree_links_Weirs[0]:
        # elif section_name == self.tree_links_Outlets[0]:
        elif section_name == self.tree_hydraulics_Transects[0]:
            new_item = Transect()
            new_item.name = "New"
            if len(self.project.transects.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.transects.value = edit_these
            else:
                self.project.transects.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        elif section_name == self.tree_quality_Pollutants[0]:
            new_item = Pollutant()
            new_item.name = "NewPollutant"
            if len(self.project.pollutants.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.pollutants.value = edit_these
            else:
                self.project.pollutants.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        elif section_name == self.tree_quality_LandUses[0]:
            new_item = Landuse()
            new_item.land_use_name = "New"
            if len(self.project.landuses.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.landuses.value = edit_these
            else:
                self.project.landuses.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.land_use_name))
        elif section_name == self.tree_curves_ControlCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.CONTROL
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_curves_DiversionCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.DIVERSION
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_curves_PumpCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.PUMP1
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_curves_RatingCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.RATING
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_curves_ShapeCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.SHAPE
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_curves_StorageCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.STORAGE
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_curves_TidalCurves[0]:
            new_item = Curve()
            new_item.curve_id = "New"
            new_item.curve_type = CurveType.TIDAL
            if len(self.project.curves.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.curves.value = edit_these
            else:
                self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == self.tree_TimeSeries[0]:
            new_item = TimeSeries()
            new_item.name = "New"
            if len(self.project.timeseries.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.timeseries.value = edit_these
            else:
                self.project.timeseries.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        elif section_name == self.tree_TimePatterns[0]:
            new_item = Pattern()
            new_item.name = "New"
            if len(self.project.patterns.value) == 0:
                edit_these = []
                edit_these.append(new_item)
                self.project.patterns.value = edit_these
            else:
                self.project.patterns.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.name))
        # elif section_name == self.tree_MapLabels[0]:

    def delete_object_clicked(self, section_name, item_name):
        if section_name == self.tree_hydrology_Subcatchments[0]:
            for value in self.project.subcatchments.value:
                if value.name == item_name:
                    self.project.subcatchments.value.remove(value)
        # elif section_name == self.tree_hydrology_RainGages[0]:
        elif section_name == self.tree_hydrology_Aquifers[0]:
            for value in self.project.aquifers.value:
                if value.name == item_name:
                    self.project.aquifers.value.remove(value)
        elif section_name == self.tree_hydrology_SnowPacks[0]:
            for value in self.project.snowpacks.value:
                if value.name == item_name:
                    self.project.snowpacks.value.remove(value)
        elif section_name == self.tree_hydrology_UnitHydrographs[0]:
            for value in self.project.hydrographs.value:
                if value.group_name == item_name:
                    self.project.hydrographs.value.remove(value)
        elif section_name == self.tree_hydrology_LIDControls[0]:
            for value in self.project.lid_controls.value:
                if value.control_name == item_name:
                    self.project.lid_controls.value.remove(value)
        elif section_name == self.tree_nodes_Junctions[0]:
            for value in self.project.junctions.value:
                if value.name == item_name:
                    self.project.junctions.value.remove(value)
        # elif section_name == self.tree_nodes_Outfalls[0]:
        # elif section_name == self.tree_nodes_Dividers[0]:
        # elif section_name == self.tree_nodes_StorageUnits[0]:
        elif section_name == self.tree_links_Conduits[0]:
            for value in self.project.conduits.value:
                if value.name == item_name:
                    self.project.conduits.value.remove(value)
        elif section_name == self.tree_links_Pumps:
            for value in self.project.pumps.value:
                if value.name == item_name:
                    self.project.pumps.value.remove(value)
        # elif section_name == self.tree_links_Orifices[0]:
        # elif section_name == self.tree_links_Weirs[0]:
        # elif section_name == self.tree_links_Outlets[0]:
        elif section_name == self.tree_hydraulics_Transects[0]:
            for value in self.project.transects.value:
                if value.name == item_name:
                    self.project.transects.value.remove(value)
        elif section_name == self.tree_quality_Pollutants[0]:
           for value in self.project.pollutants.value:
                if value.name == item_name:
                    self.project.pollutants.value.remove(value)
        elif section_name == self.tree_quality_LandUses[0]:
            for value in self.project.landuses.value:
                if value.land_use_name == item_name:
                    self.project.landuses.value.remove(value)
        elif section_name == self.tree_curves_ControlCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and value.curve_type == CurveType.CONTROL:
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_curves_DiversionCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and value.curve_type == CurveType.DIVERSION:
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_curves_PumpCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and \
                        (value.curve_type == CurveType.PUMP1 or value.curve_type == CurveType.PUMP2
                         or value.curve_type == CurveType.PUMP3 or value.curve_type == CurveType.PUMP4):
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_curves_RatingCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and value.curve_type == CurveType.RATING:
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_curves_ShapeCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and value.curve_type == CurveType.SHAPE:
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_curves_StorageCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and value.curve_type == CurveType.STORAGE:
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_curves_TidalCurves[0]:
            for value in self.project.curves.value:
                if value.curve_id == item_name and value.curve_type == CurveType.TIDAL:
                    self.project.curves.value.remove(value)
        elif section_name == self.tree_TimeSeries[0]:
            for value in self.project.timeseries.value:
                if value.name == item_name:
                    self.project.timeseries.value.remove(value)
        elif section_name == self.tree_TimePatterns[0]:
            for value in self.project.patterns.value:
                if value.name == item_name:
                    self.project.patterns.value.remove(value)
        # elif section_name == self.tree_MapLabels[0]:

    def run_simulation(self):
        self.output = None
        # First find input file to run
        file_name = ''
        use_existing = self.project and self.project.file_name and os.path.exists(self.project.file_name)
        if use_existing:
            file_name = self.project.file_name
            # TODO: save if needed, decide whether to save to temp location as previous version did.
        else:
            directory = QtCore.QSettings(self.model, "GUI").value("ProjectDir", "")
            file_name = QFileDialog.getOpenFileName(self, "Open Project...", directory,
                                                          "Inp files (*.inp);;All files (*.*)")
        if os.path.exists(file_name):

            prefix, extension = os.path.splitext(file_name)
            self.status_file_name = prefix + self.status_suffix
            self.output_filename = prefix + '.out'
            # if not os.path.exists(self.model_path):
            #     if 'darwin' in sys.platform:
            #         lib_name = 'libswmm.dylib'
            #         ext = '.dylib'
            #     elif 'win' in sys.platform:
            #         lib_name = 'swmm5_x86.dll'
            #         ext = '.dll'
            #
            #     if lib_name:
            #         self.model_path = os.path.join(self.assembly_path, lib_name)
            #         if not os.path.exists(self.model_path):
            #             pp = os.path.dirname(os.path.dirname(self.assembly_path))
            #             self.model_path = os.path.join(pp, "Externals", lib_name)
            #         if not os.path.exists(self.model_path):
            #             self.model_path = QFileDialog.getOpenFileName(self,
            #                                                           'Locate ' + self.model +' Library',
            #                                                           '/', '(*{0})'.format(ext))
            #
            # if os.path.exists(self.model_path):
            #     try:
            #         from Externals.swmm5 import pyswmm
            #         swmm_object = pyswmm(file_name, self.status_file_name, self.output_filename, self.model_path)
            #         swmm_object.swmmExec()
            #         print(swmm_object.swmm_getVersion())
            #         print(swmm_object.swmm_getMassBalErr())
            #
            #         # model_api = pyepanet.ENepanet(file_name, self.status_file_name, self.output_filename, self.model_path)
            #         # frmRun = frmRunEPANET(model_api, self.project, self)
            #         # self._forms.append(frmRun)
            #         # if not use_existing:
            #         #     # Read this project so we can refer to it while running
            #         #     frmRun.progressBar.setVisible(False)
            #         #     frmRun.lblTime.setVisible(False)
            #         #     frmRun.fraTime.setVisible(False)
            #         #     frmRun.fraBottom.setVisible(False)
            #         #     frmRun.showNormal()
            #         #     frmRun.set_status_text("Reading " + file_name)
            #         #
            #         #     self.project = Project()
            #         #     self.project.read_file(file_name)
            #         #     frmRun.project = self.project
            #         #
            #         # frmRun.Execute()
            #         return
            #     except Exception as e1:
            #         print(str(e1) + '\n' + str(traceback.print_exc()))
            #         QMessageBox.information(None, self.model,
            #                                 "Error running model with library:\n {0}\n{1}\n{2}".format(
            #                                     self.model_path, str(e1), str(traceback.print_exc())),
            #                                 QMessageBox.Ok)
            #     # finally:
            #     #     try:
            #     #         if model_api and model_api.isOpen():
            #     #             model_api.ENclose()
            #     #     except:
            #     #         pass
            #     #     return

            # Could not run with library, try running with executable
            args = []
            exe_name = "swmm5.exe"
            exe_path = os.path.join(self.assembly_path, exe_name)
            if not os.path.isfile(exe_path):
                pp = os.path.dirname(os.path.dirname(self.assembly_path))
                exe_path = os.path.join(pp, "Externals", exe_name)
            if not os.path.isfile(exe_path):
                pp = os.path.dirname(os.path.dirname(self.assembly_path))
                exe_path = os.path.join(pp, "Externals", "swmm", "model", exe_name)
            if not os.path.isfile(exe_path):
                exe_path = QFileDialog.getOpenFileName(self, 'Locate SWMM Executable', '/', 'exe files (*.exe)')
            if os.path.isfile(exe_path):
                args.append(file_name)
                args.append(self.status_file_name)
                args.append(self.output_filename)
                # running the Exe
                status = StatusMonitor0(exe_path, args, self, model='SWMM')
                status.show()
        else:
            QMessageBox.information(None, self.model, self.model + " input file not found", QMessageBox.Ok)

    def help_topics(self):
        self.helper.show_help()

    def help_about(self):
        self._frmAbout = frmAbout(self)
        self._frmAbout.show()
        pass
Esempio n. 4
0
class frmPlotViewer(QMainWindow, Ui_frmPlot):
    """
    Generic plot viewer window that can copy, save, and print a plot
    - Time Series Viewer
    """

    # MAGIC = "TSGRAPHSPEC:"

    def __init__(self, dataset, plot_type, plot_title, window_icon, x_title,
                 y_title):
        """
        Constructor
        Args:
            dataset: time series data as pandas data frame
        """
        QMainWindow.__init__(self)
        self.helper = HelpHandler(self)
        self.setupUi(self)
        self.setWindowIcon(window_icon)

        self.actionPrint.setVisible(False)
        self.actionSave.setVisible(False)
        self.actionCopy.setVisible(False)
        self.menuFile.setEnabled(False)
        self.menuFile.setVisible(False)
        self.menuFile.deleteLater()

        self.dataset = dataset
        self.plot_title = plot_title
        self.x_title = x_title
        self.y_title = y_title
        if plot_type == 'time':
            self.plot_type = 'timeseries'
            self.help_topic = "swmm/src/src/timeserieseditordialog.htm"
        elif plot_type == 'xy':
            self.plot_type = 'xy'
            self.help_topic = "swmm/src/src/transecteditordialog.htm"
        elif plot_type == 'step':
            self.plot_type = 'step'
            self.help_topic = ''  # TODO
        # self.plot = CurvePlot(self.fraPlot, width=6, height=2, dpi=100)
        # layout = QVBoxLayout(self.fraPlot)
        # layout.setContentsMargins(0, 0, 0, 0)
        # layout.addWidget(self.plot)
        # self.fraPlot.setLayout(layout)
        self.helper = HelpHandler(self)

        self.Xunits = {}
        self.Yunits = {}
        self.Xlabel = ""
        self.Ylabel = ""
        self.Xunit = ""
        self.Yunit = ""
        self.TXT_OPEN_CURVE_TITLE = 'Open a Curve'
        self.TXT_SAVE_CURVE_TITLE = 'Save Curve As'
        self.TXT_CURVE_FILTER = 'Curve files (*.CRV)|*.CRV|All files|*.*'
        self.xvals = []
        self.yvals = []
        self.btnClose.clicked.connect(self.frm_close)
        self.btnHelp.clicked.connect(self.get_help)
        self.actionOpen.triggered.connect(self.open_datafile)
        self.actionCopy.triggered.connect(self.copy_plot)
        self.actionSave.triggered.connect(self.save_plot)
        self.actionPrint.triggered.connect(self.print_plot)
        # self.installEventFilter(self)
        self.do_plot()

    def open_datafile(self):
        pass

    def copy_plot(self):
        pass

    def save_plot(self):
        pass

    def print_plot(self):
        pass

    def do_plot(self):
        """
        Construct a plot of the dataset
        ToDo: based on user-specified plot type
        Returns:

        """
        if self.dataset.shape[0] > 0 and self.dataset.shape[1] > 0:
            if self.plot_type == 'timeseries':
                # self.plot.setTitle(self.plot_title)
                # self.plot.set_time_series_data(self.dataset)
                self.set_time_series_data(self.dataset)
            elif self.plot_type == 'xy':
                # self.plot.setTitle(self.plot_title)
                # self.plot.set_xy_data(self.dataset, self.x_title, self.y_title)
                self.set_xy_data(self.dataset, self.x_title, self.y_title)
            elif self.plot_type == 'step':
                # self.plot.setTitle(self.plot_title)
                # self.plot.set_xy_data(self.dataset, self.x_title, self.y_title, step=True)
                self.set_xy_data(self.dataset,
                                 self.x_title,
                                 self.y_title,
                                 step=True)
        pass

    def frm_close(self):
        """
        Close the plot form and discard dataset
        Returns:

        """
        self.close()

    def get_help(self):
        self.helper.show_help()

    def set_xy_data(self, df, x_title, y_title, step=False):
        if df.shape[0] > 0 and df.shape[1] > 0:
            x = []
            y = []
            for row in range(len(df)):
                x.append(float(df.index[row]))
                y.append(float(df.iloc[row][0]))

            # the way frmScatterPlot does it:
            import matplotlib.pyplot as plt
            fig = plt.figure()
            fig.canvas.set_window_title(self.plot_title)
            plt.title(self.plot_title)

            plt.scatter(x,
                        y,
                        s=50,
                        c="lightblue",
                        edgecolors="blue",
                        alpha=0.5)
            plt.plot(x, y, color='red')

            plt.xlabel(x_title)
            plt.ylabel(y_title)

            plt.grid(True)
            plt.show(block=True)

    def set_time_series_data(self, df):
        if df.shape[0] > 0 and df.shape[1] > 0:
            x = []
            y = []
            for row in range(len(df)):
                if df.hour_only:
                    x.append(df.index[row])
                else:
                    x.append(mdates.date2num(df.index[row]))
                y.append(df.iloc[row][0])

            # the way frmTimeSeriesPlot does it:
            import matplotlib.pyplot as plt
            fig = plt.figure()
            fig.canvas.set_window_title(self.plot_title)
            plt.title(self.plot_title)

            # left_y_plot = fig.add_subplot()
            left_y_plot = fig.gca().axes

            # colors = get_cmap('Dark2').colors
            # color_cycler = cycler.cycler('color', colors)
            # plt.rc('axes', prop_cycle=color_cycler)

            lines_plotted = []
            line_legends = []
            if df.hour_only:
                plt.xlabel("Elapsed time (hours)")
            else:
                plt.xlabel("Elapsed time (date)")
                fig.autofmt_xdate()
            plt.grid(True)
            new_line = left_y_plot.plot(x, y, label="xxx")[0]
            if not df.hour_only:
                left_y_plot.xaxis.set_major_formatter(
                    mdates.DateFormatter('%Y-%m-%d %H:%M'))
            lines_plotted.append(new_line)
            plt.legend(lines_plotted, line_legends, loc="best")
            plt.show(block=False)
Esempio n. 5
0
class frmMainEPANET(frmMain):
    """Main form for EPANET user interface, based on frmMain which is shared with SWMM."""

    # Variables used to populate the tree control
    # Each item is a list: label plus either editing form for this section or a child list.
    # Special cases may just have a label and no editing form or children.
    # *_items are a lists of items in a section
    tree_options_Hydraulics = ["Hydraulics", frmHydraulicsOptions]
    tree_options_Quality = ["Quality", frmQualityOptions]
    tree_options_Reactions = ["Reactions", frmReactionsOptions]
    tree_options_Times = ["Times", frmTimesOptions]
    tree_options_Energy = ["Energy", frmEnergyOptions]
    tree_options_Report = ["Report", frmReportOptions]
    tree_options_MapBackdrop = ["Map/Backdrop", frmMapBackdropOptions]
    tree_options_items = [tree_options_Hydraulics,
                          tree_options_Quality,
                          tree_options_Reactions,
                          tree_options_Times,
                          tree_options_Energy,
                          tree_options_Report,
                          tree_options_MapBackdrop]

    tree_controls_Simple = ["Simple", frmControls, ["EPANET Simple Controls", "CONTROLS"]]
    tree_controls_RuleBased = ["Rule-Based", frmControls, ["EPANET Rule-Based Controls", "RULES"]]
    tree_controls_items = [tree_controls_Simple,
                           tree_controls_RuleBased]

    tree_TitleNotes = ["Title/Notes", frmTitle]
    tree_Options = ["Options", tree_options_items]
    tree_Junctions = ["Junctions", None]
    tree_Reservoirs = ["Reservoirs", None]
    tree_Tanks = ["Tanks", None]
    tree_Pipes = ["Pipes", None]
    tree_Pumps = ["Pumps", None]
    tree_Valves = ["Valves", None]
    tree_Labels = ["Labels", None]
    tree_Patterns = ["Patterns", frmPatternEditor]
    tree_Curves = ["Curves", frmCurveEditor]
    tree_Controls = ["Controls", tree_controls_items]
    tree_top_items = [tree_TitleNotes,
                      tree_Options,
                      tree_Junctions,
                      tree_Reservoirs,
                      tree_Tanks,
                      tree_Pipes,
                      tree_Pumps,
                      tree_Valves,
                      tree_Labels,
                      tree_Patterns,
                      tree_Curves,
                      tree_Controls]

    def __init__(self, q_application):
        frmMain.__init__(self, q_application)
        self.model = "EPANET"
        self.model_path = ''  # Set this only if needed later when running model
        self.output = None    # Set this when model output is available
        self.status_suffix = "_status.txt"
        self.status_file_name = ''  # Set this when model status is available
        self.output_filename = ''   # Set this when model output is available
        self.project_type = Project  # Use the model-specific Project as defined in core.epanet.project
        self.project = Project()
        self.assembly_path = os.path.dirname(os.path.abspath(__file__))
        self.on_load(tree_top_item_list=self.tree_top_items)

        HelpHandler.init_class(os.path.join(self.assembly_path, "epanet.qhc"))
        self.help_topic = ""  # TODO: specify topic to open when Help key is pressed on main form
        self.helper = HelpHandler(self)

        self.actionStatus_ReportMenu = QtGui.QAction(self)
        self.actionStatus_ReportMenu.setObjectName(from_utf8("actionStatus_ReportMenu"))
        self.actionStatus_ReportMenu.setText(transl8("frmMain", "Status", None))
        self.actionStatus_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Status", None))
        self.menuReport.addAction(self.actionStatus_ReportMenu)
        QtCore.QObject.connect(self.actionStatus_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_status)

        self.actionEnergy_ReportMenu = QtGui.QAction(self)
        self.actionEnergy_ReportMenu.setObjectName(from_utf8("actionEnergy_ReportMenu"))
        self.actionEnergy_ReportMenu.setText(transl8("frmMain", "Energy", None))
        self.actionEnergy_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Energy", None))
        self.menuReport.addAction(self.actionEnergy_ReportMenu)
        QtCore.QObject.connect(self.actionEnergy_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_energy)

        self.actionCalibration_ReportMenu = QtGui.QAction(self)
        self.actionCalibration_ReportMenu.setObjectName(from_utf8("actionCalibration_ReportMenu"))
        self.actionCalibration_ReportMenu.setText(transl8("frmMain", "Calibration", None))
        self.actionCalibration_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Calibration", None))
        self.menuReport.addAction(self.actionCalibration_ReportMenu)
        QtCore.QObject.connect(self.actionCalibration_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_calibration)

        self.actionReaction_ReportMenu = QtGui.QAction(self)
        self.actionReaction_ReportMenu.setObjectName(from_utf8("actionReaction_ReportMenu"))
        self.actionReaction_ReportMenu.setText(transl8("frmMain", "Reaction", None))
        self.actionReaction_ReportMenu.setToolTip(transl8("frmMain", "Display Simulation Reaction", None))
        self.menuReport.addAction(self.actionReaction_ReportMenu)
        QtCore.QObject.connect(self.actionReaction_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_reaction)

        self.actionFull_ReportMenu = QtGui.QAction(self)
        self.actionFull_ReportMenu.setObjectName(from_utf8("actionFull_ReportMenu"))
        self.actionFull_ReportMenu.setText(transl8("frmMain", "Full...", None))
        self.actionFull_ReportMenu.setToolTip(transl8("frmMain", "Save full report as text file", None))
        self.menuReport.addAction(self.actionFull_ReportMenu)
        QtCore.QObject.connect(self.actionFull_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_full)

        self.actionGraph_ReportMenu = QtGui.QAction(self)
        self.actionGraph_ReportMenu.setObjectName(from_utf8("actionGraph_ReportMenu"))
        self.actionGraph_ReportMenu.setText(transl8("frmMain", "Graph...", None))
        self.actionGraph_ReportMenu.setToolTip(transl8("frmMain", "Display graph selection options", None))
        self.menuReport.addAction(self.actionGraph_ReportMenu)
        QtCore.QObject.connect(self.actionGraph_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_graph)

        self.actionTable_ReportMenu = QtGui.QAction(self)
        self.actionTable_ReportMenu.setObjectName(from_utf8("actionTable_ReportMenu"))
        self.actionTable_ReportMenu.setText(transl8("frmMain", "Table...", None))
        self.actionTable_ReportMenu.setToolTip(transl8("frmMain", "Display table selection options", None))
        self.menuReport.addAction(self.actionTable_ReportMenu)
        QtCore.QObject.connect(self.actionTable_ReportMenu, QtCore.SIGNAL('triggered()'), self.report_table)

        self.Help_Topics_Menu = QtGui.QAction(self)
        self.Help_Topics_Menu.setObjectName(from_utf8("Help_Topics_Menu"))
        self.Help_Topics_Menu.setText(transl8("frmMain", "Help Topics", None))
        self.Help_Topics_Menu.setToolTip(transl8("frmMain", "Display Help Topics", None))
        self.menuHelp.addAction(self.Help_Topics_Menu)
        QtCore.QObject.connect(self.Help_Topics_Menu, QtCore.SIGNAL('triggered()'), self.help_topics)

        self.Help_About_Menu = QtGui.QAction(self)
        self.Help_About_Menu.setObjectName(from_utf8("Help_About_Menu"))
        self.Help_About_Menu.setText(transl8("frmMain", "About", None))
        self.Help_About_Menu.setToolTip(transl8("frmMain", "About EPANET", None))
        self.menuHelp.addAction(self.Help_About_Menu)
        QtCore.QObject.connect(self.Help_About_Menu, QtCore.SIGNAL('triggered()'), self.help_about)

    def report_status(self):
        print "report_status"
        if not os.path.isfile(self.status_file_name):
            prefix, extension = os.path.splitext(self.project.file_name)
            if os.path.isfile(prefix + self.status_suffix):
                self.status_file_name = prefix + self.status_suffix
        if os.path.isfile(self.status_file_name):
            webbrowser.open_new_tab(self.status_file_name)
        else:
            QMessageBox.information(None, self.model,
                                    "Model status not found.\n"
                                    "Run the model to generate model status.",
                                    QMessageBox.Ok)

    def report_energy(self):
        self._frmEnergyReport = frmEnergyReport(self)
        self._frmEnergyReport.set_data()
        self._frmEnergyReport.show()
        pass

    def report_calibration(self):
        if self.output:
            self._frmCalibrationReportOptions = frmCalibrationReportOptions(self, self.project)
            self._frmCalibrationReportOptions.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_reaction(self):
        self.reaction_report()
        pass

    def report_full(self):
        if self.output:
            directory = os.path.dirname(self.project.file_name)
            report_file_name = QtGui.QFileDialog.getSaveFileName(self, "Save Full Report As...", directory, "Text files (*.txt)")
            if report_file_name:
                try:
                    reporter = reports.Reports(self.project, self.output)
                    reporter.write_report(report_file_name)
                    webbrowser.open_new_tab(report_file_name)
                except Exception as e1:
                    msg = str(e1) + '\n' + str(traceback.print_exc())
                    print(msg)
                    QMessageBox.information(None, self.model,
                                            "Error writing report to \n" + report_file_name + '\n' + msg,
                                            QMessageBox.Ok)

        else:
            QMessageBox.information(None, self.model,
                                    "There is no model output currently open.\n"
                                    "Model output is automatically opened after model is run.",
                                    QMessageBox.Ok)

    def report_graph(self):
        if self.output:
            self._frmGraph = frmGraph(self)
            self._frmGraph.set_from(self.project, self.output)
            self._frmGraph.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def report_table(self):
        if self.output:
            self._frmTable = frmTable(self)
            self._frmTable.set_from(self.project, self.output)
            self._frmTable.show()
        else:
            QMessageBox.information(None, self.model,
                                    "Model output not found.\n"
                                    "Run the model to generate output.",
                                    QMessageBox.Ok)

    def reaction_report(self):

        # TXT_NO_REACTION = 'No reactions occurred'
        # TXT_AVG_RATES = 'Average Reaction Rates (kg/day)'
        # ' Reaction Report'

        # Find conversion factor to kilograms/day
        ucf = 1.0e6/24
        quality_options = self.project.options.quality
        if 'ug' in str(quality_options.mass_units):
            ucf = 1.0e9/24

        #
        # // Get average reaction rates from output file
        # Uoutput.GetReactRates(r);

#         procedure GetReactRates(var R: array of Single);
# //-----------------------------------------------
# // Retrieves overall average reaction rates
# // NOTE: The 3 avg. reaction rates + avg. source
# //       input rate are stored at end of the
# //       binary output file just before the last
# //       3 records.
# //-----------------------------------------------
# begin
#   Seek(Fout, FileSize(Fout)-7*RECORDSIZE);
#   BlockRead(Fout, R, 4*Sizeof(Single));
# end;

        # for i := 0 to 3 do rate[i] := r[i] / ucf;
        #
        # // Check max. rate to see if any reactions occurred
        # maxrate := MaxValue(Slice(rate,3));
        # if maxrate = 0 then
        # begin
        #   Chart1.Foot.Text.Add(TXT_NO_REACTION);
        # end
        #
        # // Add each rate category to chart
        # else
        # begin
        # Chart1.Title.Text.Add(TXT_AVG_RATES);
        # Add(rate[0],TXT_BULK,clBlue);
        # Add(rate[1],TXT_WALL,clRed);
        # Add(rate[2],TXT_TANKS,clGreen);
        #  Active := True;
        # Chart1.Foot.Text.Add(Format(FMT_INFLOW,[rate[3]]));
        # end;
        # end;

        import matplotlib.pyplot as plt

        # The slices will be ordered and plotted counter-clockwise.
        labels = '2.8 Tanks', '0.5 Bulk', '2.1 Wall'
        sizes = [52.49, 8.57, 38.93]
        colors = ['green', 'blue', 'red']
        explode = (0, 0, 0)

        plt.figure("Reaction Report")
        plt.pie(sizes, explode=explode, labels=labels, colors=colors,
                autopct='%1.2f%%', shadow=True, startangle=180)
        # Set aspect ratio to be equal so that pie is drawn as a circle.
        plt.axis('equal')
        plt.suptitle("Average Reaction Rates (kg/day)", fontsize=16)
        plt.text(0.9,-0.9,"Inflow Rate = 6")

        plt.show()

    def calibration_data(self):
        self._frmCalibrationData = frmCalibrationData(self)
        self._frmCalibrationData.show()
        pass

    def get_editor(self, edit_name):
        frm = None
        # First handle special cases where forms need more than simply being created

        # the following items will respond to a click on a node form, not the tree diagram
        if edit_name == 'Reservoirs' or edit_name == 'Tanks':
            # assume we're editing the first node for now
            frm = frmSourcesQuality(self)
            frm.setWindowTitle('EPANET Source Editor for Node ' + '1')
            frm.set_from(self.project, '1')
        elif edit_name == 'Junctions':
            # assume we're editing the first junction for now
            frm = frmDemands(self)
            frm.setWindowTitle('EPANET Demands for Junction ' + '1')
            frm.set_from(self.project, '1')
        elif edit_name == 'Patterns':
            return None
        elif edit_name == 'Curves':
            return None
        else:  # General-purpose case finds most editors from tree information
            frm = self.make_editor_from_tree(edit_name, self.tree_top_items)
        return frm

    def get_editor_with_selected_item(self, edit_name, selected_item):
        frm = None

        # the following items will respond to a click on a node form, not the tree diagram
        if edit_name == 'Reservoirs' or edit_name == 'Tanks':
            # assume we're editing the first node for now
            frm = frmSourcesQuality(self)
            frm.setWindowTitle('EPANET Source Editor for Node ' + '1')
            frm.set_from(self.project, '1')
        elif edit_name == 'Junctions':
            # assume we're editing the first junction for now
            frm = frmDemands(self)
            frm.setWindowTitle('EPANET Demands for Junction ' + '1')
            frm.set_from(self.project, '1')
        else:  # General-purpose case finds most editors from tree information
            frm = self.make_editor_from_tree(edit_name, self.tree_top_items)
            frm.set_from(self.project, selected_item)
        return frm

    def get_object_list(self, category):
        ids = []
        if category.lower() == 'junctions':
            for i in range(0, len(self.project.junctions.value)):
                ids.append(self.project.junctions.value[i].id)
        elif category.lower() == 'reservoirs':
            for i in range(0, len(self.project.reservoirs.value)):
                ids.append(self.project.reservoirs.value[i].id)
        elif category.lower() == 'tanks':
            for i in range(0, len(self.project.tanks.value)):
                ids.append(self.project.tanks.value[i].id)
        elif category.lower() == 'pipes':
            for i in range(0, len(self.project.pipes.value)):
                ids.append(self.project.pipes.value[i].id)
        elif category.lower() == 'pumps':
            for i in range(0, len(self.project.pumps.value)):
                ids.append(self.project.pumps.value[i].id)
        elif category.lower() == 'valves':
            for i in range(0, len(self.project.valves.value)):
                ids.append(self.project.valves.value[i].id)
        elif category.lower() == 'labels':
            for i in range(0, len(self.project.labels.value)):
                ids.append(self.project.labels.value[i].label)
        elif category.lower() == 'patterns':
            for i in range(0, len(self.project.patterns.value)):
                ids.append(self.project.patterns.value[i].pattern_id)
        elif category.lower() == 'curves':
            for i in range(0, len(self.project.curves.value)):
                ids.append(self.project.curves.value[i].curve_id)
        else:
            ids = None
        return ids

    def add_object_clicked(self, section_name):
        if section_name == "Patterns":
            new_item = Pattern()
            new_item.pattern_id = "NewPattern"
            self.project.patterns.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.pattern_id))
        elif section_name == "Curves":
            new_item = Curve()
            new_item.curve_id = "NewCurve"
            self.project.curves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.curve_id))
        elif section_name == "Junctions":
            new_item = Junction()
            new_item.id = "New"
            self.project.junctions.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))
        elif section_name == 'Reservoirs':
            new_item = Reservoir()
            new_item.id = "New"
            self.project.reservoirs.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))
        elif section_name == 'Tanks':
            new_item = Tank()
            new_item.id = "New"
            self.project.tanks.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))
        elif section_name == 'Pipes':
            new_item = Pipe()
            new_item.id = "New"
            self.project.pipes.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))
        elif section_name == 'Pumps':
            new_item = Pump()
            new_item.id = "New"
            self.project.pumps.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))
        elif section_name == 'Valves':
            new_item = Valve()
            new_item.id = "New"
            self.project.valves.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))
        elif section_name == 'Labels':
            new_item = Label()
            new_item.id = "New"
            self.project.labels.value.append(new_item)
            self.show_edit_window(self.get_editor_with_selected_item(self.tree_section, new_item.id))

    def delete_object_clicked(self, section_name, item_name):
        if section_name == "Patterns":
            for value in self.project.patterns.value:
                if value.pattern_id == item_name:
                    self.project.patterns.value.remove(value)
        elif section_name == "Curves":
            for value in self.project.curves.value:
                if value.curve_id == item_name:
                    self.project.curves.value.remove(value)
        elif section_name == "Junctions":
            for value in self.project.junctions.value:
                if value.id == item_name:
                    self.project.junctions.value.remove(value)
        elif section_name == 'Reservoirs':
            for value in self.project.reservoirs.value:
                if value.id == item_name:
                    self.project.reservoirs.value.remove(value)
        elif section_name == 'Tanks':
            for value in self.project.tanks.value:
                if value.id == item_name:
                    self.project.tanks.value.remove(value)
        elif section_name == 'Pipes':
            for value in self.project.pipes.value:
                if value.id == item_name:
                    self.project.pipes.value.remove(value)
        elif section_name == 'Pumps':
            for value in self.project.pumps.value:
                if value.id == item_name:
                    self.project.pumps.value.remove(value)
        elif section_name == 'Valves':
            for value in self.project.valves.value:
                if value.id == item_name:
                    self.project.valves.value.remove(value)
        elif section_name == 'Labels':
            for value in self.project.labels.value:
                if value.id == item_name:
                    self.project.labels.value.remove(value)

    def run_simulation(self):
        # Find input file to run
        file_name = ''
        use_existing = self.project and self.project.file_name and os.path.exists(self.project.file_name)
        if use_existing:
            file_name = self.project.file_name
            # TODO: save if needed, decide whether to save to temp location as previous version did.
        else:
            directory = QtCore.QSettings(self.model, "GUI").value("ProjectDir", "")
            file_name = QFileDialog.getOpenFileName(self, "Open Project...", directory,
                                                          "Inp files (*.inp);;All files (*.*)")

        if os.path.exists(file_name):
            if not os.path.exists(self.model_path):
                if 'darwin' in sys.platform:
                    lib_name = 'libepanet.dylib.dylib'
                elif 'win' in sys.platform:
                    lib_name = 'epanet2_amd64.dll'
                else:  # Linux
                    lib_name = 'libepanet2_amd64.so'
                self.model_path = self.find_external(lib_name)
            if os.path.exists(self.model_path):
                try:
                    prefix, extension = os.path.splitext(file_name)
                    self.status_file_name = prefix + self.status_suffix
                    self.output_filename = prefix + '.out'
                    model_api = ENepanet(file_name, self.status_file_name, self.output_filename, self.model_path)
                    frmRun = frmRunEPANET(model_api, self.project, self)
                    self._forms.append(frmRun)
                    if not use_existing:
                        # Read this project so we can refer to it while running
                        frmRun.progressBar.setVisible(False)
                        frmRun.lblTime.setVisible(False)
                        frmRun.fraTime.setVisible(False)
                        frmRun.fraBottom.setVisible(False)
                        frmRun.showNormal()
                        frmRun.set_status_text("Reading " + file_name)

                        self.project = Project()
                        self.project.read_file(file_name)
                        frmRun.project = self.project

                    frmRun.Execute()
                    self.report_status()
                    self.output = ENOutputWrapper.OutputObject(self.output_filename)
                    return
                except Exception as e1:
                    print(str(e1) + '\n' + str(traceback.print_exc()))
                    QMessageBox.information(None, self.model,
                                            "Error running model with library:\n {0}\n{1}\n{2}".format(
                                                self.model_path, str(e1), str(traceback.print_exc())),
                                            QMessageBox.Ok)
                finally:
                    try:
                        if model_api and model_api.isOpen():
                            model_api.ENclose()
                    except:
                        pass
                    return

            # # Could not run with library, try running with executable
            # # Run executable with StatusMonitor0
            # args = []
            # self.modelenv1 = 'EXE_EPANET'
            # program = os.environ[self.modelenv1]
            #
            # exe_name = "epanet2d.exe"
            # exe_path = os.path.join(self.assembly_path, exe_name)
            # if not os.path.exists(exe_path):
            #     pp = os.path.dirname(os.path.dirname(self.assembly_path))
            #     exe_path = os.path.join(pp, "Externals", exe_name)
            # if not os.path.exists(exe_path):
            #     exe_path = QFileDialog.getOpenFileName(self, 'Locate EPANET Executable', '/',
            #                                              'exe files (*.exe)')
            # if os.path.exists(exe_path):
            #     os.environ[self.modelenv1] = exe_path
            # else:
            #     os.environ[self.modelenv1] = ''
            #
            # if not os.path.exists(program):
            #     QMessageBox.information(None, "EPANET", "EPANET Executable not found", QMessageBox.Ok)
            #     return -1
            #
            # args.append(file_name)
            # args.append(prefix + '.txt')
            # args.append(prefix + '.out')
            # status = model_utility.StatusMonitor0(program, args, self, model='EPANET')
            # status.show()
        else:
            QMessageBox.information(None, self.model, self.model + " input file not found", QMessageBox.Ok)

    def find_external(self, lib_name):
        filename = os.path.join(self.assembly_path, lib_name)
        if not os.path.exists(filename):
            pp = os.path.dirname(os.path.dirname(self.assembly_path))
            filename = os.path.join(pp, "Externals", lib_name)
        if not os.path.exists(filename):
            pp = os.path.dirname(os.path.dirname(self.assembly_path))
            filename = os.path.join(pp, "Externals", "epanet", "model", lib_name)
        if not os.path.exists(filename):
            filename = QFileDialog.getOpenFileName(self,
                                                          'Locate ' + self.model + ' Library',
                                                          '/', '(*{0})'.format(os.path.splitext(lib_name)[1]))
        return filename

    def help_topics(self):
        self.helper.show_help()

    def help_about(self):
        self._frmAbout = frmAbout(self)
        self._frmAbout.show()
        pass
class frmPlotViewer(QMainWindow, Ui_frmPlot):
    """
    Generic plot viewer window that can copy, save, and print a plot
    - Time Series Viewer
    """

    # MAGIC = "TSGRAPHSPEC:"

    def __init__(self, dataset, plot_type, plot_title, window_icon, x_title,
                 y_title):
        """
        Constructor
        Args:
            dataset: time series data as pandas data frame
        """
        QMainWindow.__init__(self)
        self.helper = HelpHandler(self)
        self.setupUi(self)
        self.setWindowIcon(window_icon)

        self.actionPrint.setVisible(False)
        self.actionSave.setVisible(False)
        self.actionCopy.setVisible(False)
        self.menuFile.setEnabled(False)
        self.menuFile.setVisible(False)
        self.menuFile.deleteLater()

        self.dataset = dataset
        self.plot_title = plot_title
        self.x_title = x_title
        self.y_title = y_title
        if plot_type == 'time':
            self.plot_type = 'timeseries'
            self.help_topic = "swmm/src/src/timeserieseditordialog.htm"
        elif plot_type == 'xy':
            self.plot_type = 'xy'
            self.help_topic = "swmm/src/src/transecteditordialog.htm"
        self.plot = CurvePlot(self.fraPlot, width=6, height=2, dpi=100)
        layout = QVBoxLayout(self.fraPlot)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.plot)
        self.fraPlot.setLayout(layout)
        self.helper = HelpHandler(self)

        self.Xunits = {}
        self.Yunits = {}
        self.Xlabel = ""
        self.Ylabel = ""
        self.Xunit = ""
        self.Yunit = ""
        self.TXT_OPEN_CURVE_TITLE = 'Open a Curve'
        self.TXT_SAVE_CURVE_TITLE = 'Save Curve As'
        self.TXT_CURVE_FILTER = 'Curve files (*.CRV)|*.CRV|All files|*.*'
        self.xvals = []
        self.yvals = []
        self.btnClose.clicked.connect(self.frm_close)
        self.btnHelp.clicked.connect(self.get_help)
        self.actionOpen.triggered.connect(self.open_datafile)
        self.actionCopy.triggered.connect(self.copy_plot)
        self.actionSave.triggered.connect(self.save_plot)
        self.actionPrint.triggered.connect(self.print_plot)
        # self.installEventFilter(self)
        self.do_plot()

    def open_datafile(self):
        pass

    def copy_plot(self):
        pass

    def save_plot(self):
        pass

    def print_plot(self):
        pass

    def do_plot(self):
        """
        Construct a plot of the dataset
        ToDo: based on user-specified plot type
        Returns:

        """
        if self.dataset.shape[0] > 0 and self.dataset.shape[1] > 0:
            self.plot.setTitle(self.plot_title)
            if self.plot_type == 'timeseries':
                self.plot.set_time_series_data(self.dataset)
            elif self.plot_type == 'xy':
                self.plot.set_xy_data(self.dataset, self.x_title, self.y_title)

        pass

    def frm_close(self):
        """
        Close the plot form and discard dataset
        Returns:

        """
        self.close()

    def get_help(self):
        self.helper.show_help()
Esempio n. 7
0
class frmDefaultsEditor(QMainWindow, Ui_frmGenericDefaultsEditor):
    """
    Project defaults editor for setting and editing
    object id prefix (tab1)
    properties (tab2)
    hydraulic defaults (tab3)
    """
    def __init__(self, session, project, defaults):
        QMainWindow.__init__(self, session)
        self.setupUi(self)
        self.helper = HelpHandler(self)
        self.help_topic = "swmm/src/src/projectdefaultsdialog.htm"
        self.defaults = defaults
        self.session = session
        self.project = project
        self.label_changed = False
        self.property_sub_changed = False
        self.parameter_changed = False
        self.loaded = False
        self.refresh_column = None
        if self.session is not None:
            self.setWindowTitle(self.session.model + " Project Defaults")
        self.cmdOK.clicked.connect(self.cmdOK_Clicked)
        self.cmdCancel.clicked.connect(self.cmdCancel_Clicked)
        #disable Help button on form since no other forms have one
        self.cmdHelp.setVisible(False)
        #self.cmdHelp.clicked.connect(self.cmdHelp_Clicked)
        # self.tabDefaults.currentChanged(int).connect(self.tab_changed)
        # self.tblGeneric.cellChanged(int, int).connect(self.tblGeneric_changed)
        self.tabDefaults.currentChanged.connect(self.tab_changed)
        self.tblGeneric.cellChanged.connect(self.tblGeneric_changed)
        self.chk4all.setVisible(False)

        self.corner_label_tab1 = QLabel("Object", self.tblGeneric)
        self.corner_label_tab1.setAlignment(QtCore.Qt.AlignCenter)
        self.corner_label_tab1.setAttribute(
            QtCore.Qt.WA_TransparentForMouseEvents)
        self.tblGeneric.verticalHeader().geometriesChanged.connect(
            self.resizeCorner)
        self.tblGeneric.horizontalHeader().geometriesChanged.connect(
            self.resizeCorner)

        self.gridLayout_tab2 = QGridLayout(self.tabDefaults.widget(1))
        self.gridLayout_tab2.setObjectName(_fromUtf8("gridLayout_tab2"))
        self.tbl_2 = QTableWidget(self.tabDefaults.widget(1))
        self.tbl_2.setObjectName(_fromUtf8("tbl_2"))
        self.tbl_2.setColumnCount(1)
        self.tbl_2.setRowCount(1)
        self.tbl_2.horizontalHeader().setStretchLastSection(True)
        self.gridLayout_tab2.addWidget(self.tbl_2, 0, 0, 0, 0)
        # self.tbl_2.cellChanged(int, int).connect(self.tbl_2_changed)
        self.tbl_2.cellChanged.connect(self.tbl_2_changed)

        self.corner_label_tab2 = QLabel("Property", self.tbl_2)
        self.corner_label_tab2.setAlignment(QtCore.Qt.AlignCenter)
        self.corner_label_tab2.setAttribute(
            QtCore.Qt.WA_TransparentForMouseEvents)
        self.tblGeneric.verticalHeader().geometriesChanged.connect(
            self.resizeCorner)
        self.tblGeneric.horizontalHeader().geometriesChanged.connect(
            self.resizeCorner)

        self.gridLayout_tab3 = QGridLayout(self.tabDefaults.widget(2))
        self.gridLayout_tab3.setObjectName(_fromUtf8("gridLayout_tab3"))
        self.tbl_3 = QTableWidget(self.tabDefaults.widget(2))
        self.tbl_3.setObjectName(_fromUtf8("tbl_3"))
        self.tbl_3.setColumnCount(1)
        self.tbl_3.setRowCount(1)
        self.tbl_3.horizontalHeader().setStretchLastSection(True)
        self.gridLayout_tab3.addWidget(self.tbl_3, 0, 0, 0, 0)
        self.tbl_3.cellChanged.connect(self.tbl_3_changed)

        self.corner_label_tab3 = QLabel("Option", self.tbl_3)
        self.corner_label_tab3.setAlignment(QtCore.Qt.AlignCenter)
        self.corner_label_tab3.setAttribute(
            QtCore.Qt.WA_TransparentForMouseEvents)
        self.tbl_3.verticalHeader().geometriesChanged.connect(
            self.resizeCorner)
        self.tbl_3.horizontalHeader().geometriesChanged.connect(
            self.resizeCorner)

        self.sm_hydraulics = QtCore.QSignalMapper(self)
        self.sm_hydraulics.mapped.connect(self.tbl_3_combo_indexChanged)

        self.populate_defaults()
        self.installEventFilter(self)
        self.loaded = True

    def resizeCorner(self):
        tab_ind = self.tabDefaults.currentIndex()
        if tab_ind == 0:
            self.corner_label_tab1.setGeometry(
                0, 0,
                self.tblGeneric.verticalHeader().width(),
                self.tblGeneric.horizontalHeader().height())
        elif tab_ind == 1:
            self.corner_label_tab2.setGeometry(
                0, 0,
                self.tbl_2.verticalHeader().width(),
                self.tbl_2.horizontalHeader().height())
        elif tab_ind == 2:
            self.corner_label_tab3.setGeometry(
                0, 0,
                self.tbl_3.verticalHeader().width(),
                self.tbl_3.horizontalHeader().height())

    def populate_defaults(self):
        """
        set up the defaults from ini settings
        Returns:
        """
        self.set_tabs(3)
        self.tabDefaults.setTabText(0, "ID Labels")
        self.tabDefaults.setTabText(1, "Subcatchments")
        self.tabDefaults.setTabText(2, "Nodes/Links")

        self.set_tab_prefix()
        self.set_sub_properties()
        self.set_tab_hydraulics()
        #self.tab_changed(0)

    def set_tabs(self, num_tab):
        """
        ensure desired number of tabs are created
        Args:
            num_tab: the desired number of tabs
        Returns:
        """
        while self.tabDefaults.count() < num_tab:
            c = self.tabDefaults.count()
            new_tab = QWidget(self.tabDefaults)
            self.tabDefaults.addTab(new_tab, "tab_" + str(c + 1))
        while self.tabDefaults.count() > num_tab:
            c = self.tabDefaults.count()
            w = self.tabDefaults.widget(c - 1)
            self.tabDefaults.removeTab(c - 1)
            if w:
                del w

    def set_tab_prefix(self):
        """
        setup the object id tab entries
        Returns:
        """
        #self.model_object_keys = ["Rain Gage", "Subcatchment", "Junction", "Outfall", "Divider",
        #                           "Storage Unit", "Conduit", "Pump", "Regulator"]
        self.tblGeneric.setColumnCount(1)
        self.tblGeneric.setRowCount(len(self.defaults.model_object_keys))
        self.tblGeneric.setHorizontalHeaderLabels(["ID Prefix"])
        self.tblGeneric.setVerticalHeaderLabels(
            self.defaults.model_object_keys)
        for i in range(0, len(self.defaults.model_object_keys)):
            prefix = ""
            if self.defaults:
                #prefix = unicode(self.qsettings.value("Labels/" + self.model_object_keys[i], ""))
                prefix = self.defaults.model_object_prefix[
                    self.defaults.model_object_keys[i]]
            #self.tblGeneric.insertRow(self.tblGeneric.rowCount())
            self.tblGeneric.setItem(i, 0, QTableWidgetItem(prefix))
        self.tblGeneric.insertRow(self.tblGeneric.rowCount())
        self.tblGeneric.setVerticalHeaderItem(
            self.tblGeneric.rowCount() - 1,
            QTableWidgetItem(self.defaults.id_increment_key))
        if self.defaults:
            #self.increment = int(self.qsettings.value("Labels/Increment", 1))
            self.increment = self.defaults.id_increment
        self.tblGeneric.setItem(
            self.tblGeneric.rowCount() - 1, 0,
            QTableWidgetItem(str(self.defaults.id_increment)))
        pass

    def set_sub_properties(self):
        """
        setup object property defaults tab entries
        Returns:
        """
        properties = [
            "Area", "Width", "% Slope", "% Imperv", "N-Imperv", "N-Perv",
            "Dstore-Imperv", "Dstore-Perv", "%Zero-Imperv",
            "Infiltration Model"
        ]
        #self.properties_def_values = [5, 500, 0.5, 25, 0.01, 0.1, 0.05, 0.05, 25, "HORTON"]
        self.tbl_2.setColumnCount(1)
        self.tbl_2.setRowCount(len(self.defaults.properties_sub_keys))
        self.tbl_2.setHorizontalHeaderLabels(["Default Value"])
        self.tbl_2.setVerticalHeaderLabels(properties)
        for i in range(0, len(self.defaults.properties_sub_keys) - 1):
            #def_val = unicode(self.qsettings.value("Defaults/" + self.properties[i], def_val))
            def_val = self.defaults.properties_sub_values[
                self.defaults.properties_sub_keys[i]]
            self.tbl_2.setItem(i, 0, QTableWidgetItem(str(def_val)))
        self.set_infilmodel_cell(0)

        pass

    def set_tab_hydraulics(self):
        """
        setup the hydraulic parameter defaults tab entries
        Returns:
        """
        properties = [
            "Node Invert", "Node Max. Depth", "Node Ponded Area",
            "Conduit Length", "Conduit Geometry", "Conduit Roughness",
            "Flow Units", "Link Offsets", "Routing Method",
            "Force Main Equation"
        ]
        #self.parameters_def_values = [0, 0, 0, 400, "CIRCULAR", 0.01, "CFS", "DEPTH", "KINWAVE", "H_W"]
        self.tbl_3.setColumnCount(1)
        self.tbl_3.setRowCount(len(self.defaults.parameters_keys))
        self.tbl_3.setHorizontalHeaderLabels(["Default Value"])
        self.tbl_3.setVerticalHeaderLabels(properties)
        for i in range(0, len(self.defaults.parameters_keys)):
            combobox = None
            key = self.defaults.parameters_keys[i]
            def_val = self.defaults.parameters_values[key]
            if "flow_units" in key.lower():
                combobox = QComboBox()
                enum_val = FlowUnits[def_val]
            elif "link_offsets" in key.lower():
                combobox = QComboBox()
                enum_val = LinkOffsets[def_val]
            elif "routing_model" in key.lower():
                combobox = QComboBox()
                enum_val = FlowRouting[def_val.upper()]
            elif "force_main" in key.lower():
                combobox = QComboBox()
                if def_val.upper() == "H-W":
                    enum_val = ForceMainEquation['H_W']
                if def_val.upper() == "D-W":
                    enum_val = ForceMainEquation['D_W']

            if combobox is not None:
                combobox.setObjectName(key + "|" + str(i) + "|0")
                set_combo_items(type(enum_val), combobox)
                set_combo(combobox, enum_val)
                combobox.currentIndexChanged.connect(self.sm_hydraulics.map)
                self.sm_hydraulics.setMapping(combobox, i)
                self.tbl_3.setCellWidget(i, 0, combobox)
            else:
                if "conduit_shape" in key.lower():
                    self.set_channel_cell(0)
                else:
                    self.tbl_3.setItem(i, 0, QTableWidgetItem(str(def_val)))
        pass

    def eventFilter(self, ui_object, event):
        if event.type() == QtCore.QEvent.WindowUnblocked:
            if self.refresh_column and self.refresh_column > -1:
                self.set_infilmodel_cell(self.refresh_column)
                self.set_channel_cell(self.refresh_column)
                self.refresh_column = -1
        return False

    def set_infilmodel_cell(self, column):
        # text plus button for demand categories editor
        tb = TextPlusButton(self)
        self.infil_model = E_InfilModel.HORTON.name
        if self.defaults:
            self.infil_model = self.defaults.properties_sub_values[
                self.defaults.infil_model_key]
            # if self.qsettings.contains(self.default_key_infilmodel):
            #     model_obj = self.qsettings.value(self.default_key_infilmodel)
            #     # model_name = type(model_obj)
            #     if model_obj is not None:
            #         self.infil_model = unicode(model_obj.model_type().name)
            # else:
            #     self.infil_model = unicode(self.qsettings.value("Defaults/" + self.properties[len(self.properties) - 1],
            #                                                self.infil_model))
        tb.textbox.setText(self.infil_model)
        tb.textbox.setEnabled(False)
        tb.column = column
        tb.button.clicked.connect(self.make_show_infilmodel(column))
        self.tbl_2.setCellWidget(self.tbl_2.rowCount() - 1, 0, tb)

    def make_show_infilmodel(self, column):
        def local_show():
            frm = frmInfiltration(self, [],
                                  None,
                                  "Default Infiltration Model",
                                  defaults=self.defaults)
            #frm.set_from(self.project, "")
            frm.setWindowModality(QtCore.Qt.ApplicationModal)
            frm.show()
            self.refresh_column = column
            self.property_sub_changed = True
            self.set_infilmodel_cell(0)

        return local_show

    def set_channel_cell(self, column):
        # text plus button for demand categories editor
        # xsection = CrossSection()
        tb = TextPlusButton(self)
        if self.defaults is not None and self.defaults.xsection is not None:
            self.channel_geom = self.defaults.xsection.shape.name
        tb.textbox.setText(self.channel_geom)
        tb.textbox.setEnabled(False)
        tb.column = column
        tb.button.clicked.connect(self.make_show_channel(
            column, self.defaults))
        self.tbl_3.setCellWidget(4, 0, tb)

    def make_show_channel(self, column, defaults):
        def local_show():
            frm = frmCrossSection(self.session, defaults=defaults)
            frm.setWindowTitle("Define Default Conduit Geometry")
            #frm.set_from(self.project, "")
            frm.setWindowModality(QtCore.Qt.ApplicationModal)
            frm.show()
            self.refresh_column = column
            self.parameter_changed = True
            self.set_channel_cell(0)

        return local_show

    def move_table(self, index):
        """
        dynamically move table control to the currently active tab
        this is when only one table control is shared among multiple tabs
        Args:
            index: the active tab's index
        Returns:
        """
        for i in range(0, self.tabDefaults.count()):
            controls = self.tabDefaults.widget(i).findChildren(
                QTableWidget, self.tblGeneric.objectName())
            if len(controls) > 0 and i != index:
                layout_src = self.tabDefaults.widget(i).layout()
                if layout_src is not None:
                    layout_src.removeWidget(self.tblGeneric)
                layout_dest = self.tabDefaults.widget(index).layout()
                if layout_dest is None:
                    layout_dest = QGridLayout(self.tabDefaults.widget(index))
                    self.tabDefaults.widget(index).setLayout(layout_dest)
                layout_dest.addChildWidget(self.tblGeneric)
                break

        pass

    def tab_changed(self, index):
        #self.move_table(index)
        if index == 0:
            self.help_topic = "epanet/src/src/defaultidlabels.htm"
        #    self.set_tab_prefix()
        elif index == 1:
            self.help_topic = "epanet/src/src/defaultsubcatchmentproperties.htm"
        #    self.set_sub_properties()
        elif index == 2:
            self.help_topic = "epanet/src/src/defaultnodelinkproperties.htm"
        #    self.set_tab_hydraulics()
        pass

    def tblGeneric_changed(self, row, col):
        if not self.loaded: return
        if self.tblGeneric.verticalHeaderItem(row) is None: return
        item = self.tblGeneric.item(row, col)
        if item is None: return
        key = self.tblGeneric.verticalHeaderItem(row).text()
        if key == self.defaults.id_increment_key:
            val, val_is_good = ParseData.intTryParse(item.text())
            if val_is_good:
                self.defaults.id_increment = val
        else:
            self.defaults.model_object_prefix[key] = item.text()
        self.label_changed = True
        pass

    def tbl_2_changed(self, row, col):
        if not self.loaded: return
        if self.tbl_2.verticalHeaderItem(row) is None: return
        item = self.tbl_2.item(row, col)
        if item is None: return
        key = self.tbl_2.verticalHeaderItem(row).text()
        if "infiltration model" in key.lower():
            self.defaults.properties_sub_values[key] = item.currentText()
        else:
            val, val_is_good = ParseData.floatTryParse(item.text())
            if val_is_good:
                key = self.defaults.properties_sub_keys[row]
                self.defaults.properties_sub_values[key] = val
        self.property_sub_changed = True
        pass

    def tbl_3_changed(self, row, col):
        if not self.loaded: return
        if self.tbl_3.verticalHeaderItem(row) is None: return
        item = self.tbl_3.item(row, col)
        if item is None: return
        key = self.tbl_3.verticalHeaderItem(row).text()
        if "flow_units" in key.lower() or \
           "link_offsets" in key.lower() or \
           "routing" in key.lower() or \
           "force_main" in key.lower():
            # do nothing
            pass
        elif "conduit_shape" in key.lower():
            #self.defaults.xsection.shape = CrossSection[item.text()]
            pass
        else:
            val, val_is_good = ParseData.floatTryParse(item.text())
            if val_is_good:
                key = self.defaults.parameters_keys[row]
                self.defaults.parameters_values[key] = val
        self.parameter_changed = True
        pass

    def tbl_3_combo_indexChanged(self, index):
        if not self.loaded: return
        cb = self.tbl_3.cellWidget(index, 0)
        key = self.tbl_3.verticalHeaderItem(index).text()
        val = cb.currentText()
        self.defaults.parameters_values[key] = val
        self.parameter_changed = True
        pass

    def cmdOK_Clicked(self):
        """
        save/sync user changes to the defaults
        Returns:
        """
        if self.label_changed:
            self.defaults.sync_defaults_label()
            pass

        if self.property_sub_changed:
            self.defaults.sync_defaults_sub_property()
            pass

        if self.parameter_changed:
            self.defaults.sync_defaults_parameter()
            pass

        if self.chk4all.isChecked():
            # take default labels and defaults from project ini file and apply to global SWMM.ini file
            self.session.program_settings.sync()
            pass

        self.close()
        pass

    def cmdCancel_Clicked(self):
        """
        discard user changes to the defaults
        Returns:
        """
        self.close()
        pass

    def cmdHelp_Clicked(self):
        """
        display help
        """
        self.helper.show_help()
        pass
class frmCurveEditor(QMainWindow, Ui_frmCurveEditor):
    def __init__(self, main_form, title, curve_type, edit_these, new_item):
        QMainWindow.__init__(self, main_form)
        self.helper = HelpHandler(self)
        self.help_topic = "swmm/src/src/curveeditordialog.htm"
        self.setupUi(self)
        if title:
            self.setWindowTitle(title)
        self.cboCurveType.clear()
        ui.convenience.set_combo_items(core.swmm.curves.CurveType,
                                       self.cboCurveType)
        self.cmdOK.clicked.connect(self.cmdOK_Clicked)
        self.cmdCancel.clicked.connect(self.cmdCancel_Clicked)
        self.btnSave.clicked.connect(self.save_curve_data)
        self.btnLoad.clicked.connect(self.load_curve_data)
        self.btnHelp.clicked.connect(self.show_help)
        self.btnView.clicked.connect(self.btnView_Clicked)
        # self.cboCurveType.clicked.connect(self.cboCurveType_currentIndexChanged)
        self.cboCurveType.currentIndexChanged.connect(
            self.cboCurveType_currentIndexChanged)
        # self.set_from(main_form.project)   # do after init to set curve type
        self._main_form = main_form
        self.curve_type = curve_type
        self.project = main_form.project
        self.section = self.project.curves
        self.X = []
        self.Y = []
        self.new_item = new_item
        if new_item:
            self.set_from(new_item)
        elif edit_these:
            if isinstance(edit_these,
                          list):  # edit first transect if given a list
                self.set_from(edit_these[0])
            else:
                self.set_from(edit_these)

        if (main_form.program_settings.value("Geometry/" +
                                             "frmCurveEditor_geometry")
                and main_form.program_settings.value("Geometry/" +
                                                     "frmCurveEditor_state")):
            self.restoreGeometry(
                main_form.program_settings.value("Geometry/" +
                                                 "frmCurveEditor_geometry",
                                                 self.geometry(),
                                                 type=QtCore.QByteArray))
            self.restoreState(
                main_form.program_settings.value("Geometry/" +
                                                 "frmCurveEditor_state",
                                                 self.windowState(),
                                                 type=QtCore.QByteArray))

    def set_from(self, curve):
        flow_units = self._main_form.project.options.flow_units.name
        if not isinstance(curve, Curve):
            curve = self.section.value[curve]
        if isinstance(curve, Curve):
            self.editing_item = curve
            self.tblMult.setRowCount(
                max(len(curve.curve_xy) + 1, self.tblMult.rowCount()))
        if self.curve_type == "CONTROL":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            self.tblMult.setHorizontalHeaderLabels(
                ("Controller Value", "Control Setting"))
        elif self.curve_type == "DIVERSION":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            self.tblMult.setHorizontalHeaderLabels(
                ("Inflow (" + flow_units + ")",
                 "Outflow (" + flow_units + ")"))
        elif self.curve_type == "PUMP":
            self.cboCurveType.setVisible(True)
            self.lblCurveType.setVisible(True)

            if curve.curve_type.name == "PUMP1":
                if self._main_form.project.metric:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Volume (m3)", "Flow (" + flow_units + ")"))
                else:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Volume (ft3)", "Flow (" + flow_units + ")"))
            if curve.curve_type.name == "PUMP2":
                if self._main_form.project.metric:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Depth (m)", "Flow (" + flow_units + ")"))
                else:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Depth (ft)", "Flow (" + flow_units + ")"))
            if curve.curve_type.name == "PUMP3":
                if self._main_form.project.metric:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Head (m)", "Flow (" + flow_units + ")"))
                else:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Head (ft)", "Flow (" + flow_units + ")"))
            if curve.curve_type.name == "PUMP4":
                if self._main_form.project.metric:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Depth (m)", "Flow (" + flow_units + ")"))
                else:
                    self.tblMult.setHorizontalHeaderLabels(
                        ("Depth (ft)", "Flow (" + flow_units + ")"))

            self.cboCurveType.clear()
            self.cboCurveType.addItems(("TYPE1", "TYPE2", "TYPE3", "TYPE4"))
        elif self.curve_type == "RATING":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Head (m)", "Outflow (" + flow_units + ")"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Head (ft)", "Outflow (" + flow_units + ")"))
        elif self.curve_type == "SHAPE":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            self.tblMult.setHorizontalHeaderLabels(
                ("Depth/Full Depth", "Width/Full Depth"))
        elif self.curve_type == "STORAGE":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Depth (m)", "Area (m2)"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Depth (ft)", "Area (ft2)"))
        elif self.curve_type == "TIDAL":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Hour of Day", "Stage (m)"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Hour of Day", "Stage (ft)"))
        elif self.curve_type == "WEIR":
            self.cboCurveType.setVisible(False)
            self.lblCurveType.setVisible(False)
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Head (m)", "Coefficient"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Head (ft)", "Coefficient"))

        self.txtCurveName.setText(str(curve.name))
        self.txtDescription.setText(str(curve.comment))
        if self.curve_type == "PUMP":
            if curve.curve_type.name == "PUMP1":
                self.cboCurveType.setCurrentIndex(0)
            if curve.curve_type.name == "PUMP2":
                self.cboCurveType.setCurrentIndex(1)
            if curve.curve_type.name == "PUMP3":
                self.cboCurveType.setCurrentIndex(2)
            if curve.curve_type.name == "PUMP4":
                self.cboCurveType.setCurrentIndex(3)
        point_count = -1
        for point in curve.curve_xy:
            point_count += 1
            led = QLineEdit(str(point[0]))
            self.tblMult.setItem(point_count, 0, QTableWidgetItem(led.text()))
            led = QLineEdit(str(point[1]))
            self.tblMult.setItem(point_count, 1, QTableWidgetItem(led.text()))

    def cmdOK_Clicked(self):
        # TODO: Check for blank/duplicate curve name
        # TODO: Check if X-values are in ascending order
        orig_name = self.editing_item.name
        orig_comment = self.editing_item.comment
        orig_type = self.editing_item.curve_type
        orig_xy = self.editing_item.curve_xy

        self.editing_item.name = self.txtCurveName.text()
        self.editing_item.comment = self.txtDescription.text()
        if len(self.editing_item.comment) > 0:
            if self.editing_item.comment[0] != ';':
                self.editing_item.comment = ';' + self.editing_item.comment
        # curve.curve_type = core.swmm.curves.CurveType[self.cboCurveType.currentText()]
        if self.curve_type == "PUMP":
            if self.cboCurveType.currentIndex() == 0:
                self.editing_item.curve_type = core.swmm.curves.CurveType[
                    "PUMP1"]
            if self.cboCurveType.currentIndex() == 1:
                self.editing_item.curve_type = core.swmm.curves.CurveType[
                    "PUMP2"]
            if self.cboCurveType.currentIndex() == 2:
                self.editing_item.curve_type = core.swmm.curves.CurveType[
                    "PUMP3"]
            if self.cboCurveType.currentIndex() == 3:
                self.editing_item.curve_type = core.swmm.curves.CurveType[
                    "PUMP4"]
        self.editing_item.curve_xy = []
        for row in range(self.tblMult.rowCount()):
            if self.tblMult.item(row, 0) and self.tblMult.item(row, 1):
                x = self.tblMult.item(row, 0).text()
                y = self.tblMult.item(row, 1).text()
                if len(x) > 0 and len(y) > 0:
                    self.editing_item.curve_xy.append((x, y))
        if self.new_item:  # We are editing a newly created item and it needs to be added to the project
            self._main_form.add_item(self.new_item)
            self._main_form.mark_project_as_unsaved()
        else:
            pass
            # TODO: self._main_form.edited_?

        if orig_name != self.editing_item.name or \
            orig_comment != self.editing_item.comment or \
            orig_type != self.editing_item.curve_type or \
            orig_xy != self.editing_item.curve_xy:
            self._main_form.mark_project_as_unsaved()

        self._main_form.program_settings.setValue(
            "Geometry/" + "frmCurveEditor_geometry", self.saveGeometry())
        self._main_form.program_settings.setValue(
            "Geometry/" + "frmCurveEditor_state", self.saveState())
        self.close()

    def cmdCancel_Clicked(self):
        self.close()

    def cboCurveType_currentIndexChanged(self, newIndex):
        curve_type = self.cboCurveType.currentText()
        flow_units = self._main_form.project.options.flow_units.name
        if curve_type == "TYPE1":
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Volume (m3)", "Flow (" + flow_units + ")"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Volume (ft3)", "Flow (" + flow_units + ")"))
        elif curve_type == "TYPE2":
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Depth (m)", "Flow (" + flow_units + ")"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Depth (ft)", "Flow (" + flow_units + ")"))
        elif curve_type == "TYPE3":
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Head (m)", "Flow (" + flow_units + ")"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Head (ft)", "Flow (" + flow_units + ")"))
        elif curve_type == "TYPE4":
            if self._main_form.project.metric:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Depth (m)", "Flow (" + flow_units + ")"))
            else:
                self.tblMult.setHorizontalHeaderLabels(
                    ("Depth (ft)", "Flow (" + flow_units + ")"))

    def load_curve_data(self):
        directory = self._main_form.program_settings.value("DataDir", "")
        file_name, ftype = QFileDialog.getOpenFileName(self,
                                                       "Open Curve Data File",
                                                       directory,
                                                       "Curve Files (*.dat)")
        if os.path.exists(file_name):
            self._main_form.program_settings.setValue(
                "DataDir", os.path.dirname(file_name))
            self._main_form.program_settings.sync()

        if file_name:
            with open(file_name, "r") as open_file:
                lines = open_file.readlines()

            if len(lines) > 1:
                a = lines[1].split()
                self.txtDescription.setText(a[len(a) - 1])
            if len(lines) > 2:
                curve_xy = []
                for i in range(2, len(lines)):
                    try:
                        x, y = lines[i].split()
                        xval, xval_is_good = ParseData.floatTryParse(x)
                        yval, yval_is_good = ParseData.floatTryParse(y)
                        if xval_is_good and yval_is_good:
                            curve_xy.append((x, y))

                        point_count = -1
                        for point in curve_xy:
                            point_count += 1
                            led = QLineEdit(str(point[0]))
                            self.tblMult.setItem(point_count, 0,
                                                 QTableWidgetItem(led.text()))
                            led = QLineEdit(str(point[1]))
                            self.tblMult.setItem(point_count, 1,
                                                 QTableWidgetItem(led.text()))

                        pass
                    except Exception as ex:
                        pass

    def save_curve_data(self):
        directory = self._main_form.program_settings.value("DataDir", "")
        file_name, ftype = QFileDialog.getSaveFileName(self,
                                                       "Save Curve Data File",
                                                       directory,
                                                       "Curve files (*.dat)")
        if os.path.exists(file_name):
            self._main_form.program_settings.setValue(
                "DataDir", os.path.dirname(file_name))
            self._main_form.program_settings.sync()
        if file_name:
            path_only, file_only = os.path.split(file_name)
            try:
                self.curve_data_to_file(file_name)
            except Exception as ex:
                print(str(ex) + '\n' + str(traceback.print_exc()))
                QMessageBox.information(
                    self, self._main_form.model,
                    "Error saving {0}\nin {1}\n{2}\n{2}".format(
                        file_only, path_only, str(ex),
                        str(traceback.print_exc())), QMessageBox.Ok)

    def curve_data_to_file(self, file_name):
        if file_name:
            with open(file_name, 'w') as writer:
                #writer.writelines(self.as_text(project))
                writer.write("EPASWMM Curve Data\n")
                writer.write(self.txtDescription.text() + "\n")
                for row in range(self.tblMult.rowCount()):
                    if self.tblMult.item(row, 0) and self.tblMult.item(row, 1):
                        x = self.tblMult.item(row, 0).text()
                        y = self.tblMult.item(row, 1).text()
                        if len(x) > 0 and len(y) > 0:
                            writer.write("%s  %s\n" % (str(x), str(y)))

    def show_help(self):
        self.helper.show_help()

    def GetData(self):
        # construct pandas time series from grid data
        del self.X[:]
        del self.Y[:]
        n = 0
        for row in range(self.tblMult.rowCount()):
            if self.tblMult.item(row, 1):
                y_val, y_val_good = ParseData.floatTryParse(
                    self.tblMult.item(row, 1).text())
                x_val, x_val_good = ParseData.floatTryParse(
                    self.tblMult.item(row, 0).text())
                if y_val_good and x_val_good:
                    # as long as the values are good
                    self.Y.append(y_val)
                    self.X.append(x_val)
                    n += 1
            else:
                return n
        return n

    def btnView_Clicked(self):
        """
        Display the grid data with pandas dataframe plot function
        Returns: None
        """
        n = self.GetData()
        if n > 0:
            ds = pd.Series(self.Y, index=self.X)
            df = pd.DataFrame({'DS-': ds})
            # if Pump Type1 or Type2, plot as step function
            if self.curve_type == 'PUMP' and self.cboCurveType.currentIndex(
            ) in (0, 1):
                frm_plt = frmPlotViewer(
                    df, 'step',
                    self.curve_type + ' Curve ' + self.txtCurveName.text(),
                    self.windowIcon(),
                    self.tblMult.horizontalHeaderItem(0).text(),
                    self.tblMult.horizontalHeaderItem(1).text())
            else:
                frm_plt = frmPlotViewer(
                    df, 'xy',
                    self.curve_type + ' Curve ' + self.txtCurveName.text(),
                    self.windowIcon(),
                    self.tblMult.horizontalHeaderItem(0).text(),
                    self.tblMult.horizontalHeaderItem(1).text())
            # frm_plt.setWindowTitle('Curve Viewer')
            # frm_plt.setWindowModality(QtCore.Qt.ApplicationModal)
            # frm_plt.show()
        pass

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Return:
            if self.tblMult.currentRow() + 1 == self.tblMult.rowCount():
                self.tblMult.insertRow(self.tblMult.rowCount())