From aced2d7a5ecd9c357b3d538a36caf8044c7eea64 Mon Sep 17 00:00:00 2001 From: Pierre-Antoine Rouby Date: Thu, 16 Mar 2023 15:39:56 +0100 Subject: [PATCH] Configure: Switch to list of solver. --- src/config.py | 10 +- src/solver/ASolver.py | 78 +++- src/solver/GenericSolver.py | 11 + src/view/ASubWindow.py | 42 +- src/view/ConfigureAddSolverWindow.py | 76 +++ src/view/ConfigureWindow.py | 136 ++++-- src/view/MainWindow.py | 2 +- src/view/ui/ConfigureAddSolverDialog.ui | 214 +++++++++ src/view/ui/ConfigureDialog.ui | 593 ++++++++++++------------ 9 files changed, 817 insertions(+), 345 deletions(-) create mode 100644 src/solver/GenericSolver.py create mode 100644 src/view/ConfigureAddSolverWindow.py create mode 100644 src/view/ui/ConfigureAddSolverDialog.ui diff --git a/src/config.py b/src/config.py index 26416b78..f0097680 100644 --- a/src/config.py +++ b/src/config.py @@ -14,13 +14,13 @@ class Config(object): self.set_default_value() def set_default_value(self): - # Mage - self.mage_path = "" - self.mage_extract_path = "" - self.mailleur_path = "" + # Solvers + self.solvers = [] + + # Mailleur + self.mailleur = "" # Const - self.manning = False self.segment = 1000 self.max_listing = 500000 diff --git a/src/solver/ASolver.py b/src/solver/ASolver.py index a985cc49..ecdecd25 100644 --- a/src/solver/ASolver.py +++ b/src/solver/ASolver.py @@ -14,23 +14,83 @@ class AbstractSolver(object): def __init__(self, name): super(AbstractSolver, self).__init__() - self.name = name + self.current_process = None self.status = STATUS.STOPED - def nb_proc(self): - """ - Return the number of processor used by solver (usefull for - multiple solver run on same time). - """ - return 1 + # Informations + self._type = "" + self.name = name + self.description = "" - def status(self): + self.path_input = "" + self.path_solver = "" + self.path_output = "" + + self.cmd_input = "" + self.cmd_solver = "" + self.cmd_output = "" + + def __str__(self): + return f"{self.name} : {self._type} : {self.description}" + + # Getter + def get_status(self): return self.status + def get_type(self): + return self._type + + def __getitem__(self, name): + ret = None + + if name == "name": + ret = self.name + elif name == "description": + ret = self.description + elif name == "type": + ret = self._type + + return ret + + # Setter def set_status(self, status): self.status = status - def run(self): + def set_name(self, name): + self.name = name + + def set_description(self, description): + self.description = description + + def set_input(self, path, cmd): + self.path_input = path + self.cmd_input = cmd + + def set_solver(self, path, cmd): + self.path_solver = path + self.cmd_solver = cmd + + def set_output(self, path, cmd): + self.path_output = path + self.cmd_output = cmd + + # Run + def run_input_data_fomater(self): + if self.cmd_input == "": + return True + + return False + + def run_solver(self): + if self.cmd_solver == "": + return True + + return False + + def run_output_data_fomater(self, ): + if self.cmd_output == "": + return True + return False def kill(self): diff --git a/src/solver/GenericSolver.py b/src/solver/GenericSolver.py new file mode 100644 index 00000000..b756f7c0 --- /dev/null +++ b/src/solver/GenericSolver.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- + +from solver.ASolver import ( + AbstractSolver, STATUS +) + +class GenericSolver(AbstractSolver): + def __init__(self, name): + super(GenericSolver, self).__init__(name) + + self._type = "generic" diff --git a/src/view/ASubWindow.py b/src/view/ASubWindow.py index 5ef00fca..968f54ab 100644 --- a/src/view/ASubWindow.py +++ b/src/view/ASubWindow.py @@ -7,7 +7,7 @@ from PyQt5.QtWidgets import ( QMdiArea, QMdiSubWindow, QDialog, QPushButton, QLineEdit, QCheckBox, QTimeEdit, QSpinBox, QTextEdit, - QRadioButton, + QRadioButton, QComboBox, QFileDialog, ) from PyQt5.QtCore import ( QTime, @@ -182,3 +182,43 @@ class ASubWindow(QDialog): The status of radio button """ return self.find(QRadioButton, name).isChecked() + + def combobox_add_item(self, name:str, item:str): + """Add item in combo box + + Args: + name: The combo box component name + item: The item to add + + Returns: + Nothing + """ + self.find(QComboBox, name).addItem(item) + + def set_combobox_text(self, name:str, item:str): + """Set current text of combo box + + Args: + name: The combo box component name + item: The item to add + + Returns: + Nothing + """ + self.find(QComboBox, name).setCurrentText(item) + + + # Custom dialog + def file_dialog(self, select_file=True, callback=lambda x: None): + dialog = QFileDialog(self) + + if select_file: + mode = QFileDialog.FileMode.ExistingFile + else: + mode = QFileDialog.FileMode.Directory + + dialog.setFileMode(mode) + + if dialog.exec_(): + file_names = dialog.selectedFiles() + callback(file_names) diff --git a/src/view/ConfigureAddSolverWindow.py b/src/view/ConfigureAddSolverWindow.py new file mode 100644 index 00000000..0246477e --- /dev/null +++ b/src/view/ConfigureAddSolverWindow.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +from view.ASubWindow import ASubWindow +from solver.GenericSolver import GenericSolver + +from PyQt5.QtWidgets import ( + QPushButton, +) + +class ConfigureAddSolverWindow(ASubWindow): + def __init__(self, data=None, title="Configuration : Add Solver", parent=None): + super(ConfigureAddSolverWindow, self).__init__( + name=title, ui="ConfigureAddSolverDialog", parent=parent + ) + self.ui.setWindowTitle(title) + + # Combo box item + self.combobox_add_item("comboBox_solver", "Generic") + self.combobox_add_item("comboBox_solver", "Mage") + self.combobox_add_item("comboBox_solver", "Rubarbe") + + # Data to return + self.data = data + if not self.data is None: + self.copy_data() + + self.connect() + + def copy_data(self): + self.set_combobox_text("comboBox_solver", self.data.get_type()) + self.set_line_edit_text("lineEdit_name", self.data.name) + self.set_line_edit_text("lineEdit_description", self.data.description) + self.set_line_edit_text("lineEdit_input", self.data.path_input) + self.set_line_edit_text("lineEdit_input_cmd", self.data.cmd_input) + self.set_line_edit_text("lineEdit_solver", self.data.path_solver) + self.set_line_edit_text("lineEdit_solver_cmd", self.data.cmd_solver) + self.set_line_edit_text("lineEdit_output", self.data.path_output) + self.set_line_edit_text("lineEdit_output_cmd", self.data.cmd_output) + + def connect(self): + # File button + buttons = { + "pushButton_input": (lambda: self.file_dialog( + select_file = True, + callback = lambda f: self.set_line_edit_text("lineEdit_input", f[0]) + )), + "pushButton_solver": (lambda: self.file_dialog( + select_file = True, + callback = lambda f: self.set_line_edit_text("lineEdit_solver", f[0]) + )), + "pushButton_output": (lambda: self.file_dialog( + select_file = True, + callback = lambda f: self.set_line_edit_text("lineEdit_output", f[0]) + )), + } + + for button in buttons: + self.find(QPushButton, button).clicked.connect(buttons[button]) + + def accept(self): + self.data = GenericSolver(self.get_line_edit_text("lineEdit_name")) + self.data.set_description(self.get_line_edit_text("lineEdit_description")) + self.data.set_input( + self.get_line_edit_text("lineEdit_input"), + self.get_line_edit_text("lineEdit_input_cmd") + ) + self.data.set_solver( + self.get_line_edit_text("lineEdit_solver"), + self.get_line_edit_text("lineEdit_solver_cmd") + ) + self.data.set_output( + self.get_line_edit_text("lineEdit_output"), + self.get_line_edit_text("lineEdit_output_cmd") + ) + + self.done(True) diff --git a/src/view/ConfigureWindow.py b/src/view/ConfigureWindow.py index ebb083ff..369ca372 100644 --- a/src/view/ConfigureWindow.py +++ b/src/view/ConfigureWindow.py @@ -2,12 +2,62 @@ from config import Config from view.ASubWindow import ASubWindow -from PyQt5.QtWidgets import ( - QDialogButtonBox, QPushButton, QLineEdit, - QFileDialog, +from view.ListedSubWindow import ListedSubWindow +from view.ConfigureAddSolverWindow import ConfigureAddSolverWindow + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, ) -class ConfigureWindow(ASubWindow): +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, +) + + +class SolverTableModel(QAbstractTableModel): + def __init__(self, headers=[], rows=[]): + super(QAbstractTableModel, self).__init__() + self.rows = rows + self.headers = headers + + def rowCount(self, parent): + # How many rows are there? + return len(self.rows) + + def columnCount(self, parent): + # How many columns? + return len(self.headers) + + def data(self, index, role): + if role != Qt.ItemDataRole.DisplayRole: + return QVariant() + + return self.rows[index.row()][self.headers[index.column()]] + + def headerData(self, section, orientation, role): + if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal: + return self.headers[section] + + if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Vertical: + return section + + return QVariant() + + def removeRow(self, index): + del self.rows[index.row()] + self.layoutChanged.emit() + + def add_solver(self, solver): + self.rows.append(solver) + self.layoutChanged.emit() + + def change_solver(self, solver, index): + self.rows[index.row()] = solver + self.layoutChanged.emit() + + +class ConfigureWindow(ASubWindow, ListedSubWindow): def __init__(self, conf=None, title="Configure", parent=None): super(ConfigureWindow, self).__init__(name=title, ui="ConfigureDialog", parent=parent) self.ui.setWindowTitle(title) @@ -17,13 +67,17 @@ class ConfigureWindow(ASubWindow): else: self.conf = conf - # MAGE - self.set_line_edit_text("lineEdit_exec_mage", self.conf.mage_path) - self.set_line_edit_text("lineEdit_exec_mage_extract", self.conf.mage_extract_path) - self.set_line_edit_text("lineEdit_exec_mailleur", self.conf.mailleur_path) + # Solver + self.solver_table_model = SolverTableModel( + headers = ["name", "type", "description"], + rows = conf.solvers.copy() + ) + self.find(QTableView, "tableView_solver").setModel(self.solver_table_model) + + # Mailleur + self.set_line_edit_text("lineEdit_mailleur", self.conf.mailleur) # Const - self.set_check_box("checkBox_manning", self.conf.manning) self.set_line_edit_text("lineEdit_segment", str(self.conf.segment)) self.set_line_edit_text("lineEdit_max_listing", str(self.conf.max_listing)) @@ -38,23 +92,34 @@ class ConfigureWindow(ASubWindow): def connect(self): # File button buttons = { - "pushButton_exec_mage": lambda: self.file_dialog("exec_mage", True), - "pushButton_exec_mage_extract": lambda: self.file_dialog("exec_mage_extract", True), - "pushButton_exec_mailleur": lambda: self.file_dialog("exec_mailleur", True), - "pushButton_backup_path": lambda: self.file_dialog("backup_path", False), + "pushButton_solver_add": self.add_solver, + "pushButton_solver_del": self.remove_solver, + "pushButton_solver_edit": self.edit_solver, + "pushButton_backup_path": lambda: self.file_dialog( + select_file = False, + callback = lambda f: self.set_line_edit_text( + "lineEdit_backup_path", f[0] + ) + ), + "pushButton_mailleur" : lambda: self.file_dialog( + select_file = True, + callback = lambda f: self.set_line_edit_text( + "lineEdit_mailleur", f[0] + ) + ), } for button in buttons: self.find(QPushButton, button).clicked.connect(buttons[button]) def accept(self): - # MAGE - self.conf.mage_path = self.get_line_edit_text("lineEdit_exec_mage") - self.conf.mage_extract_path = self.get_line_edit_text("lineEdit_exec_mage_extract") - self.conf.mailleur_path = self.get_line_edit_text("lineEdit_exec_mailleur") + # Solvers + self.conf.solvers = self.solver_table_model.rows.copy() + + # Mailleur + self.conf.mailleur = self.get_line_edit_text("lineEdit_mailleur") # Const - self.conf.manning = self.get_check_box("checkBox_manning") self.conf.segment = self.get_line_edit_text("lineEdit_segment") self.conf.max_listing = self.get_line_edit_text("lineEdit_max_listing") @@ -74,23 +139,22 @@ class ConfigureWindow(ASubWindow): self.conf.save() self.close() - def file_dialog(self, line_edit, select_file): - dialog = QFileDialog(self) + def edit_solver(self): + indices = self.find(QTableView, "tableView_solver").selectionModel().selectedRows() + for index in indices: + self.edit_solver = ConfigureAddSolverWindow( + data=self.solver_table_model.rows[index.row()], + parent=self + ) + if self.edit_solver.exec_(): + self.solver_table_model.change_solver(self.edit_solver.data, index) - if select_file: - mode = QFileDialog.FileMode.ExistingFile - else: - mode = QFileDialog.FileMode.Directory + def add_solver(self): + dialog_solver = ConfigureAddSolverWindow(parent=self) + if dialog_solver.exec_(): + self.solver_table_model.add_solver(dialog_solver.data) - dialog.setFileMode(mode) - - if dialog.exec_(): - file_names = dialog.selectedFiles() - if len(file_names) != 1: - print("pas bien") - else: - if line_edit != "": - self.set_line_edit_text( - f"lineEdit_{line_edit}", - file_names[0] - ) + def remove_solver(self): + indices = self.find(QTableView, "tableView_solver").selectionModel().selectedRows() + for index in sorted(indices): + self.solver_table_model.removeRow(index) diff --git a/src/view/MainWindow.py b/src/view/MainWindow.py index 640caef8..fd36a135 100644 --- a/src/view/MainWindow.py +++ b/src/view/MainWindow.py @@ -238,7 +238,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow): dialog.setFileMode(QFileDialog.FileMode.ExistingFile) dialog.setDefaultSuffix(".pkl") #dialog.setFilter(dialog.filter() | QtCore.QDir.Hidden) - dialog.setNameFilters(['PKL (*.pkl)']) + dialog.setNameFilters(['PamHyr (*.pkl)']) if dialog.exec_(): file_name = dialog.selectedFiles() diff --git a/src/view/ui/ConfigureAddSolverDialog.ui b/src/view/ui/ConfigureAddSolverDialog.ui new file mode 100644 index 00000000..08efab72 --- /dev/null +++ b/src/view/ui/ConfigureAddSolverDialog.ui @@ -0,0 +1,214 @@ + + + Dialog + + + + 0 + 0 + 741 + 289 + + + + Dialog + + + + + 10 + 10 + 721 + 271 + + + + + + + + + Name + + + + + + + Type + + + + + + + + + + + + + + Description + + + + + + + + + + + + + + + + + Solver + + + + + + + + + + + + + + + + ressources/open.pngressources/open.png + + + + + + + + + + + + Path + + + + + + + Output formater + + + + + + + + + + Command line + + + + + + + + + + Input formater + + + + + + + + + + + + + + + + ressources/open.pngressources/open.png + + + + + + + + + + + + + + + + + + ressources/open.pngressources/open.png + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/view/ui/ConfigureDialog.ui b/src/view/ui/ConfigureDialog.ui index b8316907..ecaf8c02 100644 --- a/src/view/ui/ConfigureDialog.ui +++ b/src/view/ui/ConfigureDialog.ui @@ -6,8 +6,8 @@ 0 0 - 770 - 351 + 658 + 381 @@ -17,306 +17,313 @@ 10 - 20 - 751 - 321 + 10 + 641 + 361 - + - - - - - true + + + 0 + + + false + + + false + + + false + + + false + + + + Solvers + + + + + 10 + 10 + 611 + 271 + - - Executable - - - - - 10 - 20 - 351 - 111 - - - - - - - - - MAGE - - - - - - - MAGE_Extraire - - - - - - - Mailleur - - - - - - - - - - - - - - - - - - - - ressources/open.pngressources/open.png - - - - - - - - - - - - - - - - - - ressources/open.pngressources/open.png - - - - - - - - - - - - - - - - - - ressources/open.pngressources/open.png - - - - - - - - - + + + + + + + + + + + ressources/gtk_add.pngressources/gtk_add.png + + + + + + + + + + + ressources/gtk-remove.pngressources/gtk-remove.png + + + + + + + + + + + ressources/edit.pngressources/edit.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 156 + + + + + - - - - - BackUp + + + + Mailleur + + + + + 10 + 10 + 621 + 30 + - - - - 10 - 20 - 343 - 125 - - - - - - - - - Sauvegarde automatique - - - - - - - Chemin - - - - - - - Frequence - - - - - - - Max. archives - - - - - - - - - - - Activé - - - false - - - - - - - - - - - - - - - - ressources/open.pngressources/open.png - - - - - - - - - - - - HH:mm:ss - - - Qt::LocalTime - - - - - - - - - - 1 - - - 10 - - - - - - - + + + + + Mailleur path + + + + + + + + + + + + + + ressources/open.pngressources/open.png + + + + - - - - - Constante numérique + + + + Constants + + + + + 10 + 10 + 621 + 93 + - - - - 10 - 30 - 268 - 93 - - - - - - - - - Frottement - - - - - - - Nombre de segment - - - - - - - Taille max. du listing - - - - - - - - - - - Manning - - - - - - - 1000 - - - - - - - 500000 - - - - - - - + + + + + + + Nombre de segment + + + + + + + Taille max. du listing + + + + + + + + + + + 1000 + + + + + + + 500000 + + + + + + - - + + + + Backup + + + + + 10 + 10 + 611 + 125 + + + + + + + + + Sauvegarde automatique + + + + + + + Chemin + + + + + + + Frequence + + + + + + + Max. archives + + + + + + + + + + + Activé + + + false + + + + + + + + + + + + + + + + ressources/open.pngressources/open.png + + + + + + + + + + + + HH:mm:ss + + + Qt::LocalTime + + + + + + + + + + 1 + + + 10 + + + + + + + + +