diff --git a/src/Checker/Checker.py b/src/Checker/Checker.py
index 92199b8d..6e87a601 100644
--- a/src/Checker/Checker.py
+++ b/src/Checker/Checker.py
@@ -26,6 +26,10 @@ class AbstractModelChecker(object):
def description(self):
return self._description
+ @property
+ def summary(self):
+ return self._summary
+
# Checker status
def is_unknown(self):
@@ -53,11 +57,3 @@ class AbstractModelChecker(object):
otherelse
"""
raise NotImplementedMethodeError(self, self.run)
-
- def summary(self):
- """Return summary message
-
- Returns:
- Return summary string
- """
- raise NotImplementedMethodeError(self, self.summary)
diff --git a/src/Checker/Study.py b/src/Checker/Study.py
new file mode 100644
index 00000000..d0b84f21
--- /dev/null
+++ b/src/Checker/Study.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+
+from PyQt5.QtCore import QCoreApplication
+
+from Checker.Checker import AbstractModelChecker, STATUS
+
+_translate = QCoreApplication.translate
+
+
+class StudyNetworkReachChecker(AbstractModelChecker):
+ def __init__(self):
+ super(StudyNetworkReachChecker, self).__init__()
+
+ self._name = _translate("Checker", "Study network reach checker")
+ self._description = _translate("Checker", "Check if exists at least one reach for study")
+
+ def run(self, study):
+ if study is None:
+ self._status = STATUS.ERROR
+ self._summary = "invalid_study"
+ return False
+
+ river = study.river
+ if river is None:
+ self._status = STATUS.ERROR
+ self._summary = "no_river_found"
+ return False
+
+ if len(river.edges()) == 0:
+ self._status = STATUS.ERROR
+ self._summary = "no_reach_defined"
+ return False
+
+ self._summary = "ok"
+ self._status = STATUS.OK
+ return True
diff --git a/src/Model/Study.py b/src/Model/Study.py
index 3ce31c43..5cc485c2 100644
--- a/src/Model/Study.py
+++ b/src/Model/Study.py
@@ -8,6 +8,7 @@ from Model.Serializable import Serializable
from Model.River import River
+from Checker.Study import *
class Study(Serializable):
def __init__(self):
@@ -31,6 +32,14 @@ class Study(Serializable):
# Study data
self._river = River(status = self.status)
+ @classmethod
+ def checkers(cls):
+ lst = [
+ StudyNetworkReachChecker(),
+ ]
+
+ return lst
+
@property
def river(self):
return self._river
diff --git a/src/Solver/ASolver.py b/src/Solver/ASolver.py
index 830d296e..ba1e511e 100644
--- a/src/Solver/ASolver.py
+++ b/src/Solver/ASolver.py
@@ -56,7 +56,7 @@ class AbstractSolver(object):
return lst
@classmethod
- def checker(cls):
+ def checkers(cls):
lst = [
]
diff --git a/src/View/CheckList/Table.py b/src/View/CheckList/Table.py
new file mode 100644
index 00000000..071b4907
--- /dev/null
+++ b/src/View/CheckList/Table.py
@@ -0,0 +1,76 @@
+# -*- coding: utf-8 -*-
+
+from tools import trace, timer
+
+from PyQt5.QtCore import (
+ Qt, QVariant, QAbstractTableModel,
+ QCoreApplication, QModelIndex, pyqtSlot,
+ QRect,
+)
+
+from PyQt5.QtGui import (
+ QColor, QBrush,
+)
+
+from PyQt5.QtWidgets import (
+ QDialogButtonBox, QPushButton, QLineEdit,
+ QFileDialog, QTableView, QAbstractItemView,
+ QUndoStack, QShortcut, QAction, QItemDelegate,
+ QComboBox,
+)
+
+_translate = QCoreApplication.translate
+
+
+class TableModel(QAbstractTableModel):
+ def __init__(self, data=None):
+ super(QAbstractTableModel, self).__init__()
+ self._headers = ["name", "status"]
+ self._data = data
+
+ def flags(self, index):
+ options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
+ return options
+
+ def rowCount(self, parent):
+ return len(self._data)
+
+ def columnCount(self, parent):
+ return len(self._headers)
+
+ def data(self, index, role):
+ row = index.row()
+ column = index.column()
+
+ if role == Qt.ForegroundRole:
+ if self._headers[column] == "status":
+ color = Qt.gray
+
+ if self._data[row].is_ok():
+ color = Qt.green
+ elif self._data[row].is_warning():
+ color = Qt.yellow
+ elif self._data[row].is_error():
+ color = Qt.red
+
+ return QBrush(color)
+ return QVariant()
+
+ if role != Qt.ItemDataRole.DisplayRole:
+ return QVariant()
+
+ if self._headers[column] == "name":
+ return self._data[row].name
+ if self._headers[column] == "status":
+ return self._data[row].summary
+
+ return QVariant()
+
+ def headerData(self, section, orientation, role):
+ if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
+ return self._headers[section]
+
+ return QVariant()
+
+ def update(self):
+ self.layoutChanged.emit()
diff --git a/src/View/CheckList/Window.py b/src/View/CheckList/Window.py
new file mode 100644
index 00000000..c83bda9e
--- /dev/null
+++ b/src/View/CheckList/Window.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+
+import time
+import threading
+
+from tools import trace, timer
+
+from View.ASubWindow import ASubMainWindow
+from View.ListedSubWindow import ListedSubWindow
+
+from PyQt5.QtGui import (
+ QKeySequence,
+)
+
+from PyQt5.QtCore import (
+ Qt, QVariant, QAbstractTableModel,
+ QCoreApplication, QModelIndex, pyqtSlot,
+ QRect,
+)
+
+from PyQt5.QtWidgets import (
+ QDialogButtonBox, QPushButton, QLineEdit,
+ QFileDialog, QTableView, QAbstractItemView,
+ QUndoStack, QShortcut, QAction, QItemDelegate,
+ QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
+ QProgressBar,
+)
+
+from View.CheckList.Table import TableModel
+
+_translate = QCoreApplication.translate
+
+def _run_checker_list(study, checker_list, parent):
+ parent.start_compute()
+ for checker in checker_list:
+ time.sleep(1)
+ checker.run(study)
+ parent.progress()
+ parent.end_compute()
+
+class CheckListWindow(ASubMainWindow, ListedSubWindow):
+ def __init__(self, title="Check list",
+ study=None, config=None,
+ solver=None, parent=None):
+ self._title = title + " - " + study.name
+
+ self._study = study
+ self._config = config
+ self._solver = solver
+
+ super(CheckListWindow, self).__init__(
+ name=self._title, ui="CheckList", parent=parent
+ )
+ self.ui.setWindowTitle(self._title)
+
+ self._checker_list = (
+ self._study.checkers() + self._solver.checkers()
+ )
+
+ self.setup_table()
+ self.setup_progress_bar()
+ self.setup_connections()
+ self.setup_thread()
+
+ def setup_table(self):
+ table = self.find(QTableView, f"tableView")
+
+ self._table = TableModel(
+ data = self._checker_list,
+ )
+
+ table.setModel(self._table)
+ table.setSelectionBehavior(QAbstractItemView.SelectRows)
+ table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
+ table.setAlternatingRowColors(True)
+
+ def setup_progress_bar(self):
+ self._progress = self.find(QProgressBar, f"progressBar")
+ self._p = 0 # Progress current step
+
+ self._progress.setRange(0, len(self._checker_list))
+ self._progress.setValue(self._p)
+
+ def setup_connections(self):
+ self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
+ self.find(QPushButton, "pushButton_retry").clicked.connect(self.retry)
+ self.find(QPushButton, "pushButton_cancel").clicked.connect(self.reject)
+
+ def setup_thread(self):
+ self._t1 = threading.Thread(
+ target=_run_checker_list,
+ args=(self._study, self._checker_list, self,)
+ )
+ self._t1.start()
+
+ def progress(self):
+ self._p += 1
+ self._progress.setValue(self._p)
+ # self._table.update()
+
+ def start_compute(self):
+ self._p = 0
+ self._progress.setValue(self._p)
+
+ def end_compute(self):
+ self._table.layoutChanged.emit()
+ self.find(QPushButton, "pushButton_retry").setEnabled(True)
+
+ errors = list(filter(lambda c: c.is_error(), self._checker_list))
+ if len(errors) == 0:
+ self.find(QPushButton, "pushButton_ok").setEnabled(True)
+
+ def end(self):
+ # self._t1.join()
+ self.close()
+
+ def retry(self):
+ self._t1.join()
+ self._t1 = threading.Thread(
+ target=_run_checker_list,
+ args=(self._study, self._checker_list, self,)
+ )
+
+ self.find(QPushButton, "pushButton_retry").setEnabled(False)
+ self.find(QPushButton, "pushButton_ok").setEnabled(False)
+
+ self._t1.start()
+
+ def reject(self):
+ print("cancel")
+ self.end()
+
+ def accept(self):
+ print("ok")
+ self.end()
diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py
index bc79d2fb..b7cfa96e 100644
--- a/src/View/MainWindow.py
+++ b/src/View/MainWindow.py
@@ -29,6 +29,7 @@ from View.Stricklers.Window import StricklersWindow
from View.Sections.Window import SectionsWindow
from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow
+from View.CheckList.Window import CheckListWindow
from Model.Study import Study
@@ -382,6 +383,13 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
)
if run.exec():
solver = run.solver
+ check = CheckListWindow(
+ study = self.model,
+ config = self.conf,
+ solver = solver,
+ parent = self
+ )
+ check.show()
# TODO: Delete me !
###############
diff --git a/src/View/ui/CheckList.ui b/src/View/ui/CheckList.ui
index 79589e5e..06e6403c 100644
--- a/src/View/ui/CheckList.ui
+++ b/src/View/ui/CheckList.ui
@@ -16,7 +16,7 @@
-
-
+
-
@@ -26,31 +26,52 @@
-
-
-
- false
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Retry
-
-
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Cancel
+
+
+
+ -
+
+
+ false
+
+
+ Retry
+
+
+
+ -
+
+
+ false
+
+
+ Ok
+
+
+
+
-
-
- toolBar
-
-
- TopToolBarArea
-
-
- false
-
-
-
-