From aced2d7a5ecd9c357b3d538a36caf8044c7eea64 Mon Sep 17 00:00:00 2001
From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr>
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          | 591 ++++++++++++------------
 9 files changed, 816 insertions(+), 344 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 = ""
+
+        self.path_input = ""
+        self.path_solver = ""
+        self.path_output = ""
 
-    def status(self):
+        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 view.ListedSubWindow import ListedSubWindow
+from view.ConfigureAddSolverWindow import ConfigureAddSolverWindow
+
+from PyQt5.QtCore import (
+    Qt, QVariant, QAbstractTableModel,
+)
+
 from PyQt5.QtWidgets import (
     QDialogButtonBox, QPushButton, QLineEdit,
-    QFileDialog,
+    QFileDialog, QTableView,
 )
 
-class ConfigureWindow(ASubWindow):
+
+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)
-
-        if select_file:
-            mode = QFileDialog.FileMode.ExistingFile
-        else:
-            mode = QFileDialog.FileMode.Directory
-
-        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 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)
+
+    def add_solver(self):
+        dialog_solver = ConfigureAddSolverWindow(parent=self)
+        if dialog_solver.exec_():
+            self.solver_table_model.add_solver(dialog_solver.data)
+
+    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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Dialog</class>
+ <widget class="QDialog" name="Dialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>741</width>
+    <height>289</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>10</y>
+     <width>721</width>
+     <height>271</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <item>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_2">
+        <property name="text">
+         <string>Name</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Type</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" colspan="2">
+       <layout class="QHBoxLayout" name="horizontalLayout_5">
+        <item>
+         <widget class="QComboBox" name="comboBox_solver"/>
+        </item>
+       </layout>
+      </item>
+      <item row="2" column="0" colspan="2">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Description</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1" colspan="2">
+       <widget class="QLineEdit" name="lineEdit_name"/>
+      </item>
+      <item row="2" column="2">
+       <widget class="QLineEdit" name="lineEdit_description"/>
+      </item>
+     </layout>
+    </item>
+    <item>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="5" column="0">
+       <widget class="QLabel" name="label_5">
+        <property name="text">
+         <string>Solver</string>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="1">
+       <layout class="QHBoxLayout" name="horizontalLayout_2">
+        <item>
+         <widget class="QLineEdit" name="lineEdit_solver"/>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_solver">
+          <property name="text">
+           <string/>
+          </property>
+          <property name="icon">
+           <iconset>
+            <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="5" column="2">
+       <widget class="QLineEdit" name="lineEdit_solver_cmd"/>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLabel" name="label_7">
+        <property name="text">
+         <string>Path</string>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="0">
+       <widget class="QLabel" name="label_6">
+        <property name="text">
+         <string>Output formater</string>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="2">
+       <widget class="QLineEdit" name="lineEdit_output_cmd"/>
+      </item>
+      <item row="0" column="2">
+       <widget class="QLabel" name="label_8">
+        <property name="text">
+         <string>Command line</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QLineEdit" name="lineEdit_input_cmd"/>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Input formater</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <widget class="QLineEdit" name="lineEdit_input"/>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_input">
+          <property name="text">
+           <string/>
+          </property>
+          <property name="icon">
+           <iconset>
+            <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item row="6" column="1">
+       <layout class="QHBoxLayout" name="horizontalLayout_3">
+        <item>
+         <widget class="QLineEdit" name="lineEdit_output"/>
+        </item>
+        <item>
+         <widget class="QPushButton" name="pushButton_output">
+          <property name="text">
+           <string/>
+          </property>
+          <property name="icon">
+           <iconset>
+            <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </item>
+    <item>
+     <widget class="QDialogButtonBox" name="buttonBox">
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
+      <property name="standardButtons">
+       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>Dialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>Dialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
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 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>770</width>
-    <height>351</height>
+    <width>658</width>
+    <height>381</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -17,306 +17,313 @@
    <property name="geometry">
     <rect>
      <x>10</x>
