Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TID (OID) Configurator #844

Merged
merged 30 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6c2579a
move Checkbox Delegate to utils
signedav Nov 17, 2023
eadee7d
Put checkbox in the middle
signedav Nov 17, 2023
383fdc4
Weird order of the setData parameters - marked with a comment. One co…
signedav Nov 17, 2023
8e2847f
Integration of TID configuration page WIP
signedav Nov 17, 2023
3d6b6e0
here we go. first version of the tid configurator - needs finetuning
signedav Nov 17, 2023
bb5ead5
have now 1 a page then a tid_configuator and there the two panels
signedav Nov 17, 2023
5f5d2fb
nice expression dialog delegate, but it still appears only on double …
signedav Nov 17, 2023
e43ea38
at least with one click it opens the expression widget
signedav Nov 17, 2023
4f90716
Make delegates beautiful - means show them from beginning.
signedav Nov 20, 2023
a0d85cf
TID Manager openable via menu
signedav Nov 20, 2023
36a7772
push changes to model on ok when still editing cell in view
signedav Nov 20, 2023
1aac0c5
Descriptive text. Layout finetuning and tooltips.
signedav Nov 20, 2023
a065b1e
Documentation for TID Generation
signedav Nov 23, 2023
3300f61
fix typos
signedav Nov 23, 2023
a8cee7e
Update docs/user_guide/import_workflow.md
signedav Nov 24, 2023
a7ea3a9
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
7ffa813
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
b9ea04d
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
cb32d9b
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
9377aa5
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
762971c
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
6b5a2a1
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
3d2894e
Update docs/user_guide/import_workflow.md
signedav Nov 24, 2023
64333f7
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
840f76d
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
f7642b6
remove comment
signedav Nov 24, 2023
f23f751
icon
signedav Nov 24, 2023
5f162b0
Update docs/background_info/oid_tid_generator.md
signedav Nov 24, 2023
dd7fc02
change ch100000 to %change%
signedav Nov 24, 2023
24a9124
wording
signedav Nov 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions QgisModelBaker/gui/dataset_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ def _close_editing(self):
if layer.isEditable():
editable_layers.append(layer)
if editable_layers:
# in case it could not close it automatically
warning_box = QMessageBox(self)
warning_box.setIcon(QMessageBox.Warning)
warning_title = self.tr("Layers still editable")
Expand Down
263 changes: 263 additions & 0 deletions QgisModelBaker/gui/panel/layer_tids_panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
"""
/***************************************************************************
-------------------
begin : 17.11.2023
git sha : :%H$
copyright : (C) 2023 by Dave Signer
email : david at opengis ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""


from enum import Enum, IntEnum

from qgis.core import QgsProject
from qgis.gui import QgsFieldExpressionWidget
from qgis.PyQt.QtCore import QAbstractTableModel, QModelIndex, Qt
from qgis.PyQt.QtGui import QPixmap
from qgis.PyQt.QtWidgets import (
QAbstractItemView,
QHeaderView,
QStyledItemDelegate,
QWidget,
)

import QgisModelBaker.utils.gui_utils as gui_utils
from QgisModelBaker.libs.modelbaker.utils.qgis_utils import QgisProjectUtils
from QgisModelBaker.utils.gui_utils import CheckDelegate

WIDGET_UI = gui_utils.get_ui_class("layer_tids_panel.ui")


class TIDModel(QAbstractTableModel):
"""
ItemModel providing all TIDs and default values of the passed project

