""" """ from core import mncheck, checking import logging from qgis.core import QgsProject import sys from PyQt5 import QtWidgets from PyQt5 import uic from PyQt5.Qt import Qt from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtWidgets import QApplication, QTreeWidgetItem from core.checking import TestResult from core.constants import MAIN, RSCDIR, VERSION from ui.dlg_contact import DlgContact logger = logging.getLogger("mncheck") Ui_Main, _ = uic.loadUiType(MAIN / 'ui'/ 'dlg_main.ui') class QComlink(QObject): started_test = pyqtSignal(TestResult) ended_test = pyqtSignal(TestResult) def _started_test(self, test): self.started_test.emit(test) def _ended_test(self, test): self.ended_test.emit(test) class DlgMain(QtWidgets.QDialog): def __init__(self, iface, parent=None): super().__init__(parent) self.available_schemas = mncheck.list_schemas() self.iface = iface self.schema_lib = None self.user_conf = {} self.createWidgets() def createWidgets(self): """ set up the interface """ self.ui = Ui_Main() self.ui.setupUi(self) self.user_conf = mncheck.get_user_data() self.setWindowTitle(f"MnCheck v{VERSION}") self.setWindowIcon(QIcon(MAIN / "icon.png")) self.ui.btn_run.setIcon(QIcon(RSCDIR / "play.png")) self.ui.btn_run.clicked.connect(self.run) self.ui.btn_help.setIcon(QIcon(RSCDIR / "question.png")) self.ui.btn_help.clicked.connect(self.show_help) self.ui.btn_contact.clicked.connect(self.show_contact) for i, schema_name in enumerate(self.available_schemas): s = mncheck.get_schema(schema_name) try: self.ui.cbb_schemas.addItem(s.SCHEMA_NAME, i) except AttributeError: self.ui.cbb_schemas.addItem(schema_name, i) if 'current_schema' in self.user_conf and self.user_conf['current_schema'] == schema_name: self.ui.cbb_schemas.setCurrentIndex(i) self.ui.cbb_schemas.currentIndexChanged.connect(self.update_layers_list) self.ui.progress_bar.setVisible(False) self.ui.tree_report.setColumnWidth(0, 35) self.ui.tree_report.itemClicked.connect(self.tree_item_clicked) self.ui.tree_report.expanded.connect(self.tree_item_expanded) QgsProject.instance().layersAdded.connect(self.update_layers_list) QgsProject.instance().layersRemoved.connect(self.update_layers_list) self.update_layers_list() def tree_item_expanded(self, _): self.tree_auto_resize() def tree_auto_resize(self): self.ui.tree_report.resizeColumnToContents(1) self.ui.tree_report.resizeColumnToContents(2) self.ui.tree_report.setColumnWidth(1, self.ui.tree_report.columnWidth(1) + 20) self.ui.tree_report.setColumnWidth(2, self.ui.tree_report.columnWidth(2) + 20) def current_schema_name(self): return self.available_schemas[int(self.ui.cbb_schemas.itemData(self.ui.cbb_schemas.currentIndex()))] def init_progress_bar(self, value=0, minimum=0, maximum=100): self.ui.progress_bar.setMinimum(minimum) self.ui.progress_bar.setValue(value) self.ui.progress_bar.setMaximum(maximum) def test_started(self, test): logger.debug("* %s - start test", test.name) def test_ended(self, test): logger.debug("* %s - %s", test.name, test.status_str) if test.status == checking.ERROR: try: logger.debug("%s", "\n".join([e.info['exc_info'] for e in test.errors])) except KeyError: pass self.ui.progress_bar.setValue(self.ui.progress_bar.value() + 1) self.ui.progress_bar.update() def update_layers_list(self): schema_name = self.current_schema_name() logger.info("Selected schema: %s", schema_name) schema = mncheck.get_schema(schema_name) expected = [model.layername for model in schema.models] logger.info("Expected layers: %s", str(expected)) found = [layer.name().lower() for layer in QgsProject.instance().mapLayers().values()] logger.info("Found layers: %s", str(found)) self.ui.btn_run.setEnabled(True) self.ui.tree_report.clear() for layername in expected: item = QTreeWidgetItem() if layername.lower() in found: item.setIcon(0, QIcon(QPixmap(RSCDIR / "ok_16.png"))) item.setText(1, layername) else: item.setIcon(0, QIcon(QPixmap(RSCDIR / "error_16.png"))) item.setText(1, f"{layername}: La couche est introuvable") self.ui.btn_run.setEnabled(False) self.ui.tree_report.addTopLevelItem(item) self.tree_auto_resize() def run(self): QApplication.setOverrideCursor(Qt.WaitCursor) self.ui.tree_report.clear() try: schema_name = self.current_schema_name() schema = mncheck.get_schema(schema_name) if not schema: logger.error("Aucun schéma sélectionné - Opération annulée") return if not schema.checkers: logger.error("Aucun testeur trouvé dans le schéma") return for checker_cls in schema.checkers: logger.info(f"Execution du checker {checker_cls.__name__}") self._run(checker_cls) except: raise finally: self.tree_auto_resize() self.ui.progress_bar.setVisible(False) QApplication.restoreOverrideCursor() def _run(self, checker_cls): checker = checker_cls() checker.comlink = QComlink() checker.comlink.started_test.connect(self.test_started) checker.comlink.ended_test.connect(self.test_ended) self.ui.progress_bar.setVisible(True) self.init_progress_bar(maximum=len(checker.tests)) results = checker.run() for result in results: topitem = QTreeWidgetItem() if result.status == checking.SUCCESS: topitem.setIcon(0, QIcon(QPixmap(RSCDIR / "ok_16.png"))) topitem.setText(1, f"{result.title}") elif result.status == checking.FAILURE: topitem.setIcon(0, QIcon(QPixmap(RSCDIR / "error_16.png"))) topitem.setText(1, f"{result.title} ({len(result.errors)})") elif result.status == checking.ERROR: topitem.setIcon(0, QIcon(QPixmap(RSCDIR / "warning_16.png"))) topitem.setText(1, f"{result.title} [Erreur inconnue]") else: topitem.setText(1, f"{result.title} [Erreur: aucun résultat]") topitem.setToolTip(0, f"{result.status_str}") topitem.setToolTip(1, f"{result.description}\n[test: {result.name}]") self.ui.tree_report.addTopLevelItem(topitem) for err in result.errors: erritem = QTreeWidgetItem() msg = err.message erritem.setText(1, msg) if "exc_info" in err.info: erritem.setData(1, Qt.UserRole, err) elif "model" in err.info: data = err.info["model"] erritem.setText(2, f"{data.layername}".upper()) erritem.setData(1, Qt.UserRole, data) elif "item" in err.info: data = err.info["item"] erritem.setText(2, f"{data}") erritem.setData(1, Qt.UserRole, data) font = erritem.font(2) font.setItalic(True) erritem.setFont(2, font) topitem.addChild(erritem) def tree_item_clicked(self, item, _): data = item.data(1, Qt.UserRole) if not data: return elif hasattr(data, "_feature"): self.zoom_to_feature(data.layer, data._feature) elif hasattr(data, "layer"): self.select_layer(data.layer) def select_layer(self, layer): self.iface.setActiveLayer(layer) def zoom_to_feature(self, layer, feature): self.iface.setActiveLayer(layer) self.iface.mapCanvas().zoomToFeatureExtent(feature.geometry().boundingBox()) layer.removeSelection() layer.select(feature.id()) def show_contact(self): dlg = DlgContact() dlg.show() dlg.exec_() def show_help(self): pass def store_config(self): user_conf = mncheck.get_user_data() user_conf["current_schema"] = self.current_schema_name() mncheck.dump_user_data(user_conf) def closeEvent(self, event): self.store_config() super().closeEvent(event)