-     <y>20</y>
-     <width>751</width>
-     <height>321</height>
+     <y>10</y>
+     <width>641</width>
+     <height>361</height>
     </rect>
    </property>
-   <layout class="QVBoxLayout" name="verticalLayout_8">
+   <layout class="QVBoxLayout" name="verticalLayout">
     <item>
-     <layout class="QGridLayout" name="gridLayout">
-      <item row="0" column="0">
-       <widget class="QGroupBox" name="groupBox">
-        <property name="enabled">
-         <bool>true</bool>
+     <widget class="QTabWidget" name="tabWidget">
+      <property name="currentIndex">
+       <number>0</number>
+      </property>
+      <property name="documentMode">
+       <bool>false</bool>
+      </property>
+      <property name="tabsClosable">
+       <bool>false</bool>
+      </property>
+      <property name="movable">
+       <bool>false</bool>
+      </property>
+      <property name="tabBarAutoHide">
+       <bool>false</bool>
+      </property>
+      <widget class="QWidget" name="tab_solvers">
+       <attribute name="title">
+        <string>Solvers</string>
+       </attribute>
+       <widget class="QWidget" name="layoutWidget">
+        <property name="geometry">
+         <rect>
+          <x>10</x>
+          <y>10</y>
+          <width>611</width>
+          <height>271</height>
+         </rect>
         </property>
-        <property name="title">
-         <string>Executable</string>
+        <layout class="QVBoxLayout" name="verticalLayout_2">
+         <item>
+          <layout class="QHBoxLayout" name="horizontalLayout_2">
+           <item>
+            <widget class="QPushButton" name="pushButton_solver_add">
+             <property name="text">
+              <string/>
+             </property>
+             <property name="icon">
+              <iconset>
+               <normaloff>ressources/gtk_add.png</normaloff>ressources/gtk_add.png</iconset>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="pushButton_solver_del">
+             <property name="text">
+              <string/>
+             </property>
+             <property name="icon">
+              <iconset>
+               <normaloff>ressources/gtk-remove.png</normaloff>ressources/gtk-remove.png</iconset>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QPushButton" name="pushButton_solver_edit">
+             <property name="text">
+              <string/>
+             </property>
+             <property name="icon">
+              <iconset>
+               <normaloff>ressources/edit.png</normaloff>ressources/edit.png</iconset>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <spacer name="horizontalSpacer">
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>40</width>
+               <height>20</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </item>
+         <item>
+          <widget class="QTableView" name="tableView_solver">
+           <property name="minimumSize">
+            <size>
+             <width>0</width>
+             <height>156</height>
+            </size>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+      <widget class="QWidget" name="tab_mailleur">
+       <attribute name="title">
+        <string>Mailleur</string>
+       </attribute>
+       <widget class="QWidget" name="">
+        <property name="geometry">
+         <rect>
+          <x>10</x>
+          <y>10</y>
+          <width>621</width>
+          <height>30</height>
+         </rect>
         </property>
