From fd0823f2bba5467a3e8f9b90076b052395737a40 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 14:20:03 +0100 Subject: [PATCH 1/9] recognize if we find a metaconfig-id in the corrent database - if so, we provide it to the gui. we can disable the metaconfig from the database and select another project topping from the usabilityhub or from the local system. when a topping is selected we disable the optimize strategy. --- .../workflow_wizard/project_creation_page.py | 460 ++++++++++++++---- .../ui/workflow_wizard/project_creation.ui | 207 +++++--- 2 files changed, 497 insertions(+), 170 deletions(-) diff --git a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py index dd4a7039a..cea3b14af 100644 --- a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py +++ b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py @@ -17,28 +17,43 @@ ***************************************************************************/ """ +import configparser import os +import re import yaml -from qgis.core import QgsProject +from qgis.core import Qgis, QgsProject from qgis.PyQt.QtCore import Qt -from qgis.PyQt.QtWidgets import QWizardPage +from qgis.PyQt.QtWidgets import QCompleter, QWizardPage +import QgisModelBaker.libs.modelbaker.utils.db_utils as db_utils from QgisModelBaker.libs.modelbaker.dataobjects.project import Project from QgisModelBaker.libs.modelbaker.db_factory.db_simple_factory import DbSimpleFactory from QgisModelBaker.libs.modelbaker.dbconnector.db_connector import DBConnectorError from QgisModelBaker.libs.modelbaker.generator.generator import Generator from QgisModelBaker.libs.modelbaker.iliwrapper.globals import DbIliMode -from QgisModelBaker.libs.modelbaker.iliwrapper.ilicache import IliToppingFileItemModel +from QgisModelBaker.libs.modelbaker.iliwrapper.ilicache import ( + IliDataCache, + IliDataFileCompleterDelegate, + IliDataItemModel, + IliToppingFileItemModel, +) from QgisModelBaker.libs.modelbaker.utils.globals import OptimizeStrategy +from QgisModelBaker.libs.modelbaker.utils.qt_utils import ( + FileValidator, + make_file_selector, +) from QgisModelBaker.utils import gui_utils from QgisModelBaker.utils.globals import CATALOGUE_DATASETNAME -from QgisModelBaker.utils.gui_utils import LogColor +from QgisModelBaker.utils.gui_utils import TRANSFERFILE_MODELS_BLACKLIST, LogColor PAGE_UI = gui_utils.get_ui_class("workflow_wizard/project_creation.ui") class ProjectCreationPage(QWizardPage, PAGE_UI): + + ValidExtensions = ["YAML", "yaml"] + def __init__(self, parent, title): QWizardPage.__init__(self, parent) @@ -48,6 +63,12 @@ def __init__(self, parent, title): self.setTitle(title) self.setStyleSheet(gui_utils.DEFAULT_STYLE) + self.db_simple_factory = DbSimpleFactory() + self.configuration = None + + self.existing_projecttopping_id = None + self.projecttopping_id = None + self.optimize_combo.clear() self.optimize_combo.addItem( self.tr("Hide unused base class layers"), OptimizeStrategy.HIDE @@ -57,13 +78,32 @@ def __init__(self, parent, title): ) self.optimize_combo.addItem(self.tr("No optimization"), OptimizeStrategy.NONE) - self.db_simple_factory = DbSimpleFactory() - self.configuration = None - self.create_project_button.clicked.connect(self._create_project) - self.is_complete = False + self.existing_topping_checkbox.setVisible(False) + self.existing_topping_checkbox.stateChanged.connect(self._use_existing) + + self.ilitoppingcache = IliDataCache(None) + self.ilitopping_delegate = IliDataFileCompleterDelegate() + self.topping_line_edit.setPlaceholderText( + self.tr("[Search project toppings on the repositories or the local system]") + ) + self.topping_line_edit.textChanged.connect(self._complete_completer) + self.topping_line_edit.punched.connect(self._complete_completer) + self.topping_line_edit.textChanged.emit(self.topping_line_edit.text()) + self.topping_line_edit.textChanged.connect(self._on_completer_activated) + self.topping_file_browse_button.clicked.connect( + make_file_selector( + self.topping_line_edit, + title=self.tr("Project Topping"), + file_filter=self.tr("Project Topping File (*.yaml *.YAML)"), + ) + ) + self.fileValidator = FileValidator( + pattern=["*." + ext for ext in self.ValidExtensions], allow_empty=False + ) + def isComplete(self): return self.is_complete @@ -73,7 +113,240 @@ def setComplete(self, complete): self.completeChanged.emit() def restore_configuration(self, configuration): + self.setEnabled(False) self.configuration = configuration + self.db_connector = db_utils.get_db_connector(self.configuration) + + # get existing topping + self.existing_topping_checkbox.setVisible(False) + self.existing_projecttopping_id = self._existing_projecttopping_id() + if self.existing_projecttopping_id: + self.tr("Use existing project topping {}").format(self.projecttopping_id) + self.existing_topping_checkbox.setVisible(True) + self.existing_topping_checkbox.setChecked(True) + else: + self._use_existing(False) + self.setEnabled(True) + + def _use_existing(self, state): + # triggered by checked state... + if state: + self._clean_topping() + self.topping_line_edit.setText("") + self._enable_topping_selection(False) + self._enable_optimize_combo(False) + self.projecttopping_id = self.existing_projecttopping_id + self._set_topping_info(True) + else: + self._clean_topping() + models = ";".join(self._modelnames()) + self.ilitoppingcache = IliDataCache( + self.configuration.base_configuration, "projecttopping", models + ) + self.ilitoppingcache.new_message.connect( + self.workflow_wizard.log_panel.show_message + ) + # wait before activating untill end of refreshment + self.ilitoppingcache.model_refreshed.connect( + lambda: self._enable_topping_selection(True) + ) + self._enable_optimize_combo(True) + self.ilitoppingcache.refresh() + + completer = QCompleter( + self.ilitoppingcache.sorted_model, + self.topping_line_edit, + ) + completer.setCaseSensitivity(Qt.CaseInsensitive) + completer.setModelSorting( + QCompleter.ModelSorting.CaseInsensitivelySortedModel + ) + completer.setFilterMode(Qt.MatchContains) + completer.popup().setItemDelegate(self.ilitopping_delegate) + self.topping_line_edit.setCompleter(completer) + self._enable_optimize_combo(True) + + def _enable_topping_selection(self, state): + # doublecheck if meanwhile user checked box again + if state: + state = state and not self.existing_topping_checkbox.isChecked() + self.topping_file_browse_button.setEnabled(state) + self.topping_line_edit.setEnabled(state) + self.topping_line_label.setEnabled(state) + self.topping_info.setEnabled(state) + + def _enable_optimize_combo(self, state): + self.optimize_combo.setEnabled(state) + self.optimize_label.setEnabled(state) + + def _datasource_metaconfig(self): + metaconfig_id = None + setting_records = self.db_connector.get_ili2db_settings() + for setting_record in setting_records: + if setting_record["tag"] == "ch.ehi.ili2db.metaConfigFileName": + metaconfig_id = setting_record["setting"] + break + if metaconfig_id: + metaconfig_file_path_list = self.workflow_wizard.get_topping_file_list( + [metaconfig_id] + ) + + if not metaconfig_file_path_list: + self.workflow_wizard.log_panel.print_info( + self.tr( + "Found a metaconfig-id ({}) in the data source, but no corresponding metaconfig in the repositories." + ).format(metaconfig_id), + LogColor.COLOR_TOPPING, + ) + return None + + metaconfig = configparser.ConfigParser() + with open(metaconfig_file_path_list[0]) as metaconfig_file: + metaconfig.read_file(metaconfig_file) + return metaconfig + + return None + + def _existing_projecttopping_id(self): + metaconfig = self.configuration.metaconfig + + if not metaconfig: + metaconfig = self._datasource_metaconfig() + + if not metaconfig: + # no existing metaconfig available + return None + + # get projecttopping_id from metaconfig + if "CONFIGURATION" in metaconfig.sections(): + configuration_section = metaconfig["CONFIGURATION"] + # get topping referenced in qgis.modelbaker.projecttopping + key = "qgis.modelbaker.projecttopping" + if key not in configuration_section: + key = "qgis.modelbaker.layertree" + self.workflow_wizard.log_panel.print_info( + self.tr( + 'Keyword "qgis.modelbaker.layertree" is deprecated (but still working). Use "qgis.modelbaker.projecttopping" instead.' + ), + LogColor.COLOR_TOPPING, + ) + + if key in configuration_section: + self.workflow_wizard.log_panel.print_info( + self.tr("Metaconfig contains a project topping."), + LogColor.COLOR_TOPPING, + ) + projecttopping_id_list = configuration_section[key].split(";") + if len(projecttopping_id_list) > 1: + self.workflow_wizard.log_panel.print_info( + self.tr( + "Only one projectopping allowed. Taking first one of the list." + ), + LogColor.COLOR_TOPPING, + ) + return projecttopping_id_list[0] + return None + + def _complete_completer(self): + if self.topping_line_edit.hasFocus() and self.topping_line_edit.completer(): + if not self.topping_line_edit.text(): + self.topping_line_edit.completer().setCompletionMode( + QCompleter.UnfilteredPopupCompletion + ) + self.topping_line_edit.completer().complete() + else: + match_contains = ( + self.topping_line_edit.completer() + .completionModel() + .match( + self.topping_line_edit.completer() + .completionModel() + .index(0, 0), + Qt.DisplayRole, + self.topping_line_edit.text(), + -1, + Qt.MatchContains, + ) + ) + if len(match_contains) > 1: + self.topping_line_edit.completer().setCompletionMode( + QCompleter.PopupCompletion + ) + self.topping_line_edit.completer().complete() + self.topping_line_edit.completer().popup().scrollToTop() + + def _on_completer_activated(self, text=None): + self._clean_topping() + if os.path.isfile(self.topping_line_edit.text()): + self.projecttopping_id = self.topping_line_edit.text() + self._set_topping_info(True) + self._enable_optimize_combo(False) + return + + matches = self.ilitoppingcache.model.match( + self.ilitoppingcache.model.index(0, 0), + Qt.DisplayRole, + self.topping_line_edit.text(), + 1, + Qt.MatchExactly, + ) + if matches: + model_index = matches[0] + self.projecttopping_id = f"ilidata:{self.ilitoppingcache.model.data(model_index, int(IliDataItemModel.Roles.ID))}" + self._set_topping_info(True, model_index) + self._enable_optimize_combo(False) + return + + self._set_topping_info(not self.topping_line_edit.text()) + self._enable_optimize_combo(True) + + def _clean_topping(self): + self.projecttopping_id = None + self.topping_info.setText("") + + def _set_topping_info(self, valid, index=None): + if self.projecttopping_id: + if index: + self.topping_info.setText( + self.tr( + "

Current project topping is: {} ({})
{}

" + ).format( + self.ilitoppingcache.model.data(index, Qt.DisplayRole), + self.projecttopping_id, + self.ilitoppingcache.model.data( + index, int(IliDataItemModel.Roles.SHORT_DESCRIPTION) or "" + ), + ) + ) + else: + self.topping_info.setText( + self.tr( + "

Current project topping is: {}

" + ).format(self.projecttopping_id) + ) + + self.topping_info.setStyleSheet(f"color: {LogColor.COLOR_TOPPING}") + + self.topping_line_edit.setStyleSheet( + "QLineEdit {{ background-color: {} }}".format( + "#ffffff" if valid else "#ffd356" + ) + ) + + def _modelnames(self): + modelnames = [] + db_models = self.db_connector.get_models() + regex = re.compile(r"(?:\{[^\}]*\}|\s)") + for db_model in db_models: + for modelname in regex.split(db_model["modelname"]): + name = modelname.strip() + if ( + name + and name not in TRANSFERFILE_MODELS_BLACKLIST + and name not in modelnames + ): + modelnames.append(name) + return modelnames def _create_project(self): self.progress_bar.setValue(0) @@ -167,117 +440,92 @@ def _create_project(self): mapthemes = {} resolved_layouts = {} custom_variables = {} + transaction_mode = None - # Project topping file for legend and layers: collect and download - projecttopping_file_path_list = [] - if ( - self.configuration.metaconfig - and "CONFIGURATION" in self.configuration.metaconfig.sections() - ): - configuration_section = self.configuration.metaconfig["CONFIGURATION"] - # get topping referenced in qgis.modelbaker.projecttopping - key = "qgis.modelbaker.projecttopping" - if key not in configuration_section: - key = "qgis.modelbaker.layertree" - self.workflow_wizard.log_panel.print_info( - self.tr( - 'Keyword "qgis.modelbaker.layertree" is deprecated (but still working). Use "qgis.modelbaker.projecttopping" instead.' - ), - LogColor.COLOR_TOPPING, - ) + if self.projecttopping_id: + # Project topping file for legend and layers: collect and download + projecttopping_file_path = self.ilidata_path_resolver( + "", self.projecttopping_id + ) - if key in configuration_section: + if projecttopping_file_path: self.workflow_wizard.log_panel.print_info( - self.tr("Metaconfig contains a project topping."), + self.tr("Parse project topping file {}…").format( + projecttopping_file_path + ), LogColor.COLOR_TOPPING, ) - projecttopping_data_list = configuration_section[key].split(";") - projecttopping_file_path_list = ( - self.workflow_wizard.get_topping_file_list(projecttopping_data_list) - ) - - if len(projecttopping_file_path_list) > 1: - self.workflow_wizard.log_panel.print_info( - self.tr( - "Multiple project toppings can lead to unexpected behavior, when the sections are not clearly separated." - ), - LogColor.COLOR_TOPPING, - ) - - for projecttopping_file_path in projecttopping_file_path_list: - self.workflow_wizard.log_panel.print_info( - self.tr("Parse project topping file {}…").format( - projecttopping_file_path - ), - LogColor.COLOR_TOPPING, - ) - with open(projecttopping_file_path) as stream: - try: - projecttopping_data = yaml.safe_load(stream) - - # layertree / legend - layertree_key = "layertree" - if layertree_key not in projecttopping_data: - layertree_key = "legend" - self.workflow_wizard.log_panel.print_info( - self.tr( - 'Keyword "legend" is deprecated (but still working).. Use "layertree" instead.' - ), - LogColor.COLOR_TOPPING, - ) - if layertree_key in projecttopping_data: - legend = generator.legend( - available_layers, - layertree_structure=projecttopping_data[layertree_key], - path_resolver=lambda path: self.ilidata_path_resolver( - os.path.dirname(projecttopping_file_path), path + with open(projecttopping_file_path) as stream: + try: + projecttopping_data = yaml.safe_load(stream) + + # layertree / legend + layertree_key = "layertree" + if layertree_key not in projecttopping_data: + layertree_key = "legend" + self.workflow_wizard.log_panel.print_info( + self.tr( + 'Keyword "legend" is deprecated (but still working).. Use "layertree" instead.' + ), + LogColor.COLOR_TOPPING, + ) + if layertree_key in projecttopping_data: + legend = generator.legend( + available_layers, + layertree_structure=projecttopping_data[layertree_key], + path_resolver=lambda path: self.ilidata_path_resolver( + os.path.dirname(projecttopping_file_path), path + ) + if path + else None, ) - if path - else None, - ) - # layer order - layerorder_key = "layerorder" - if layerorder_key not in projecttopping_data: - layerorder_key = "layer-order" - - if layerorder_key in projecttopping_data: - custom_layer_order_structure = projecttopping_data[ - layerorder_key - ] - - # map themes - if "mapthemes" in projecttopping_data: - mapthemes = projecttopping_data["mapthemes"] - - # layouts - if "layouts" in projecttopping_data: - resolved_layouts = generator.resolved_layouts( - projecttopping_data["layouts"], - path_resolver=lambda path: self.ilidata_path_resolver( - os.path.dirname(projecttopping_file_path), path + # layer order + layerorder_key = "layerorder" + if layerorder_key not in projecttopping_data: + layerorder_key = "layer-order" + + if layerorder_key in projecttopping_data: + custom_layer_order_structure = projecttopping_data[ + layerorder_key + ] + + # map themes + if "mapthemes" in projecttopping_data: + mapthemes = projecttopping_data["mapthemes"] + + # layouts + if "layouts" in projecttopping_data: + resolved_layouts = generator.resolved_layouts( + projecttopping_data["layouts"], + path_resolver=lambda path: self.ilidata_path_resolver( + os.path.dirname(projecttopping_file_path), path + ) + if path + else None, ) - if path - else None, - ) - # variables - if "variables" in projecttopping_data: - custom_variables = projecttopping_data["variables"] + # variables + if "variables" in projecttopping_data: + custom_variables = projecttopping_data["variables"] - # properties (inoffical) - if "properties" in projecttopping_data: - custom_project_properties = projecttopping_data["properties"] + # properties (inoffical) + if "properties" in projecttopping_data: + custom_project_properties = projecttopping_data[ + "properties" + ] - except yaml.YAMLError as exc: - self.workflow_wizard.log_panel.print_info( - self.tr("Unable to parse project topping: {}").format(exc), - LogColor.COLOR_TOPPING, - ) + except yaml.YAMLError as exc: + self.workflow_wizard.log_panel.print_info( + self.tr("Unable to parse project topping: {}").format(exc), + LogColor.COLOR_TOPPING, + ) - self.progress_bar.setValue(55) + self.progress_bar.setValue(55) - transaction_mode = custom_project_properties.get("transaction_mode", None) + transaction_mode = custom_project_properties.get( + "transaction_mode", None + ) if Qgis.QGIS_VERSION_INT < 32600: # pass transaction_mode as boolean diff --git a/QgisModelBaker/ui/workflow_wizard/project_creation.ui b/QgisModelBaker/ui/workflow_wizard/project_creation.ui index 5e0c435d7..d93d27753 100644 --- a/QgisModelBaker/ui/workflow_wizard/project_creation.ui +++ b/QgisModelBaker/ui/workflow_wizard/project_creation.ui @@ -14,61 +14,79 @@ Select Files - - + + - Qt::Vertical + Qt::Horizontal - 20 - 40 + 40 + 20 - - - - - 0 - 0 - - - - <html><head/><body><p><span style=" font-weight:600;">Hide unused base class layers:</span></p><p>- Base class layers with same named extensions will be <span style=" font-style:italic;">hidden</span> and and base class layers with multiple extensions as well. Except if the extension is in the same model, then it's will <span style=" font-style:italic;">not</span> be <span style=" font-style:italic;">hidden</span> but <span style=" font-style:italic;">renamed</span>.</p><p>- Relations of hidden layers will <span style=" font-style:italic;">not</span> be <span style=" font-style:italic;">created</span> and with them <span style=" font-style:italic;">no</span> widgets<br/></p><p><span style=" font-weight:600;">Group unused base class layers:</span></p><p>- Base class layers with same named extensions will be <span style=" font-style:italic;">collected in a group</span> and base class layers with multiple extensions as well. Except if the extension is in the same model, then it's will <span style=" font-style:italic;">not</span> be <span style=" font-style:italic;">grouped</span> but <span style=" font-style:italic;">renamed</span>.</p><p>- Relations of grouped layers will be <span style=" font-style:italic;">created</span> but the widgets <span style=" font-style:italic;">not applied</span> to the form.</p></body></html> - - - - Hide unused base class layers - - - - - Group unused base class layers - - - - - No optimization - - - - - - - - - 0 - 0 - - - - <html><head/><body><p>If you don't get it - nevermind and keep the default. If it's not like expected - try again with 'No optimization'...</p></body></html> - - - Project optimization strategy concerning inheritances - + + + + + + + false + + + + + + + 0 + 0 + + + + Project Topping + + + + + + + + 0 + 0 + + + + + + + + Use existing project topping + + + + + + + Browse Interlis files + + + + + + + + + + TextLabel + + + true + + + + @@ -96,35 +114,96 @@ - - - - Qt::Horizontal - - - - 40 - 20 - + + + + 0 - + + + + + + + + + + + + + 0 + 0 + + + + <html><head/><body><p>If you don't get it - nevermind and keep the default. If it's not like expected - try again with 'No optimization'...</p></body></html> + + + Project optimization strategy concerning inheritances + + + + + + + + 0 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Hide unused base class layers:</span></p><p>- Base class layers with same named extensions will be <span style=" font-style:italic;">hidden</span> and and base class layers with multiple extensions as well. Except if the extension is in the same model, then it's will <span style=" font-style:italic;">not</span> be <span style=" font-style:italic;">hidden</span> but <span style=" font-style:italic;">renamed</span>.</p><p>- Relations of hidden layers will <span style=" font-style:italic;">not</span> be <span style=" font-style:italic;">created</span> and with them <span style=" font-style:italic;">no</span> widgets<br/></p><p><span style=" font-weight:600;">Group unused base class layers:</span></p><p>- Base class layers with same named extensions will be <span style=" font-style:italic;">collected in a group</span> and base class layers with multiple extensions as well. Except if the extension is in the same model, then it's will <span style=" font-style:italic;">not</span> be <span style=" font-style:italic;">grouped</span> but <span style=" font-style:italic;">renamed</span>.</p><p>- Relations of grouped layers will be <span style=" font-style:italic;">created</span> but the widgets <span style=" font-style:italic;">not applied</span> to the form.</p></body></html> + + + + Hide unused base class layers + + + + + Group unused base class layers + + + + + No optimization + + + + + + - + Generate - - - - 0 + + + + Qt::Vertical - + + + 20 + 40 + + + + + + CompletionLineEdit + +
QgisModelBaker.utils.gui_utils
+ 1 +
+
From 8b6c9689f42fba881738fc231ee292fc216a4189 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 14:20:36 +0100 Subject: [PATCH 2/9] keep it disabled when searching for reference data --- .../gui/workflow_wizard/default_baskets_page.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py b/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py index 981cb5beb..1acfcb081 100644 --- a/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py +++ b/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py @@ -52,9 +52,6 @@ def isComplete(self): def setComplete(self, complete): self.is_complete = complete - self.create_default_baskets_button.setDisabled(complete) - self.skip_button.setDisabled(complete) - self.baskets_panel.setDisabled(complete) self.completeChanged.emit() def nextId(self): @@ -88,6 +85,9 @@ def _create_default_baskets(self): self.progress_bar.setFormat(self.tr("Default baskets created!")) self.progress_bar.setValue(100) self.setStyleSheet(gui_utils.SUCCESS_STYLE) + self.create_default_baskets_button.setDisabled(True) + self.skip_button.setDisabled(True) + self.baskets_panel.setDisabled(True) self.setComplete(True) else: self.workflow_wizard.log_panel.print_info(message) @@ -103,4 +103,7 @@ def _skip(self): self.progress_bar.setFormat(self.tr("SKIPPED")) self.progress_bar.setTextVisible(True) self.setStyleSheet(gui_utils.INACTIVE_STYLE) + self.create_default_baskets_button.setDisabled(True) + self.skip_button.setDisabled(True) + self.baskets_panel.setDisabled(True) self.setComplete(True) From 451eb172de1d554bcc52580b33c6db856f1011f4 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 16:28:52 +0100 Subject: [PATCH 3/9] finetuning on project create and prototype of progress bar when loading 'something' kind of a busy indicator --- QgisModelBaker/gui/panel/log_panel.py | 10 +++- .../gui/workflow_wizard/execution_page.py | 7 +++ .../import_schema_configuration_page.py | 17 +++++- .../workflow_wizard/project_creation_page.py | 52 ++++++++++++++----- .../gui/workflow_wizard/workflow_wizard.py | 27 +++++++++- .../ui/workflow_wizard/project_creation.ui | 29 ++++++----- 6 files changed, 113 insertions(+), 29 deletions(-) diff --git a/QgisModelBaker/gui/panel/log_panel.py b/QgisModelBaker/gui/panel/log_panel.py index 2e29757f8..bad6b0070 100644 --- a/QgisModelBaker/gui/panel/log_panel.py +++ b/QgisModelBaker/gui/panel/log_panel.py @@ -19,7 +19,7 @@ import logging -from PyQt5.QtWidgets import QGridLayout +from PyQt5.QtWidgets import QGridLayout, QProgressBar from qgis.core import Qgis from qgis.gui import QgsMessageBar from qgis.PyQt.QtCore import QSize, Qt @@ -40,9 +40,17 @@ def __init__(self, parent=None): self.txtStdout.setLayout(QGridLayout()) self.txtStdout.layout().setContentsMargins(0, 0, 0, 0) self.txtStdout.layout().addWidget(self.bar, 0, 0, Qt.AlignTop) + self.scrollbar = self.txtStdout.verticalScrollBar() + + self.busy_bar = QProgressBar() + self.busy_bar.setRange(0, 0) + self.busy_bar.setTextVisible(True) + self.busy_bar.setVisible(False) layout = QGridLayout() layout.addWidget(self.txtStdout) + layout.addWidget(self.busy_bar) + self.setLayout(layout) def sizeHint(self): diff --git a/QgisModelBaker/gui/workflow_wizard/execution_page.py b/QgisModelBaker/gui/workflow_wizard/execution_page.py index f184f92ac..2b5a5eddf 100644 --- a/QgisModelBaker/gui/workflow_wizard/execution_page.py +++ b/QgisModelBaker/gui/workflow_wizard/execution_page.py @@ -195,3 +195,10 @@ def _on_process_finished(self, exit_code, result): message = self.tr("Finished with errors!") self.workflow_wizard.log_panel.print_info(message, color) + + def busy(self, busy, text=None): + self.setEnabled(not busy) + if busy: + self.workflow_wizard.start_busy_bar(text) + else: + self.workflow_wizard.stop_busy_bar() diff --git a/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py b/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py index 8d0eb1a43..956ff3b6c 100644 --- a/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py +++ b/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py @@ -185,6 +185,7 @@ def _update_ilimetaconfigcache(self): self.ilimetaconfigcache.model_refreshed.connect( self._update_metaconfig_completer ) + self.busy(True, self.tr("Refresh repository data...")) self._refresh_ili_metaconfig_cache() def _update_ilireferencedatacache(self): @@ -289,6 +290,7 @@ def _update_metaconfig_completer(self, rows): completer.popup().setItemDelegate(self.metaconfig_delegate) self.ili_metaconfig_line_edit.setCompleter(completer) self.ili_metaconfig_line_edit.setEnabled(bool(rows)) + self.busy(False) def _on_metaconfig_completer_activated(self, text=None): self._clean_metaconfig() @@ -315,8 +317,9 @@ def _on_metaconfig_completer_activated(self, text=None): self.ilimetaconfigcache.model.data(model_index, Qt.DisplayRole), metaconfig_id, self.ilimetaconfigcache.model.data( - model_index, int(IliDataItemModel.Roles.SHORT_DESCRIPTION) or "" - ), + model_index, int(IliDataItemModel.Roles.SHORT_DESCRIPTION) + ) + or "", ) ) self.metaconfig_file_info_label.setStyleSheet("color: #341d5c") @@ -433,6 +436,7 @@ def _load_crs_from_metaconfig(self, ili2db_metaconfig): self._crs_changed() def _load_metaconfig(self): + self.busy(True, "Load metaconfiguration...") # load ili2db parameters to the GUI if "ch.ehi.ili2db" in self.metaconfig.sections(): self.workflow_wizard.log_panel.print_info( @@ -570,3 +574,12 @@ def _load_metaconfig(self): LogColor.COLOR_TOPPING, ) self.workflow_wizard.refresh_import_models() + + self.busy(False) + + def busy(self, busy, text=None): + self.setEnabled(not busy) + if busy: + self.workflow_wizard.start_busy_bar(text) + else: + self.workflow_wizard.stop_busy_bar() diff --git a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py index cea3b14af..dba76e769 100644 --- a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py +++ b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py @@ -113,7 +113,10 @@ def setComplete(self, complete): self.completeChanged.emit() def restore_configuration(self, configuration): - self.setEnabled(False) + self.busy( + True, + self.tr("Restoring configuration and check existing metaconfigfile..."), + ) self.configuration = configuration self.db_connector = db_utils.get_db_connector(self.configuration) @@ -126,7 +129,7 @@ def restore_configuration(self, configuration): self.existing_topping_checkbox.setChecked(True) else: self._use_existing(False) - self.setEnabled(True) + self.busy(False) def _use_existing(self, state): # triggered by checked state... @@ -139,14 +142,26 @@ def _use_existing(self, state): self._set_topping_info(True) else: self._clean_topping() - models = ";".join(self._modelnames()) self.ilitoppingcache = IliDataCache( - self.configuration.base_configuration, "projecttopping", models + self.configuration.base_configuration, + type="projecttopping", + models=";".join(self._modelnames()), + datasources=["pg"] + if ( + self.workflow_wizard.import_schema_configuration.tool & DbIliMode.pg + ) + else ["gpkg"] + if ( + self.workflow_wizard.import_schema_configuration.tool + & DbIliMode.gpkg + ) + else None, ) self.ilitoppingcache.new_message.connect( self.workflow_wizard.log_panel.show_message ) - # wait before activating untill end of refreshment + # wait before activating until end of refreshment + self.busy(True, self.tr("Refresh repository data...")) self.ilitoppingcache.model_refreshed.connect( lambda: self._enable_topping_selection(True) ) @@ -174,6 +189,7 @@ def _enable_topping_selection(self, state): self.topping_line_edit.setEnabled(state) self.topping_line_label.setEnabled(state) self.topping_info.setEnabled(state) + self.busy(False) def _enable_optimize_combo(self, state): self.optimize_combo.setEnabled(state) @@ -307,21 +323,26 @@ def _clean_topping(self): def _set_topping_info(self, valid, index=None): if self.projecttopping_id: if index: + if self.existing_topping_checkbox.isChecked(): + info = self.tr( + "Project topping received according to the id found in the database or selected previously" + ) + else: + info = self.tr("Project topping received according selection") self.topping_info.setText( - self.tr( - "

Current project topping is: {} ({})
{}

" - ).format( - self.ilitoppingcache.model.data(index, Qt.DisplayRole), + "

{} ({})
{}

".format( + info, self.projecttopping_id, self.ilitoppingcache.model.data( - index, int(IliDataItemModel.Roles.SHORT_DESCRIPTION) or "" - ), + index, int(IliDataItemModel.Roles.SHORT_DESCRIPTION) + ) + or "", ) ) else: self.topping_info.setText( self.tr( - "

Current project topping is: {}

" + "

Project topping from file {}

" ).format(self.projecttopping_id) ) @@ -638,3 +659,10 @@ def ilidata_path_resolver(self, base_path, path): data_file_path_list = self.workflow_wizard.get_topping_file_list([path]) return data_file_path_list[0] if data_file_path_list else None return os.path.join(base_path, path) + + def busy(self, busy, text=None): + self.setEnabled(not busy) + if busy: + self.workflow_wizard.start_busy_bar(text) + else: + self.workflow_wizard.stop_busy_bar() diff --git a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py index b446ed079..2f67d2a25 100644 --- a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py +++ b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py @@ -59,6 +59,7 @@ IliToppingFileCache, ) from QgisModelBaker.libs.modelbaker.utils.globals import DbActionType +from QgisModelBaker.utils import gui_utils from QgisModelBaker.utils.gui_utils import ( FileDropListView, ImportDataModel, @@ -271,6 +272,9 @@ def next_id(self): "Checking for potential referenced data on the repositories (might take a while)..." ) ) + self.schema_configuration_page.busy( + True, self.tr("Checking for potential referenced data...") + ) self.schema_configuration_page.setComplete(False) if ( self.import_data_file_model.rowCount() @@ -283,6 +287,7 @@ def next_id(self): self.tr("Potential referenced data found.") ) self.schema_configuration_page.setComplete(True) + self.schema_configuration_page.busy(False) return PageIds.ImportDataConfiguration else: self.log_panel.print_info( @@ -291,6 +296,7 @@ def next_id(self): ) ) self.schema_configuration_page.setComplete(True) + self.schema_configuration_page.busy(False) if self.current_id == PageIds.ImportSchemaExecution: # if basket handling active, go to the create basket @@ -307,6 +313,9 @@ def next_id(self): "Checking for potential referenced data on the repositories (might take a while)..." ) ) + self.import_schema_execution_page.busy( + True, self.tr("Checking for potential referenced data...") + ) self.import_schema_execution_page.setComplete(False) if self.update_referecedata_cache_model( self._db_modelnames(self.import_data_configuration), @@ -316,8 +325,10 @@ def next_id(self): self.tr("Potential referenced data found.") ) self.import_schema_execution_page.setComplete(True) + self.import_schema_execution_page.busy(False) return PageIds.ImportDataConfiguration self.import_schema_execution_page.setComplete(True) + self.import_schema_execution_page.busy(False) # otherwise, go to project create return PageIds.ProjectCreation @@ -334,6 +345,9 @@ def next_id(self): ) ) self.default_baskets_page.setComplete(False) + self.ddefault_baskets_page.busy( + True, self.tr("Checking for potential referenced data...") + ) if self.update_referecedata_cache_model( self._db_modelnames(self.import_data_configuration), "referenceData", @@ -342,8 +356,10 @@ def next_id(self): self.tr("Potential referenced data found.") ) self.default_baskets_page.setComplete(True) + self.default_baskets_page.busy(False) return PageIds.ImportDataConfiguration self.default_baskets_page.setComplete(True) + self.default_baskets_page.busy(False) # otherwise, go to project create return PageIds.ProjectCreation @@ -670,10 +686,19 @@ def append_dropped_files(self, dropped_files, dropped_ini_files): dropped_ini_files[0] ) + def start_busy_bar(self, text="Loading..."): + self.log_panel.busy_bar.setFormat(text) + self.log_panel.busy_bar.setVisible(True) + + def stop_busy_bar(self): + self.log_panel.busy_bar.setVisible(False) + self.log_panel.scrollbar.setValue(self.log_panel.scrollbar.maximum()) + class WorkflowWizardDialog(QDialog): def __init__(self, iface, base_config, parent): QDialog.__init__(self, parent) + self.setStyleSheet(gui_utils.DEFAULT_STYLE) self.iface = iface self.base_config = base_config @@ -683,8 +708,8 @@ def __init__(self, iface, base_config, parent): self.workflow_wizard.setStartId(PageIds.Intro) self.workflow_wizard.setWindowFlags(Qt.Widget) self.workflow_wizard.show() - self.workflow_wizard.finished.connect(self.done) + layout = QVBoxLayout() splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.workflow_wizard) diff --git a/QgisModelBaker/ui/workflow_wizard/project_creation.ui b/QgisModelBaker/ui/workflow_wizard/project_creation.ui index d93d27753..4478ecc5f 100644 --- a/QgisModelBaker/ui/workflow_wizard/project_creation.ui +++ b/QgisModelBaker/ui/workflow_wizard/project_creation.ui @@ -61,6 +61,9 @@ + + <html><head/><body><p>A project topping is already given by the previous metaconfiguration selection or via the metaconfiguration id stored in the database. Uncheck, when you want to choose another project topping file.</p></body></html> + Use existing project topping @@ -114,6 +117,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -181,19 +197,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - From 0127020deba18c615a04cd98d69779cd858c64e8 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 16:41:54 +0100 Subject: [PATCH 4/9] fix typo --- QgisModelBaker/gui/workflow_wizard/workflow_wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py index 2f67d2a25..6c0a2cc2b 100644 --- a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py +++ b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py @@ -345,7 +345,7 @@ def next_id(self): ) ) self.default_baskets_page.setComplete(False) - self.ddefault_baskets_page.busy( + self.default_baskets_page.busy( True, self.tr("Checking for potential referenced data...") ) if self.update_referecedata_cache_model( From 6282a2dde1f034d11314fc0bb82352292e7b2231 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 17:02:49 +0100 Subject: [PATCH 5/9] cleanup --- .../workflow_wizard/project_creation_page.py | 181 +++++++++--------- 1 file changed, 91 insertions(+), 90 deletions(-) diff --git a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py index dba76e769..294cfd74b 100644 --- a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py +++ b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py @@ -124,22 +124,23 @@ def restore_configuration(self, configuration): self.existing_topping_checkbox.setVisible(False) self.existing_projecttopping_id = self._existing_projecttopping_id() if self.existing_projecttopping_id: - self.tr("Use existing project topping {}").format(self.projecttopping_id) self.existing_topping_checkbox.setVisible(True) + # with setting it checked _use_existing is called self.existing_topping_checkbox.setChecked(True) else: self._use_existing(False) self.busy(False) def _use_existing(self, state): - # triggered by checked state... + # triggered by checked state. if state: self._clean_topping() - self.topping_line_edit.setText("") - self._enable_topping_selection(False) - self._enable_optimize_combo(False) self.projecttopping_id = self.existing_projecttopping_id self._set_topping_info(True) + # disable other widgets + self._enable_topping_selection(False) + self._enable_optimize_combo(False) + self.topping_line_edit.setText("") else: self._clean_topping() self.ilitoppingcache = IliDataCache( @@ -165,7 +166,6 @@ def _use_existing(self, state): self.ilitoppingcache.model_refreshed.connect( lambda: self._enable_topping_selection(True) ) - self._enable_optimize_combo(True) self.ilitoppingcache.refresh() completer = QCompleter( @@ -179,7 +179,6 @@ def _use_existing(self, state): completer.setFilterMode(Qt.MatchContains) completer.popup().setItemDelegate(self.ilitopping_delegate) self.topping_line_edit.setCompleter(completer) - self._enable_optimize_combo(True) def _enable_topping_selection(self, state): # doublecheck if meanwhile user checked box again @@ -189,80 +188,14 @@ def _enable_topping_selection(self, state): self.topping_line_edit.setEnabled(state) self.topping_line_label.setEnabled(state) self.topping_info.setEnabled(state) + + self._enable_optimize_combo(state) self.busy(False) def _enable_optimize_combo(self, state): self.optimize_combo.setEnabled(state) self.optimize_label.setEnabled(state) - def _datasource_metaconfig(self): - metaconfig_id = None - setting_records = self.db_connector.get_ili2db_settings() - for setting_record in setting_records: - if setting_record["tag"] == "ch.ehi.ili2db.metaConfigFileName": - metaconfig_id = setting_record["setting"] - break - if metaconfig_id: - metaconfig_file_path_list = self.workflow_wizard.get_topping_file_list( - [metaconfig_id] - ) - - if not metaconfig_file_path_list: - self.workflow_wizard.log_panel.print_info( - self.tr( - "Found a metaconfig-id ({}) in the data source, but no corresponding metaconfig in the repositories." - ).format(metaconfig_id), - LogColor.COLOR_TOPPING, - ) - return None - - metaconfig = configparser.ConfigParser() - with open(metaconfig_file_path_list[0]) as metaconfig_file: - metaconfig.read_file(metaconfig_file) - return metaconfig - - return None - - def _existing_projecttopping_id(self): - metaconfig = self.configuration.metaconfig - - if not metaconfig: - metaconfig = self._datasource_metaconfig() - - if not metaconfig: - # no existing metaconfig available - return None - - # get projecttopping_id from metaconfig - if "CONFIGURATION" in metaconfig.sections(): - configuration_section = metaconfig["CONFIGURATION"] - # get topping referenced in qgis.modelbaker.projecttopping - key = "qgis.modelbaker.projecttopping" - if key not in configuration_section: - key = "qgis.modelbaker.layertree" - self.workflow_wizard.log_panel.print_info( - self.tr( - 'Keyword "qgis.modelbaker.layertree" is deprecated (but still working). Use "qgis.modelbaker.projecttopping" instead.' - ), - LogColor.COLOR_TOPPING, - ) - - if key in configuration_section: - self.workflow_wizard.log_panel.print_info( - self.tr("Metaconfig contains a project topping."), - LogColor.COLOR_TOPPING, - ) - projecttopping_id_list = configuration_section[key].split(";") - if len(projecttopping_id_list) > 1: - self.workflow_wizard.log_panel.print_info( - self.tr( - "Only one projectopping allowed. Taking first one of the list." - ), - LogColor.COLOR_TOPPING, - ) - return projecttopping_id_list[0] - return None - def _complete_completer(self): if self.topping_line_edit.hasFocus() and self.topping_line_edit.completer(): if not self.topping_line_edit.text(): @@ -354,21 +287,6 @@ def _set_topping_info(self, valid, index=None): ) ) - def _modelnames(self): - modelnames = [] - db_models = self.db_connector.get_models() - regex = re.compile(r"(?:\{[^\}]*\}|\s)") - for db_model in db_models: - for modelname in regex.split(db_model["modelname"]): - name = modelname.strip() - if ( - name - and name not in TRANSFERFILE_MODELS_BLACKLIST - and name not in modelnames - ): - modelnames.append(name) - return modelnames - def _create_project(self): self.progress_bar.setValue(0) @@ -660,6 +578,89 @@ def ilidata_path_resolver(self, base_path, path): return data_file_path_list[0] if data_file_path_list else None return os.path.join(base_path, path) + def _datasource_metaconfig(self): + metaconfig_id = None + setting_records = self.db_connector.get_ili2db_settings() + for setting_record in setting_records: + if setting_record["tag"] == "ch.ehi.ili2db.metaConfigFileName": + metaconfig_id = setting_record["setting"] + break + if metaconfig_id: + metaconfig_file_path_list = self.workflow_wizard.get_topping_file_list( + [metaconfig_id] + ) + + if not metaconfig_file_path_list: + self.workflow_wizard.log_panel.print_info( + self.tr( + "Found a metaconfig-id ({}) in the data source, but no corresponding metaconfig in the repositories." + ).format(metaconfig_id), + LogColor.COLOR_TOPPING, + ) + return None + + metaconfig = configparser.ConfigParser() + with open(metaconfig_file_path_list[0]) as metaconfig_file: + metaconfig.read_file(metaconfig_file) + return metaconfig + + return None + + def _existing_projecttopping_id(self): + metaconfig = self.configuration.metaconfig + + if not metaconfig: + metaconfig = self._datasource_metaconfig() + + if not metaconfig: + # no existing metaconfig available + return None + + # get projecttopping_id from metaconfig + if "CONFIGURATION" in metaconfig.sections(): + configuration_section = metaconfig["CONFIGURATION"] + # get topping referenced in qgis.modelbaker.projecttopping + key = "qgis.modelbaker.projecttopping" + if key not in configuration_section: + key = "qgis.modelbaker.layertree" + self.workflow_wizard.log_panel.print_info( + self.tr( + 'Keyword "qgis.modelbaker.layertree" is deprecated (but still working). Use "qgis.modelbaker.projecttopping" instead.' + ), + LogColor.COLOR_TOPPING, + ) + + if key in configuration_section: + self.workflow_wizard.log_panel.print_info( + self.tr("Metaconfig contains a project topping."), + LogColor.COLOR_TOPPING, + ) + projecttopping_id_list = configuration_section[key].split(";") + if len(projecttopping_id_list) > 1: + self.workflow_wizard.log_panel.print_info( + self.tr( + "Only one projectopping allowed. Taking first one of the list." + ), + LogColor.COLOR_TOPPING, + ) + return projecttopping_id_list[0] + return None + + def _modelnames(self): + modelnames = [] + db_models = self.db_connector.get_models() + regex = re.compile(r"(?:\{[^\}]*\}|\s)") + for db_model in db_models: + for modelname in regex.split(db_model["modelname"]): + name = modelname.strip() + if ( + name + and name not in TRANSFERFILE_MODELS_BLACKLIST + and name not in modelnames + ): + modelnames.append(name) + return modelnames + def busy(self, busy, text=None): self.setEnabled(not busy) if busy: From 9858be7ae303c4d32c86b5cf930c227103c61170 Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 17:34:47 +0100 Subject: [PATCH 6/9] busy state on basket page --- QgisModelBaker/gui/workflow_wizard/default_baskets_page.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py b/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py index 1acfcb081..1d9d36ff2 100644 --- a/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py +++ b/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py @@ -107,3 +107,10 @@ def _skip(self): self.skip_button.setDisabled(True) self.baskets_panel.setDisabled(True) self.setComplete(True) + + def busy(self, busy, text=None): + self.setEnabled(not busy) + if busy: + self.workflow_wizard.start_busy_bar(text) + else: + self.workflow_wizard.stop_busy_bar() From ef4410b6b80ccd9dbf9eae4b670606b86f09efaf Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 17:42:51 +0100 Subject: [PATCH 7/9] move busy functionality to workflowwizard and pass the page --- .../workflow_wizard/default_baskets_page.py | 7 --- .../import_schema_configuration_page.py | 15 ++----- .../workflow_wizard/project_creation_page.py | 16 +++---- .../gui/workflow_wizard/workflow_wizard.py | 45 +++++++++++-------- 4 files changed, 35 insertions(+), 48 deletions(-) diff --git a/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py b/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py index 1d9d36ff2..1acfcb081 100644 --- a/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py +++ b/QgisModelBaker/gui/workflow_wizard/default_baskets_page.py @@ -107,10 +107,3 @@ def _skip(self): self.skip_button.setDisabled(True) self.baskets_panel.setDisabled(True) self.setComplete(True) - - def busy(self, busy, text=None): - self.setEnabled(not busy) - if busy: - self.workflow_wizard.start_busy_bar(text) - else: - self.workflow_wizard.stop_busy_bar() diff --git a/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py b/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py index 956ff3b6c..c77b205b5 100644 --- a/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py +++ b/QgisModelBaker/gui/workflow_wizard/import_schema_configuration_page.py @@ -185,7 +185,7 @@ def _update_ilimetaconfigcache(self): self.ilimetaconfigcache.model_refreshed.connect( self._update_metaconfig_completer ) - self.busy(True, self.tr("Refresh repository data...")) + self.workflow_wizard.busy(self, True, self.tr("Refresh repository data...")) self._refresh_ili_metaconfig_cache() def _update_ilireferencedatacache(self): @@ -290,7 +290,7 @@ def _update_metaconfig_completer(self, rows): completer.popup().setItemDelegate(self.metaconfig_delegate) self.ili_metaconfig_line_edit.setCompleter(completer) self.ili_metaconfig_line_edit.setEnabled(bool(rows)) - self.busy(False) + self.workflow_wizard.busy(self, False) def _on_metaconfig_completer_activated(self, text=None): self._clean_metaconfig() @@ -436,7 +436,7 @@ def _load_crs_from_metaconfig(self, ili2db_metaconfig): self._crs_changed() def _load_metaconfig(self): - self.busy(True, "Load metaconfiguration...") + self.workflow_wizard.busy(self, True, "Load metaconfiguration...") # load ili2db parameters to the GUI if "ch.ehi.ili2db" in self.metaconfig.sections(): self.workflow_wizard.log_panel.print_info( @@ -575,11 +575,4 @@ def _load_metaconfig(self): ) self.workflow_wizard.refresh_import_models() - self.busy(False) - - def busy(self, busy, text=None): - self.setEnabled(not busy) - if busy: - self.workflow_wizard.start_busy_bar(text) - else: - self.workflow_wizard.stop_busy_bar() + self.workflow_wizard.busy(self, False) diff --git a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py index 294cfd74b..65b2c6643 100644 --- a/QgisModelBaker/gui/workflow_wizard/project_creation_page.py +++ b/QgisModelBaker/gui/workflow_wizard/project_creation_page.py @@ -113,7 +113,8 @@ def setComplete(self, complete): self.completeChanged.emit() def restore_configuration(self, configuration): - self.busy( + self.workflow_wizard.busy( + self, True, self.tr("Restoring configuration and check existing metaconfigfile..."), ) @@ -129,7 +130,7 @@ def restore_configuration(self, configuration): self.existing_topping_checkbox.setChecked(True) else: self._use_existing(False) - self.busy(False) + self.workflow_wizard.busy(self, False) def _use_existing(self, state): # triggered by checked state. @@ -162,7 +163,7 @@ def _use_existing(self, state): self.workflow_wizard.log_panel.show_message ) # wait before activating until end of refreshment - self.busy(True, self.tr("Refresh repository data...")) + self.workflow_wizard.busy(self, True, self.tr("Refresh repository data...")) self.ilitoppingcache.model_refreshed.connect( lambda: self._enable_topping_selection(True) ) @@ -190,7 +191,7 @@ def _enable_topping_selection(self, state): self.topping_info.setEnabled(state) self._enable_optimize_combo(state) - self.busy(False) + self.workflow_wizard.busy(self, False) def _enable_optimize_combo(self, state): self.optimize_combo.setEnabled(state) @@ -660,10 +661,3 @@ def _modelnames(self): ): modelnames.append(name) return modelnames - - def busy(self, busy, text=None): - self.setEnabled(not busy) - if busy: - self.workflow_wizard.start_busy_bar(text) - else: - self.workflow_wizard.stop_busy_bar() diff --git a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py index 6c0a2cc2b..3292c91a0 100644 --- a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py +++ b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py @@ -272,8 +272,10 @@ def next_id(self): "Checking for potential referenced data on the repositories (might take a while)..." ) ) - self.schema_configuration_page.busy( - True, self.tr("Checking for potential referenced data...") + self.busy( + self.schema_configuration_page, + True, + self.tr("Checking for potential referenced data..."), ) self.schema_configuration_page.setComplete(False) if ( @@ -287,7 +289,7 @@ def next_id(self): self.tr("Potential referenced data found.") ) self.schema_configuration_page.setComplete(True) - self.schema_configuration_page.busy(False) + self.busy(self.schema_configuration_page, False) return PageIds.ImportDataConfiguration else: self.log_panel.print_info( @@ -296,7 +298,7 @@ def next_id(self): ) ) self.schema_configuration_page.setComplete(True) - self.schema_configuration_page.busy(False) + self.busy(self.schema_configuration_page, False) if self.current_id == PageIds.ImportSchemaExecution: # if basket handling active, go to the create basket @@ -313,8 +315,10 @@ def next_id(self): "Checking for potential referenced data on the repositories (might take a while)..." ) ) - self.import_schema_execution_page.busy( - True, self.tr("Checking for potential referenced data...") + self.busy( + self.import_schema_execution_page, + True, + self.tr("Checking for potential referenced data..."), ) self.import_schema_execution_page.setComplete(False) if self.update_referecedata_cache_model( @@ -325,10 +329,10 @@ def next_id(self): self.tr("Potential referenced data found.") ) self.import_schema_execution_page.setComplete(True) - self.import_schema_execution_page.busy(False) + self.busy(self.import_schema_execution_page, False) return PageIds.ImportDataConfiguration self.import_schema_execution_page.setComplete(True) - self.import_schema_execution_page.busy(False) + self.busy(self.import_schema_execution_page, False) # otherwise, go to project create return PageIds.ProjectCreation @@ -345,8 +349,10 @@ def next_id(self): ) ) self.default_baskets_page.setComplete(False) - self.default_baskets_page.busy( - True, self.tr("Checking for potential referenced data...") + self.busy( + self.default_baskets_page, + True, + self.tr("Checking for potential referenced data..."), ) if self.update_referecedata_cache_model( self._db_modelnames(self.import_data_configuration), @@ -356,10 +362,10 @@ def next_id(self): self.tr("Potential referenced data found.") ) self.default_baskets_page.setComplete(True) - self.default_baskets_page.busy(False) + self.busy(self.default_baskets_page, False) return PageIds.ImportDataConfiguration self.default_baskets_page.setComplete(True) - self.default_baskets_page.busy(False) + self.busy(self.default_baskets_page, False) # otherwise, go to project create return PageIds.ProjectCreation @@ -686,13 +692,14 @@ def append_dropped_files(self, dropped_files, dropped_ini_files): dropped_ini_files[0] ) - def start_busy_bar(self, text="Loading..."): - self.log_panel.busy_bar.setFormat(text) - self.log_panel.busy_bar.setVisible(True) - - def stop_busy_bar(self): - self.log_panel.busy_bar.setVisible(False) - self.log_panel.scrollbar.setValue(self.log_panel.scrollbar.maximum()) + def busy(self, page, busy, text="Busy..."): + page.setEnabled(not busy) + if busy: + self.log_panel.busy_bar.setFormat(text) + self.log_panel.busy_bar.setVisible(True) + else: + self.log_panel.busy_bar.setVisible(False) + self.log_panel.scrollbar.setValue(self.log_panel.scrollbar.maximum()) class WorkflowWizardDialog(QDialog): From 86f63885179e60b1eff7e985f042c4c737c3e96f Mon Sep 17 00:00:00 2001 From: signedav Date: Mon, 4 Dec 2023 17:52:29 +0100 Subject: [PATCH 8/9] remove unused function --- QgisModelBaker/gui/workflow_wizard/execution_page.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/QgisModelBaker/gui/workflow_wizard/execution_page.py b/QgisModelBaker/gui/workflow_wizard/execution_page.py index 2b5a5eddf..f184f92ac 100644 --- a/QgisModelBaker/gui/workflow_wizard/execution_page.py +++ b/QgisModelBaker/gui/workflow_wizard/execution_page.py @@ -195,10 +195,3 @@ def _on_process_finished(self, exit_code, result): message = self.tr("Finished with errors!") self.workflow_wizard.log_panel.print_info(message, color) - - def busy(self, busy, text=None): - self.setEnabled(not busy) - if busy: - self.workflow_wizard.start_busy_bar(text) - else: - self.workflow_wizard.stop_busy_bar() From 3589cf95acbec8f66f030e21ffc185ff4295c3e8 Mon Sep 17 00:00:00 2001 From: signedav Date: Wed, 6 Dec 2023 08:28:04 +0100 Subject: [PATCH 9/9] Update QgisModelBaker/gui/workflow_wizard/workflow_wizard.py Co-authored-by: Damiano Lombardi --- QgisModelBaker/gui/workflow_wizard/workflow_wizard.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py index 3292c91a0..5281860bc 100644 --- a/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py +++ b/QgisModelBaker/gui/workflow_wizard/workflow_wizard.py @@ -694,11 +694,10 @@ def append_dropped_files(self, dropped_files, dropped_ini_files): def busy(self, page, busy, text="Busy..."): page.setEnabled(not busy) + self.log_panel.busy_bar.setVisible(busy) if busy: self.log_panel.busy_bar.setFormat(text) - self.log_panel.busy_bar.setVisible(True) else: - self.log_panel.busy_bar.setVisible(False) self.log_panel.scrollbar.setValue(self.log_panel.scrollbar.maximum())