From 37cd2f8269ff507f3de66d90bd33948ab85ab5c8 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Mon, 13 Aug 2018 17:23:03 +0200 Subject: [PATCH 1/3] Show source repository Fix #213 --- projectgenerator/gui/generate_project.py | 13 ++- projectgenerator/libili2db/ilicache.py | 110 +++++++++++++++++++++-- 2 files changed, 110 insertions(+), 13 deletions(-) diff --git a/projectgenerator/gui/generate_project.py b/projectgenerator/gui/generate_project.py index e0504c8b9..48878a0af 100644 --- a/projectgenerator/gui/generate_project.py +++ b/projectgenerator/gui/generate_project.py @@ -29,7 +29,7 @@ from projectgenerator.gui.multiple_models import MultipleModelsDialog from projectgenerator.libili2db.globals import CRS_PATTERNS from projectgenerator.libili2db.ili2dbconfig import SchemaImportConfiguration -from projectgenerator.libili2db.ilicache import IliCache +from projectgenerator.libili2db.ilicache import IliCache, ModelCompleterDelegate from projectgenerator.libili2db.iliimporter import JavaNotFoundError from projectgenerator.utils.qt_utils import ( make_file_selector, @@ -55,7 +55,8 @@ QCoreApplication, QSettings, Qt, - QLocale + QLocale, + QTimer ) from qgis.core import ( QgsProject, @@ -154,7 +155,9 @@ def __init__(self, iface, base_config, parent=None): self.ili_models_line_edit.textChanged.connect(self.on_model_changed) self.ilicache = IliCache(base_config) - self.ilicache.models_changed.connect(self.update_models_completer) + # self.ilicache.models_changed.connect(self.update_models_completer) + QTimer.singleShot(5000, self.update_models_completer) + # self.update_models_completer() self.ilicache.new_message.connect(self.show_message) self.ilicache.refresh() @@ -534,8 +537,10 @@ def ili_file_changed(self): self.ilicache.models_changed.emit() def update_models_completer(self): - completer = QCompleter(self.sender().model_names) + completer = QCompleter(self.ilicache.model, self.ili_models_line_edit) completer.setCaseSensitivity(Qt.CaseInsensitive) + self.delegate = ModelCompleterDelegate() + completer.popup().setItemDelegate(self.delegate) self.ili_models_line_edit.setCompleter(completer) self.multiple_models_dialog.models_line_edit.setCompleter(completer) diff --git a/projectgenerator/libili2db/ilicache.py b/projectgenerator/libili2db/ilicache.py index fd55e54b7..2a455faab 100644 --- a/projectgenerator/libili2db/ilicache.py +++ b/projectgenerator/libili2db/ilicache.py @@ -25,9 +25,28 @@ import re +from enum import Enum from projectgenerator.libili2db.ili2dbutils import get_all_modeldir_in_path -from projectgenerator.utils.qt_utils import download_file, NetworkError -from PyQt5.QtCore import QObject, pyqtSignal +from projectgenerator.utils.qt_utils import download_file +from PyQt5.QtCore import ( + QObject, + pyqtSignal, + Qt, + QModelIndex +) +from PyQt5.QtGui import ( + QStandardItemModel, + QStandardItem, + QPalette, + QRegion +) +from PyQt5.QtWidgets import ( + QItemDelegate, + QLabel, + QStyle, + QWidget, + QGridLayout +) from qgis.core import QgsMessageLog, Qgis @@ -45,6 +64,7 @@ def __init__(self, configuration, single_ili_file=None): self.repositories = dict() self.base_configuration = configuration self.single_ili_file = single_ili_file + self.model = IliModelItemModel() def refresh(self): if not self.base_configuration is None: @@ -66,7 +86,7 @@ def process_single_ili_file(self): models = self.process_ili_file(self.single_ili_file) self.repositories["no_repo"] = sorted( models, key=lambda m: m['version'], reverse=True) - self.models_changed.emit() + self.model.set_repositories(self.repositories) def download_repository(self, url): """ @@ -143,11 +163,13 @@ def _process_ilimodels(self, file, netloc): model['name'] = model_metadata.find('ili23:Name', self.ns).text model['version'] = model_metadata.find( 'ili23:Version', self.ns).text + model['repository'] = netloc repo_models.append(model) self.repositories[netloc] = sorted( repo_models, key=lambda m: m['version'], reverse=True) - self.models_changed.emit() + + self.model.set_repositories(self.repositories) def process_local_ili_folder(self, path): """ @@ -161,7 +183,8 @@ def process_local_ili_folder(self, path): self.repositories[path] = sorted( models, key=lambda m: m['version'], reverse=True) - self.models_changed.emit() + + self.model.set_repositories(self.repositories) def process_ili_file(self, ilifile): fileModels = list() @@ -171,12 +194,17 @@ def process_ili_file(self, ilifile): try: fileModels = self.parse_ili_file(ilifile, "latin1") self.new_message.emit(Qgis.Warning, - self.tr('Even though the ili file `{}` could be read, it is not in UTF-8. Please encode your ili models in UTF-8.'.format(os.path.basename(ilifile)))) + self.tr( + 'Even though the ili file `{}` could be read, it is not in UTF-8. Please encode your ili models in UTF-8.'.format( + os.path.basename(ilifile)))) except UnicodeDecodeError as e: self.new_message.emit(Qgis.Critical, - self.tr('Could not parse ili file `{}` with UTF-8 nor Latin-1 encodings. Please encode your ili models in UTF-8.'.format(os.path.basename(ilifile)))) - QgsMessageLog.logMessage(self.tr('Could not parse ili file `{ilifile}`. We suggest you to encode it in UTF-8. ({exception})'.format( - ilifile=ilifile, exception=str(e))), self.tr('Projectgenerator')) + self.tr( + 'Could not parse ili file `{}` with UTF-8 nor Latin-1 encodings. Please encode your ili models in UTF-8.'.format( + os.path.basename(ilifile)))) + QgsMessageLog.logMessage(self.tr( + 'Could not parse ili file `{ilifile}`. We suggest you to encode it in UTF-8. ({exception})'.format( + ilifile=ilifile, exception=str(e))), self.tr('Projectgenerator')) fileModels = list() return fileModels @@ -195,6 +223,7 @@ def parse_ili_file(self, ilipath, encoding): model = dict() model['name'] = result.group(1) model['version'] = '' + model['repository'] = ilipath models += [model] result = re_model_version.search(line) @@ -210,3 +239,66 @@ def model_names(self): for model in repo: names.append(model['name']) return names + + +class IliModelItemModel(QStandardItemModel): + class Roles(Enum): + ILIREPO = Qt.UserRole + 1 + VERSION = Qt.UserRole + 2 + + def __int__(self): + return self.value + + def __init__(self, parent=None): + super().__init__(0, 1, parent) + + def set_repositories(self, repositories): + self.clear() + row = 0 + + for repository in repositories.values(): + for model in repository: + item = QStandardItem() + item.setData(model['name'], int(Qt.DisplayRole)) + item.setData(model['name'], int(Qt.EditRole)) + item.setData(model['repository'], int(IliModelItemModel.Roles.ILIREPO)) + item.setData(model['version'], int(IliModelItemModel.Roles.VERSION)) + + self.appendRow(item) + row += 1 + + +class ModelCompleterDelegate(QItemDelegate): + """ + A item delegate for the autocompleter of model dialogs. + It shows the source repository next to the model name. + """ + + def __init__(self): + super().__init__() + self.widget = QWidget() + self.widget.setLayout(QGridLayout()) + self.widget.layout().setContentsMargins(0, 0, 0, 0) + self.model_label = QLabel() + self.model_label.setAttribute(Qt.WA_TranslucentBackground) + self.repository_label = QLabel() + self.repository_label.setAlignment(Qt.AlignRight) + self.widget.layout().addWidget(self.model_label, 0, 0) + self.widget.layout().addWidget(self.repository_label, 0, 1) + + def paint(self, painter, option, index): + option.index = index + super().paint(painter, option, index) + + def drawDisplay(self, painter, option, rect, text): + repository = option.index.data(int(IliModelItemModel.Roles.ILIREPO)) + version = option.index.data(int(IliModelItemModel.Roles.VERSION)) + self.repository_label.setText('{}'.format(repository)) + self.model_label.setText('{model}{version}'.format(model=text, version=version)) + self.widget.setMinimumSize(rect.size()) + + model_palette = option.palette + if option.state & QStyle.State_Selected: + model_palette.setColor(QPalette.WindowText, model_palette.color(QPalette.Active, QPalette.HighlightedText)) + + self.widget.render(painter, rect.topLeft(), QRegion(), QWidget.DrawChildren) From 4d8afee48f521fe83ad5c0ca4f6df393e73827d3 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Mon, 13 Aug 2018 17:29:22 +0200 Subject: [PATCH 2/3] Do not show version in model dropdown --- projectgenerator/libili2db/ilicache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projectgenerator/libili2db/ilicache.py b/projectgenerator/libili2db/ilicache.py index 2a455faab..1a4328ee5 100644 --- a/projectgenerator/libili2db/ilicache.py +++ b/projectgenerator/libili2db/ilicache.py @@ -293,8 +293,8 @@ def paint(self, painter, option, index): def drawDisplay(self, painter, option, rect, text): repository = option.index.data(int(IliModelItemModel.Roles.ILIREPO)) version = option.index.data(int(IliModelItemModel.Roles.VERSION)) - self.repository_label.setText('{}'.format(repository)) - self.model_label.setText('{model}{version}'.format(model=text, version=version)) + self.repository_label.setText('{repository}'.format(repository=repository)) + self.model_label.setText('{model}'.format(model=text)) self.widget.setMinimumSize(rect.size()) model_palette = option.palette From cb244ccfa5cc94e100f5031d0dc3da028ee75065 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Mon, 13 Aug 2018 17:42:57 +0200 Subject: [PATCH 3/3] Cleanup leftovers --- projectgenerator/gui/export.py | 8 +++++--- projectgenerator/gui/generate_project.py | 12 ++---------- projectgenerator/gui/import_data.py | 8 +++++--- projectgenerator/gui/multiple_models.py | 2 +- projectgenerator/libili2db/ilicache.py | 1 - 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/projectgenerator/gui/export.py b/projectgenerator/gui/export.py index 9b9bccbaa..64b8ac688 100644 --- a/projectgenerator/gui/export.py +++ b/projectgenerator/gui/export.py @@ -25,7 +25,7 @@ from projectgenerator.gui.options import OptionsDialog from projectgenerator.gui.multiple_models import MultipleModelsDialog from projectgenerator.libili2db.iliexporter import JavaNotFoundError -from projectgenerator.libili2db.ilicache import IliCache +from projectgenerator.libili2db.ilicache import IliCache, ModelCompleterDelegate from projectgenerator.utils.qt_utils import make_save_file_selector, Validators, \ make_file_selector, FileValidator, NonEmptyStringValidator, make_folder_selector, OverrideCursor from qgis.PyQt.QtGui import QColor, QDesktopServices, QFont, QValidator @@ -118,7 +118,7 @@ def __init__(self, base_config, parent=None): settings = QSettings() ilifile = settings.value('QgsProjectGenerator/ili2db/ilifile') self.ilicache = IliCache(base_config, ilifile or None) - self.ilicache.models_changed.connect(self.update_models_completer) + self.update_models_completer() self.ilicache.refresh() def accepted(self): @@ -346,8 +346,10 @@ def link_activated(self, link): QDesktopServices.openUrl(link) def update_models_completer(self): - completer = QCompleter(self.ilicache.model_names) + completer = QCompleter(self.ilicache.model, self.ili_models_line_edit) completer.setCaseSensitivity(Qt.CaseInsensitive) + self.delegate = ModelCompleterDelegate() + completer.popup().setItemDelegate(self.delegate) self.ili_models_line_edit.setCompleter(completer) self.multiple_models_dialog.models_line_edit.setCompleter(completer) diff --git a/projectgenerator/gui/generate_project.py b/projectgenerator/gui/generate_project.py index 48878a0af..41889a6a7 100644 --- a/projectgenerator/gui/generate_project.py +++ b/projectgenerator/gui/generate_project.py @@ -55,8 +55,7 @@ QCoreApplication, QSettings, Qt, - QLocale, - QTimer + QLocale ) from qgis.core import ( QgsProject, @@ -155,9 +154,7 @@ def __init__(self, iface, base_config, parent=None): self.ili_models_line_edit.textChanged.connect(self.on_model_changed) self.ilicache = IliCache(base_config) - # self.ilicache.models_changed.connect(self.update_models_completer) - QTimer.singleShot(5000, self.update_models_completer) - # self.update_models_completer() + self.update_models_completer() self.ilicache.new_message.connect(self.show_message) self.ilicache.refresh() @@ -521,8 +518,6 @@ def ili_file_changed(self): # Update completer to add models from given ili file self.iliFileCache = IliCache( self.base_configuration, self.ili_file_line_edit.text().strip()) - self.iliFileCache.models_changed.connect( - self.update_models_completer) self.iliFileCache.new_message.connect(self.show_message) self.iliFileCache.refresh() models = self.iliFileCache.process_ili_file(self.ili_file_line_edit.text().strip()) @@ -533,9 +528,6 @@ def ili_file_changed(self): self.ili_models_line_edit.textChanged.emit( self.ili_models_line_edit.text()) - # Update completer to show repository models in models dir - self.ilicache.models_changed.emit() - def update_models_completer(self): completer = QCompleter(self.ilicache.model, self.ili_models_line_edit) completer.setCaseSensitivity(Qt.CaseInsensitive) diff --git a/projectgenerator/gui/import_data.py b/projectgenerator/gui/import_data.py index b04aa1119..bfa0b68ad 100644 --- a/projectgenerator/gui/import_data.py +++ b/projectgenerator/gui/import_data.py @@ -24,7 +24,7 @@ from projectgenerator.gui.options import OptionsDialog from projectgenerator.gui.multiple_models import MultipleModelsDialog from projectgenerator.libili2db.iliimporter import JavaNotFoundError -from projectgenerator.libili2db.ilicache import IliCache +from projectgenerator.libili2db.ilicache import IliCache, ModelCompleterDelegate from projectgenerator.utils.qt_utils import ( make_file_selector, make_save_file_selector, @@ -137,7 +137,7 @@ def __init__(self, base_config, parent=None): settings = QSettings() ilifile = settings.value('QgsProjectGenerator/ili2db/ilifile') self.ilicache = IliCache(base_config, ilifile or None) - self.ilicache.models_changed.connect(self.update_models_completer) + self.update_models_completer() self.ilicache.refresh() def accepted(self): @@ -360,8 +360,10 @@ def link_activated(self, link): QDesktopServices.openUrl(link) def update_models_completer(self): - completer = QCompleter(self.ilicache.model_names) + completer = QCompleter(self.ilicache.model, self.ili_models_line_edit) completer.setCaseSensitivity(Qt.CaseInsensitive) + self.delegate = ModelCompleterDelegate() + completer.popup().setItemDelegate(self.delegate) self.ili_models_line_edit.setCompleter(completer) self.multiple_models_dialog.models_line_edit.setCompleter(completer) diff --git a/projectgenerator/gui/multiple_models.py b/projectgenerator/gui/multiple_models.py index e781f5013..1c5890049 100644 --- a/projectgenerator/gui/multiple_models.py +++ b/projectgenerator/gui/multiple_models.py @@ -31,7 +31,7 @@ class MultipleModelsDialog(QDialog, DIALOG_UI): def __init__(self, parent=None): QDialog.__init__(self, parent) self.setupUi(self) - QgsGui.instance().enableAutoGeometryRestore(self); + QgsGui.instance().enableAutoGeometryRestore(self) self.parent = parent self.model_list.itemSelectionChanged.connect(self.on_selection_changed) diff --git a/projectgenerator/libili2db/ilicache.py b/projectgenerator/libili2db/ilicache.py index 1a4328ee5..60d299827 100644 --- a/projectgenerator/libili2db/ilicache.py +++ b/projectgenerator/libili2db/ilicache.py @@ -55,7 +55,6 @@ class IliCache(QObject): 'ili23': 'http://www.interlis.ch/INTERLIS2.3' } - models_changed = pyqtSignal() new_message = pyqtSignal(int, str) def __init__(self, configuration, single_ili_file=None):