-        <widget class="QWidget" name="layoutWidget">
-         <property name="geometry">
-          <rect>
-           <x>10</x>
-           <y>20</y>
-           <width>351</width>
-           <height>111</height>
-          </rect>
-         </property>
-         <layout class="QHBoxLayout" name="horizontalLayout_2">
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout_4">
-            <item>
-             <widget class="QLabel" name="label_4">
-              <property name="text">
-               <string>MAGE</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_5">
-              <property name="text">
-               <string>MAGE_Extraire</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_6">
-              <property name="text">
-               <string>Mailleur</string>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </item>
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout_5">
-            <item>
-             <layout class="QHBoxLayout" name="horizontalLayout_6">
-              <item>
-               <widget class="QLineEdit" name="lineEdit_exec_mage"/>
-              </item>
-              <item>
-               <widget class="QPushButton" name="pushButton_exec_mage">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="icon">
-                 <iconset>
-                  <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <layout class="QHBoxLayout" name="horizontalLayout_8">
-              <item>
-               <widget class="QLineEdit" name="lineEdit_exec_mage_extract"/>
-              </item>
-              <item>
-               <widget class="QPushButton" name="pushButton_exec_mage_extract">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="icon">
-                 <iconset>
-                  <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <layout class="QHBoxLayout" name="horizontalLayout_7">
-              <item>
-               <widget class="QLineEdit" name="lineEdit_exec_mailleur"/>
-              </item>
-              <item>
-               <widget class="QPushButton" name="pushButton_exec_mailleur">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="icon">
-                 <iconset>
-                  <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-           </layout>
-          </item>
-         </layout>
-        </widget>
+        <layout class="QHBoxLayout" name="horizontalLayout_5">
+         <item>
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string>Mailleur path</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="lineEdit_mailleur"/>
+         </item>
+         <item>
+          <widget class="QPushButton" name="pushButton_mailleur">
+           <property name="text">
+            <string/>
+           </property>
+           <property name="icon">
+            <iconset>
+             <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
+           </property>
+          </widget>
+         </item>
+        </layout>
        </widget>
-      </item>
-      <item row="0" column="1" rowspan="2">
-       <widget class="QGroupBox" name="groupBox_3">
-        <property name="title">
-         <string>BackUp</string>
+      </widget>
+      <widget class="QWidget" name="tab_constant">
+       <attribute name="title">
+        <string>Constants</string>
+       </attribute>
+       <widget class="QWidget" name="layoutWidget_2">
+        <property name="geometry">
+         <rect>
+          <x>10</x>
+          <y>10</y>
+          <width>621</width>
+          <height>93</height>
+         </rect>
         </property>
-        <widget class="QWidget" name="">
-         <property name="geometry">
-          <rect>
-           <x>10</x>
-           <y>20</y>
-           <width>343</width>
-           <height>125</height>
-          </rect>
-         </property>
-         <layout class="QHBoxLayout" name="horizontalLayout_4">
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout_7">
-            <item>
-             <widget class="QLabel" name="label_7">
-              <property name="text">
-               <string>Sauvegarde automatique</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_8">
-              <property name="text">
-               <string>Chemin</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_9">
-              <property name="text">
-               <string>Frequence</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_10">
-              <property name="text">
-               <string>Max. archives</string>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </item>
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout_6">
-            <item>
-             <widget class="QCheckBox" name="checkBox_backup">
-              <property name="text">
-               <string>Activé</string>
-              </property>
-              <property name="tristate">
-               <bool>false</bool>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <layout class="QHBoxLayout" name="horizontalLayout_3">
-              <item>
-               <widget class="QLineEdit" name="lineEdit_backup_path"/>
-              </item>
-              <item>
-               <widget class="QPushButton" name="pushButton_backup_path">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="icon">
-                 <iconset>
-                  <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <widget class="QTimeEdit" name="timeEdit_backup_frequence">
-              <property name="minimumTime">
-               <time>
-                <hour>0</hour>
-                <minute>1</minute>
-                <second>0</second>
-               </time>
-              </property>
-              <property name="displayFormat">
-               <string>HH:mm:ss</string>
-              </property>
-              <property name="timeSpec">
-               <enum>Qt::LocalTime</enum>
-              </property>
-              <property name="time">
-               <time>
-                <hour>0</hour>
-                <minute>5</minute>
-                <second>0</second>
-               </time>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QSpinBox" name="spinBox_backup_max">
-              <property name="minimum">
-               <number>1</number>
-              </property>
-              <property name="value">
-               <number>10</number>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </item>
-         </layout>
-        </widget>
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_3">
+           <item>
+            <widget class="QLabel" name="label_2">
+             <property name="text">
+              <string>Nombre de segment</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLabel" name="label_3">
+             <property name="text">
+              <string>Taille max. du listing</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_4">
+           <item>
+            <widget class="QLineEdit" name="lineEdit_segment">
+             <property name="text">
+              <string>1000</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLineEdit" name="lineEdit_max_listing">
+             <property name="text">
+              <string>500000</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+        </layout>
        </widget>