oid_settings is a dictionary like:
{
"Strasse":
{
"oid_domain": "STANDARDOID",
"interlis_topic" : "OIDMadness_V1",
"default_value_expression": "uuid()",
"in_form": True
}
[...]
}
"""

class Roles(Enum):
LAYER = Qt.UserRole + 1

def __int__(self):
return self.value

class Columns(IntEnum):
NAME = 0
OID_DOMAIN = 1
DEFAULT_VALUE = 2
IN_FORM = 3

def __init__(self):
super().__init__()
self.oid_settings = {}

def columnCount(self, parent):
return len(TIDModel.Columns)

def rowCount(self, parent):
return len(self.oid_settings.keys())

def flags(self, index):
if index.column() == TIDModel.Columns.IN_FORM:
return Qt.ItemIsEnabled
if index.column() == TIDModel.Columns.DEFAULT_VALUE:
return Qt.ItemIsEditable | Qt.ItemIsEnabled
return Qt.ItemIsSelectable | Qt.ItemIsEnabled

def index(self, row: int, column: int, parent: QModelIndex = ...) -> QModelIndex:
"""
default override
"""
return super().createIndex(row, column, parent)

def parent(self, index):
"""
default override
"""
return index

def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
if section == TIDModel.Columns.NAME:
return self.tr("Layer")
if section == TIDModel.Columns.OID_DOMAIN:
return self.tr("TID (OID Type)")
if section == TIDModel.Columns.DEFAULT_VALUE:
return self.tr("Default Value Expression")
if section == TIDModel.Columns.IN_FORM:
return self.tr("Show")

def data(self, index, role):
if role == int(Qt.DisplayRole) or role == int(Qt.EditRole):
key = list(self.oid_settings.keys())[index.row()]
if index.column() == TIDModel.Columns.NAME:
return f"{key} ({self.oid_settings[key]['interlis_topic']})"
if index.column() == TIDModel.Columns.OID_DOMAIN:
return self.oid_settings[key]["oid_domain"]
if index.column() == TIDModel.Columns.DEFAULT_VALUE:
return self.oid_settings[key]["default_value_expression"]
if index.column() == TIDModel.Columns.IN_FORM:
return self.oid_settings[key]["in_form"]
elif role == int(Qt.ToolTipRole):
key = list(self.oid_settings.keys())[index.row()]
if index.column() == TIDModel.Columns.NAME:
return f"{key} ({self.oid_settings[key]['interlis_topic']})"
if index.column() == TIDModel.Columns.OID_DOMAIN:
message = self.tr(
"<html><head/><body><p>The OID format is not defined, you can use whatever you want, but it should always start with an underscore <code>_</code> or an alphanumeric value.</p></body></html>"
)
oid_domain = self.oid_settings[key].get("oid_domain", "")
if oid_domain[-7:] == "UUIDOID":
message = self.tr(
"<html><head/><body><p>The OID should be an Universally Unique Identifier (OID TEXT*36).</p></body></html>"
)
elif oid_domain[-11:] == "STANDARDOID":
message = self.tr(
"""<html>
<body>
<p>
The OID format requireds an 8 char prefix and 8 char postfix.
</p>
<p><b>Prefix (2 + 6 chars):</b> Country identifier + a 'global' identification part assigned once by the official authority.</p>
</p><p><b>Postfix (8 chars):</b> Sequence (numeric or alphanumeric) of your system as 'local' identification part.</p>
</body>
</html>
"""
)
elif oid_domain[-6:] == "I32OID":
message = self.tr(
"<html><head/><body><p>The OID must be an integer value (OID 0 .. 2147483647).</p></body></html>"
)
elif oid_domain[-6:] == "ANYOID":
message = self.tr(
"<html><head/><body><p>The OID format could vary depending in what basket the object (entry) is located.</p><p>These objects could be in the following topics: {topics}</body></html>".format(
topics=self.oid_settings[key]["interlis_topic"]
)
)
return message
if index.column() == TIDModel.Columns.DEFAULT_VALUE:
return self.oid_settings[key]["default_value_expression"]
if index.column() == TIDModel.Columns.IN_FORM:
return self.tr("Show t_ili_tid field (OID) in attribute form.")
elif role == int(TIDModel.Roles.LAYER):
key = list(self.oid_settings.keys())[index.row()]
return self.oid_settings[key]["layer"]
return None

def setData(self, index, data, role):
if role == int(Qt.EditRole):
if index.column() == TIDModel.Columns.DEFAULT_VALUE:
key = list(self.oid_settings.keys())[index.row()]
self.oid_settings[key]["default_value_expression"] = data
self.dataChanged.emit(index, index)
if index.column() == TIDModel.Columns.IN_FORM:
key = list(self.oid_settings.keys())[index.row()]
self.oid_settings[key]["in_form"] = data
self.dataChanged.emit(index, index)
return True

def load_tid_config(self, qgis_project=None):
self.beginResetModel()
self.oid_settings = QgisProjectUtils(qgis_project).get_oid_settings()
self.endResetModel()

def save_tid_config(self, qgis_project=None):
if qgis_project:
QgisProjectUtils(qgis_project).set_oid_settings(self.oid_settings)


class FieldExpressionDelegate(QStyledItemDelegate):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.editor = None

def createEditor(self, parent, option, index):
self.editor = QgsFieldExpressionWidget(parent)
layer = index.data(int(TIDModel.Roles.LAYER))
self.editor.setLayer(layer)
return self.editor

def setEditorData(self, editor, index):
value = index.data(int(Qt.DisplayRole))
self.editor.setExpression(value)

def setModelData(self, editor, model, index):
value = editor.expression()
print(f"new exp{value}")
model.setData(index, value, int(Qt.EditRole))

def updateEditorGeometry(self, editor, option, index):
self.editor.setGeometry(option.rect)

def paint(self, painter, option, index):
opt = self.createEditor(self.parent, option, index)
opt.editable = False
value = index.data(int(Qt.DisplayRole))
opt.setExpression(value)
opt.resize(option.rect.width(), option.rect.height())
pixmap = QPixmap(opt.width(), opt.height())
opt.render(pixmap)
painter.drawPixmap(option.rect, pixmap)
painter.restore()


class LayerTIDsPanel(QWidget, WIDGET_UI):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.parent = parent
self.tid_model = TIDModel()
self.layer_tids_view.setModel(self.tid_model)

self.layer_tids_view.horizontalHeader().setSectionResizeMode(
TIDModel.Columns.NAME, QHeaderView.Stretch
)
self.layer_tids_view.horizontalHeader().setSectionResizeMode(
TIDModel.Columns.OID_DOMAIN, QHeaderView.ResizeToContents
)
self.layer_tids_view.horizontalHeader().setSectionResizeMode(
TIDModel.Columns.DEFAULT_VALUE, QHeaderView.ResizeToContents
)
self.layer_tids_view.horizontalHeader().setSectionResizeMode(
TIDModel.Columns.IN_FORM, QHeaderView.ResizeToContents
)

self.layer_tids_view.setItemDelegateForColumn(
TIDModel.Columns.IN_FORM,
CheckDelegate(self, Qt.EditRole),
)
self.layer_tids_view.setItemDelegateForColumn(
TIDModel.Columns.DEFAULT_VALUE,
FieldExpressionDelegate(self),
)
self.layer_tids_view.setEditTriggers(QAbstractItemView.AllEditTriggers)

def load_tid_config(self, qgis_project=QgsProject.instance()):
self.tid_model.load_tid_config(qgis_project)

def save_tid_config(self, qgis_project=QgsProject.instance()):
# if a cell is still edited, we need to store it in model by force
index = self.layer_tids_view.currentIndex()
self.layer_tids_view.currentChanged(index, index)
self.tid_model.save_tid_config(qgis_project)
46 changes: 46 additions & 0 deletions QgisModelBaker/gui/panel/set_sequence_panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
/***************************************************************************
-------------------
begin : 17.11.2023
git sha : :%H$
copyright : (C) 2023 by Dave Signer
email : david at opengis ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""


from qgis.PyQt.QtWidgets import QWidget

import QgisModelBaker.utils.gui_utils as gui_utils

WIDGET_UI = gui_utils.get_ui_class("set_sequence_panel.ui")


class SetSequencePanel(QWidget, WIDGET_UI):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)

def load_sequence(self, db_connector=None):
if db_connector:
sequence_value = db_connector.get_ili2db_sequence_value()
self.sequence_value_edit.setValue(sequence_value)

def save_sequence(self, db_connector=None):
if self.sequence_group.isChecked():
if db_connector:
return db_connector.set_ili2db_sequence_value(
self.sequence_value_edit.value()
)
return False, self.tr("Could not reset T_Id - no db_connector...")
else:
return True, self.tr("T_Id not set.")
Loading
Loading