MainWindow.py 15.8 KB
Newer Older
# -*- coding: utf-8 -*-

import os
from queue import Queue
from PyQt5 import QtGui
from PyQt5.QtGui import (
    QKeySequence,
)

from PyQt5.QtCore import (
    QTranslator, QEvent
)
from PyQt5.QtWidgets import (
    QMainWindow, QApplication, QAction,
    QFileDialog, QShortcut, QMenu, QToolBar,
)
from PyQt5.uic import loadUi
from View.ASubWindow import WindowToolKit
from View.ListedSubWindow import ListedSubWindow
from View.DummyWindow import DummyWindow
from View.Configure.Window import ConfigureWindow
from View.Study.Window import NewStudyWindow
from View.About.Window import AboutWindow
from View.Network.Window import NetworkWindow
from View.Geometry.Window import GeometryWindow
from View.BoundaryCondition.Window import BoundaryConditionWindow
from View.LateralContribution.Window import LateralContributionWindow
from View.InitialConditions.Window import InitialConditionsWindow
from View.Stricklers.Window import StricklersWindow
from View.Sections.Window import SectionsWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.CheckList.Window import CheckListWindow
from View.Debug.Window import ReplWindow
from Model.Study import Study
    "action_menu_new", "action_menu_open", "action_menu_import_mage",
    "action_menu_import_rubarbe", "action_toolBar_open",
    "action_menu_close", "action_menu_edit", "action_menu_save",
    "action_menu_save_as", "action_toolBar_close", "action_toolBar_save",
    "action_toolBar_run_solver", "action_toolBar_kill_solver"
    "action_toolBar_network", "action_toolBar_geometry",
    "action_toolBar_mesh", "action_toolBar_run_meshing_tool",
    "action_toolBar_boundary_cond", "action_toolBar_lateral_contrib",
    "action_toolBar_spills", "action_toolBar_sections",
    "action_toolBar_stricklers", "action_toolBar_building",
    "action_toolBar_initial_cond",
    "action_menu_run_solver", "action_menu_numerical_parameter",
    "action_menu_edit_network", "action_menu_edit_geometry",
    "action_menu_boundary_conditions", "action_menu_initial_conditions",
    "action_menu_edit_friction", "action_menu_edit_lateral_contribution",
    "action_menu_run_solver",
]

action = (
    no_model_action + model_action + define_model_action
)