-      </item>
-      <item row="1" column="0">
-       <widget class="QGroupBox" name="groupBox_2">
-        <property name="title">
-         <string>Constante numérique</string>
+      </widget>
+      <widget class="QWidget" name="tab">
+       <attribute name="title">
+        <string>Backup</string>
+       </attribute>
+       <widget class="QWidget" name="layoutWidget_3">
+        <property name="geometry">
+         <rect>
+          <x>10</x>
+          <y>10</y>
+          <width>611</width>
+          <height>125</height>
+         </rect>
         </property>
-        <widget class="QWidget" name="">
-         <property name="geometry">
-          <rect>
-           <x>10</x>
-           <y>30</y>
-           <width>268</width>
-           <height>93</height>
-          </rect>
-         </property>
-         <layout class="QHBoxLayout" name="horizontalLayout">
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout_3">
-            <item>
-             <widget class="QLabel" name="label">
-              <property name="text">
-               <string>Frottement</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_2">
-              <property name="text">
-               <string>Nombre de segment</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLabel" name="label_3">
-              <property name="text">
-               <string>Taille max. du listing</string>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </item>
-          <item>
-           <layout class="QVBoxLayout" name="verticalLayout">
-            <item>
-             <widget class="QCheckBox" name="checkBox_manning">
-              <property name="text">
-               <string>Manning</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLineEdit" name="lineEdit_segment">
-              <property name="text">
-               <string>1000</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QLineEdit" name="lineEdit_max_listing">
-              <property name="text">
-               <string>500000</string>
-              </property>
-             </widget>
-            </item>
-           </layout>
-          </item>
-         </layout>
-        </widget>
+        <layout class="QHBoxLayout" name="horizontalLayout_4">
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_7">
+           <item>
+            <widget class="QLabel" name="label_7">
+             <property name="text">
+              <string>Sauvegarde automatique</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLabel" name="label_8">
+             <property name="text">
+              <string>Chemin</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLabel" name="label_9">
+             <property name="text">
+              <string>Frequence</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QLabel" name="label_10">
+             <property name="text">
+              <string>Max. archives</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_6">
+           <item>
+            <widget class="QCheckBox" name="checkBox_backup">
+             <property name="text">
+              <string>Activé</string>
+             </property>
+             <property name="tristate">
+              <bool>false</bool>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_3">
+             <item>
+              <widget class="QLineEdit" name="lineEdit_backup_path"/>
+             </item>
+             <item>
+              <widget class="QPushButton" name="pushButton_backup_path">
+               <property name="text">
+                <string/>
+               </property>
+               <property name="icon">
+                <iconset>
+                 <normaloff>ressources/open.png</normaloff>ressources/open.png</iconset>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+           <item>
+            <widget class="QTimeEdit" name="timeEdit_backup_frequence">
+             <property name="minimumTime">
+              <time>
+               <hour>0</hour>
+               <minute>1</minute>
+               <second>0</second>
+              </time>
+             </property>
+             <property name="displayFormat">
+              <string>HH:mm:ss</string>
+             </property>
+             <property name="timeSpec">
+              <enum>Qt::LocalTime</enum>
+             </property>
+             <property name="time">
+              <time>
+               <hour>0</hour>
+               <minute>5</minute>
+               <second>0</second>
+              </time>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QSpinBox" name="spinBox_backup_max">
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="value">
+              <number>10</number>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </item>
+        </layout>
        </widget>
-      </item>
-     </layout>
+      </widget>
+     </widget>
     </item>
     <item>
      <widget class="QDialogButtonBox" name="buttonBox">
-- 
GitLab