class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
    def __init__(self, conf=None):
        super(ApplicationWindow, self).__init__()
        self._close_question = False

        # App Configuration
        self.conf = conf

            os.path.join(os.path.dirname(__file__), "ui", "MainWindow.ui"),
        self.setup_sc()
        self.setup_connection()
        self.setup_debug_mode(init = True)
        #self.ui.retranslateUi()
    def set_title(self):
        if self.model is not None:
            self.setWindowTitle(f"PAMHYR - {self.model.name}")
        else:
            self.setWindowTitle("PAMHYR")

    def enable_actions(self, action:str, enable:bool):
        """Enable of disable an action componant

        Args:
            action: Action to enable/disable
            enable: True to Enable, or False to disable

        Returns:
            Nothing
        """
        self.findChild(QAction, action).setEnabled(enable)
        # self._run_sc = QShortcut(QKeySequence("F5"), self)
        return
        """Connect action to callback function

        Returns:
            Nothing
        """
        actions = {
            # Menu action
            "action_menu_config": self.open_configure,
            "action_menu_new": self.open_new_study,
            "action_menu_edit": self.open_edit_study,
            "action_menu_open": self.open_model,
            "action_menu_save": self.save_study,
            "action_menu_save_as": self.save_as_study,
            "action_menu_numerical_parameter": self.open_solver_parameters,
            "action_menu_edit_network": self.open_network,
            "action_menu_edit_geometry": self.open_geometry,
            "action_menu_boundary_conditions": self.open_boundary_cond,
            "action_menu_initial_conditions": self.open_initial_conditions,
            "action_menu_edit_friction": self.open_sections,
            "action_menu_edit_lateral_contribution": self.open_lateral_contrib,
            "action_menu_run_solver": self.run_solver,
            ## Help
            "action_menu_about": self.open_about,
            # ToolBar action
            "action_toolBar_quit": self.close,
            "action_toolBar_open": self.open_model,
            "action_toolBar_save": self.save_study,
            "action_toolBar_close": self.close_model,
            "action_toolBar_run_solver": self.run_solver,
            ## Current actions
            "action_toolBar_network": self.open_network,
            "action_toolBar_geometry": self.open_geometry,
            "action_toolBar_mesh": lambda: self.open_dummy("Mesh"),
            "action_toolBar_run_meshing_tool": self.open_solver_parameters,
            "action_toolBar_boundary_cond": self.open_boundary_cond,
            "action_toolBar_lateral_contrib": self.open_lateral_contrib,
            "action_toolBar_spills": lambda: self.open_dummy("Deversement"),
            "action_toolBar_stricklers": self.open_stricklers,
            "action_toolBar_sections": self.open_sections,
            "action_toolBar_building": lambda: self.open_dummy("Ouvrages"),
            "action_toolBar_initial_cond": self.open_initial_conditions,
            self.findChild(QAction, action)\
                .triggered.connect(actions[action])
            # action.triggered.connect(actions[action])

        # self._run_sc.activated.connect(self.run_solver)

    def changeEvent(self, event):
        if event.type() == QEvent.LanguageChange:
            self.retranslateUi()
        super(ApplicationWindow, self).changeEvent(event)

    def close(self):
        if self.model is not None and not self.model.is_saved:
            self._close_question = True
            if self.dialog_close():
                super(ApplicationWindow, self).close()
            else:
                self._close_question = False
        else:
            super(ApplicationWindow, self).close()

    def closeEvent(self, event):
        if not self._close_question:
            if self.model is not None and not self.model.is_saved:
                if self.dialog_close(cancel = False):
                    super(ApplicationWindow, self).closeEvent(event)
        else:
            super(ApplicationWindow, self).closeEvent(event)

        """Set default window style

        Returns:
            Nothing
        """
        self.update_enable_action()
        # Maximise window
        self.showMaximized()

    def set_debug_lvl(self, debug = True):
        if debug:
            logger.setLevel(logging.DEBUG)
            logger.info("Set logging level to DEBUG")
        else:
            logger.setLevel(logging.INFO)
            logger.info("Set logging level to INFO")


    def setup_debug_mode(self, init = False):
        menu = self.findChild(QMenu, "menu_help")

        if init:
            self.debug_action = QAction("Debug", self)
            self.debug_action.setStatusTip("Debug")
            self.debug_action.triggered.connect(self.open_debug)

            if self.conf.debug:
                menu.addAction(self.debug_action)
                self.set_debug_lvl(debug = True)
        else:
            if self.conf.debug:
                menu.addAction(self.debug_action)
                self.set_debug_lvl(debug = True)
            else:
                menu.removeAction(self.debug_action)
                self.set_debug_lvl(debug = False)
    #########
    # MODEL #
    #########

    def get_model(self):
        return self.model

    def set_model(self, model):
        self.model = model
        self.update_enable_action()
        self.set_title()

    def close_model(self):
        self.model = None
        self.update_enable_action()
        self.set_title()
        """Update status of action componante
        Update status of action componant, enable or disable in
        function of model state

        Returns:
            Nothing
        """
        no_model = self.model is None

        for action in no_model_action:
            self.enable_actions(action, no_model)

        for action in define_model_action + other_model_action:
            self.enable_actions(action, not no_model)

        for action in model_action:
            self.enable_actions(action, not no_model)

    ############
    # FEATURES #
    ############

    def save_study(self):
        """Save current study

        Save current study, if study as no associate file, open a
        file dialog.

        Returns:
            Nothing
        """
        if self.model.filename is None or self.model.filename == "":
            file_name, _ = QFileDialog.getSaveFileName(
                self, "Save File",
                "", "Pamhyr(*.pamhyr)"
            if file_name.rsplit(".", 1)[-1] == "pamhyr":
                self.model.filename = file_name
            else:
                self.model.filename = file_name + ".pamhyr"
        if self.model.is_saved:
            return

        self.model.save()

    def save_as_study(self):
        """Save current study as new file

        Save current study as new file, if study as no associate file,
        open a file dialog.

        Returns:
            Nothing
        """
        file_name, _ = QFileDialog.getSaveFileName(
            self, "Save File",
            "", "Pamhyr(*.pamhyr)"
        if file_name[-4:] == ".pamhyr":
            self.model.filename = file_name
        else:
            self.model.filename = file_name + ".pamhyr"
    ##################
    # MSG AND DIALOG #
    ##################
    def msg_select_reach(self):
        self.message_box("Please select a reach",
                         "Geometry edition need a reach selected "
                         "into river network window to work on it")

    def dialog_close(self, cancel = True):
        dlg = QMessageBox(self)

        dlg.setWindowTitle("Close PAMHYR without saving study")
        dlg.setText("Do you want to save current study before PAMHYR close ?")
        opt = QMessageBox.Save | QMessageBox.Ignore
        if cancel:
            opt |= QMessageBox.Cancel

        dlg.setStandardButtons(opt)
        dlg.setIcon(QMessageBox.Warning)

        res = dlg.exec()

        if res == QMessageBox.Save:
            self.save_study()
            return True
        elif res == QMessageBox.Ignore:
            return True
        elif res == QMessageBox.Cancel:
            return False

    #############
    # SUBWINDOW #
    #############

    def open_configure(self):
        """Open configure window

        Open PamHyr configure window

        Returns:
            Nothing
        """
        self.config = ConfigureWindow(conf=self.conf, parent=self)
        self.config.show()

        """Open about window

        Open a new window with information about PamHyr

        Returns:
            Nothing
        """
        self.about = AboutWindow(parent=self)
        self.about.show()

    def open_model(self):
        """Open file dialog to select saved model

        Returns:
            Nothing
        """
        if self.model is None:
            dialog = QFileDialog(self)
            dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
            dialog.setDefaultSuffix(".pamhyr")
            #dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden)
            dialog.setNameFilters(['PamHyr (*.pamhyr)'])

            if dialog.exec_():
                file_name = dialog.selectedFiles()
                self.set_model(Study.open(file_name[0]))
                logger.info(f"Open Study - {self.model.name}")
                self.set_title()

    def open_new_study(self):
        """Open dialog to set new study

        Returns:
            Nothing
        """
        if self.model is None:
            self.new_study = NewStudyWindow(parent=self)
            self.new_study.show()

    def open_edit_study(self):
        """Open dialog to set new study

        Returns:
            Nothing
        """
        if not self.model is None:
            self.new_study = NewStudyWindow(study=self.model, parent=self)
            self.new_study.show()

    def open_network(self):
        """Open network dialog

        Returns:
            Nothing
        """
        if (self.model is not None and
            not self.sub_win_exists("River network")):
            self.network = NetworkWindow(model=self.model, parent=self)
            self.network.show()
        if (self.model is not None and
            self.model.river.has_current_reach()):
            geometry = GeometryWindow(model=self.model, parent=self)
        bound = BoundaryConditionWindow(study = self.model, parent = self)
        bound.show()
    def open_lateral_contrib(self):
        lateral = LateralContributionWindow(study = self.model, parent = self)
        lateral.show()
    def open_stricklers(self):
        strick = StricklersWindow(
            study = self.model,
            config = self.conf,
    def open_sections(self):
        if (self.model is not None and
            self.model.river.has_current_reach()):
            sections = SectionsWindow(
                study = self.model,
                parent = self
            )
            sections.show()
        else:
            self.msg_select_reach()
    def open_initial_conditions(self):
        if self.model.river.has_current_reach():
            initial = InitialConditionsWindow(
                study = self.model,
                parent = self
            )
    def open_solver_parameters(self):
        params = SolverParametersWindow(
    def run_solver(self):
        run = SelectSolverWindow(
            study = self.model,
            check = CheckListWindow(
                study = self.model,
                config = self.conf,
                solver = solver,
                parent = self
            )
            check.show()
    def solver_log(self, solver):
        sol = SolverLogWindow(
            study = self.model,
            config = self.conf,
            solver = solver,
            parent = self
        )
        sol.show()

    #########
    # DEBUG #
    #########

    def open_debug(self):
        repl = ReplWindow(
            study = self.model,
            config = self.conf,
            parent = self
        )
        repl.show()

    # TODO: Delete me !
    ###############
    # DUMMY STUFF #
    ###############

    def open_dummy(self, title="Dummy"):
        self.dummy = DummyWindow(
            title=title if type(title) is str else "Dummy",
            parent=self
        )
        self.dummy.show()