From d161991611c69507cc6eb1a9674603ac46d2e174 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Tue, 22 Nov 2022 11:22:32 +0100 Subject: [PATCH 1/9] added bad fix for default Value retrieval (for XP_ExterneReferenz and others) --- XPTools.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/XPTools.py b/XPTools.py index bdaed8c..6d4f20c 100644 --- a/XPTools.py +++ b/XPTools.py @@ -568,11 +568,25 @@ def createFeature(self, layer, fid = None): newFeaturesetId(fid) provider = layer.dataProvider() + + fields = layer.fields() newFeature.initAttributes(fields.count()) for i in range(fields.count()): - newFeature.setAttribute(i,provider.defaultValue(i)) + ## bad fix for bug in Default retrieval from postgres + ## (defaultValue won't give 9999 integer for e.g. XP_ExterneReferenz default value, + ## but defaultValueClause does. Though defaultValueClause will return '' + ## where None/NULL is correct) + ## REALLY DON'T KNOW IF THERE IS SOMEWHERE A CORRECT DEFAULT EMPTY STRING, WHICH + ## SHOULDN'T BE FIXED... + if provider.defaultValueClause(i)=='': + newFeature.setAttribute(i,provider.defaultValue(i)) + else: + newFeature.setAttribute(i,provider.defaultValueClause(i)) + ## end fix + ## old: + ## newFeature.setAttribute(i,provider.defaultValue(i)) return newFeature else: From 2dd6920785aaf29cf244d4a888de7f38353fd9b3 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Tue, 22 Nov 2022 14:27:48 +0100 Subject: [PATCH 2/9] experimented with hoehenmanager - stalled at selecting a reference XP_Objekt --- Ui_Hoehenmanager.ui | 104 ++++++++++++++++++++++++++++++++ XPTools.py | 4 +- XPlan.py | 23 ++++++- XPlanDialog.py | 142 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 Ui_Hoehenmanager.ui diff --git a/Ui_Hoehenmanager.ui b/Ui_Hoehenmanager.ui new file mode 100644 index 0000000..1395007 --- /dev/null +++ b/Ui_Hoehenmanager.ui @@ -0,0 +1,104 @@ + + + Hoehenmananger + + + + 0 + 0 + 400 + 300 + + + + Hoehenmanager + + + true + + + true + + + + + + + + Filterbegriff eingeben + + + + + + + Nur dem Filter entsprechende Einträge anzeigen + + + Filtern + + + + + + + + + Qt::CustomContextMenu + + + Rechtsklick zum Bearbeiten + + + QAbstractItemView::NoEditTriggers + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close|QDialogButtonBox::Reset + + + + + + + + + buttonBox + accepted() + Hoehenmananger + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Hoehenmananger + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/XPTools.py b/XPTools.py index 6d4f20c..7987354 100644 --- a/XPTools.py +++ b/XPTools.py @@ -267,8 +267,8 @@ def getBereicheFuerFeatures(self, db, gids): def getMaxGid(self, db, schemaName, tableName, pkFieldName = "gid"): retValue = -9999 - sel = "SELECT " + pkFieldName + " FROM \"" + schemaName + "\".\"" + tableName + \ - "\" ORDER BY 1 DESC LIMIT 1;" + sel = 'SELECT "' + pkFieldName + '" FROM \"' + schemaName + '"."' + tableName + \ + '" ORDER BY 1 DESC LIMIT 1;' query = QtSql.QSqlQuery(db) query.prepare(sel) diff --git a/XPlan.py b/XPlan.py index b374283..f4dceeb 100644 --- a/XPlan.py +++ b/XPlan.py @@ -27,8 +27,10 @@ from qgis.PyQt import QtCore, QtWidgets, QtSql from qgis.core import * from qgis.gui import * +# import importlib try: + ## importlib.reload(DataDrivenInputMask) from DataDrivenInputMask.ddattribute import DdTable except: pass @@ -42,7 +44,7 @@ from .XPImport import XPImporter from .XPlanDialog import XPlanungConf from .XPlanDialog import ChooseObjektart -from .XPlanDialog import XPNutzungsschablone, BereichsmanagerDialog, ReferenzmanagerDialog, ImportDialog +from .XPlanDialog import XPNutzungsschablone, BereichsmanagerDialog, ReferenzmanagerDialog, HoehenmanagerDialog, ImportDialog class XpError(object): '''General error''' @@ -193,6 +195,8 @@ def initGui(self): self.action24.triggered.connect(self.loadSO) self.action25 = QtWidgets.QAction(u"ExterneReferenzen bearbeiten", self.iface.mainWindow()) self.action25.triggered.connect(self.referenzmanagerStarten) + self.action25b = QtWidgets.QAction(u"Hoehenangaben bearbeiten", self.iface.mainWindow()) + self.action25b.triggered.connect(self.hoehenmanagerStarten) self.action26 = QtWidgets.QAction(u"räuml. Geltungsbereiche neu berechnen", self.iface.mainWindow()) self.action26.triggered.connect(self.geltungsbereichBerechnen) @@ -205,7 +209,7 @@ def initGui(self): self.action30 = QtWidgets.QAction(u"Importieren", self.iface.mainWindow()) self.action30.triggered.connect(self.importData) - self.xpMenu.addActions([self.action20, self.action25, self.action29, + self.xpMenu.addActions([self.action20, self.action25, self.action25b, self.action29, self.action6, self.action10, self.action30]) self.bereichMenu.addActions([self.action3, self.action1, self.action4]) self.bpMenu.addActions([self.action21, self.action26, self.action28]) @@ -706,6 +710,21 @@ def referenzmanagerStarten(self): dlg.show() dlg.exec_() + def hoehenmanagerStarten(self): + if self.db == None: + self.initialize(False) + + if self.db != None: + refSchema = "XP_Sonstiges" + refTable = "XP_Hoehenangabe" + extRefLayer = self.getLayerForTable(refSchema, refTable) + + if extRefLayer != None: + self.app.xpManager.moveLayerToGroup(extRefLayer, refSchema) + dlg = HoehenmanagerDialog(self, extRefLayer) + dlg.show() + dlg.exec_() + def onLayerDestroyed(self, layer): '''Slot, der aufgerufen wird wenn ein XP-Layer aus dem Projekt entfernt wird erst in QGIS3 wird das Layerobjekt übergeben''' diff --git a/XPlanDialog.py b/XPlanDialog.py index 16b475a..a93ad7b 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -55,6 +55,9 @@ REFERENZMANAGER_CLASS, _ = uic.loadUiType(os.path.join( os.path.dirname(__file__), 'Ui_Referenzmanager.ui')) +HOEHENMANAGER_CLASS, _ = uic.loadUiType(os.path.join( + os.path.dirname(__file__), 'Ui_Hoehenmanager.ui')) + IMPORT_CLASS, _ = uic.loadUiType(os.path.join( os.path.dirname(__file__), 'Ui_Import.ui')) @@ -735,6 +738,145 @@ def accept(self): self.done(self.selected) +class HoehenmanagerDialog(QtWidgets.QDialog, HOEHENMANAGER_CLASS): + def __init__(self, xplanplugin, hoehenLayer): + QtWidgets.QDialog.__init__(self) + # Set up the user interface from Designer. + self.setupUi(self) + self.xplanplugin = xplanplugin + self.hoehenLayer = hoehenLayer + self.hoehen.customContextMenuRequested.connect(self.on_hoehen_customContextMenuRequested) + self.hoehen.contextMenu = QtWidgets.QMenu(self.hoehen) + self.editAction = QtWidgets.QAction("Bearbeiten", self.hoehen.contextMenu) + self.editAction.triggered.connect(self.editHoehen) + self.hoehen.contextMenu.addAction(self.editAction) + self.removeAction = QtWidgets.QAction(u"Löschen", self.hoehen.contextMenu) + self.removeAction.triggered.connect(self.removeHoehen) + self.hoehen.contextMenu.addAction(self.removeAction) + self.newAction = QtWidgets.QAction("Neue externeHoehen", self.hoehen.contextMenu) + self.newAction.triggered.connect(self.newHoehen) + self.hoehen.contextMenu.addAction(self.newAction) + self.buttonBox.button(QtWidgets.QDialogButtonBox.Reset).clicked.connect(self.initialize) + self.initialize() + + def initialize(self): + self.txlFilter.setText("") + #self.btnFilter.setEnabled(False) + self.setTitle = "Hoehenmanager" + self.fillHoehen() + + def fillHoehen(self): + self.hoehen.clear() + filter = self.txlFilter.text() + + if filter == "": + self.hoehenLayer.removeSelection() + self.hoehenLayer.invertSelection() + else: + abfrage = "\"id\" like '%" + filter + "%'" + self.hoehenLayer.selectByExpression(abfrage) + + for aFeat in self.hoehenLayer.selectedFeatures(): + if aFeat.id() > 0: + anItem = QtWidgets.QListWidgetItem(str( ( aFeat["id"], aFeat['hoehenbezug'], aFeat['bezugspunkt'], (aFeat['h'],aFeat['hMin'],aFeat['hMax'],aFeat['hZwingend'])))) + anItem.feature = aFeat + self.hoehen.addItem(anItem) + + self.hoehen.sortItems() + + def editFeature(self, thisFeature): + self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) + self.fillHoehen() + + def editHoehen(self): + self.editFeature(self.hoehen.currentItem().feature) + + def newHoehen(self): + if self.xplanplugin.db == None: + self.showError(u"Es ist keine Datenbank verbunden") + self.done(0) + else: + refSchema = "XP_Basisobjekte" + refTable = "XP_Objekt_hoehenangabe" + hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) + + if hoehenAngLayer != None: + maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, + refTable, pkFieldName = "XP_Objekt_gid") + + if maxId != None: + newFeat = self.xplanplugin.tools.createFeature(hoehenAngLayer) + + if self.xplanplugin.tools.setEditable(hoehenAngLayer, True, self.xplanplugin.iface): + if hoehenAngLayer.addFeature(newFeat): + if hoehenAngLayer.commitChanges(): ## THIS doesn't work, because if using XP_Objekt_hohenangabe, + ## the related XP_Objekt must be known (and associated) already. + ## So wee need a chooser dialog in between + ## ("click the XP_Object you like to relate to"?) + hoehenAngLayer.reload() + self.hoehenLayer.reload() + expr = '"XP_Objekt_gid" > ' + str(maxId) + self.hoehenLayer.selectByExpression(expr) + + if len(self.hoehenLayer.selectedFeatures()) == 1: + thisFeat = self.hoehenLayer.selectedFeatures()[0] + self.editFeature(thisFeat) + else: + self.showError(u"Neues Feature nicht gefunden! " + expr) + else: + self.showError(u"Kann in Tabelle " + refSchema + "." + refTable + \ + u" kein Feature einfügen!") + + def removeHoehen(self): + feat2Remove = self.hoehen.currentItem().feature + + if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): + if self.hoehenLayer.deleteFeature(feat2Remove.id()): + if self.hoehenLayer.commitChanges(): + self.fillHoehen() + else: + self.showError(u"Konnte Änderungen nicht speichern") + else: + self.showError(u"Konnte Hoehen nicht löschen") + else: + self.showError(u"Kann Layer " + self.hoehenLayer.name() + " nicht editieren") + + def showError(self, msg): + self.xplanplugin.tools.showError(msg) + + @QtCore.pyqtSlot( str ) + def on_txlFilter_textChanged(self, currentText): + self.btnFilter.setEnabled(len(currentText) > 0) + + @QtCore.pyqtSlot( ) + def on_txlFilter_returnPressed(self): + if len(self.txlFilter.text()) > 3: + self.btnFilter.click() + + @QtCore.pyqtSlot( ) + def on_btnFilter_clicked(self): + self.fillHoehen() + + @QtCore.pyqtSlot( QtWidgets.QListWidgetItem ) + def on_hoehen_itemDoubleClicked(self, clickedItem): + self.editFeature(clickedItem.feature) + + @QtCore.pyqtSlot( QtCore.QPoint) + def on_hoehen_customContextMenuRequested(self, atPoint): + clickedItem = self.hoehen.itemAt(atPoint) + self.editAction.setVisible(clickedItem != None) + self.removeAction.setVisible(clickedItem != None) + + if clickedItem != None: + self.hoehen.setCurrentItem(clickedItem) + + self.hoehen.contextMenu.resize(self.hoehen.contextMenu.sizeHint()) + self.hoehen.contextMenu.popup(self.hoehen.mapToGlobal(QtCore.QPoint(atPoint))) + + @QtCore.pyqtSlot() + def reject(self): + self.done(0) + class ReferenzmanagerDialog(QtWidgets.QDialog, REFERENZMANAGER_CLASS): def __init__(self, xplanplugin, referenzenLayer): QtWidgets.QDialog.__init__(self) From 51231a1ffaa664eaed34346a3ad632af2a5c8248 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Wed, 25 Jan 2023 13:47:56 +0100 Subject: [PATCH 3/9] Added canvas to Hoehenmanager (for selection, but selection is yet missing) --- .gitignore | 6 +++ Ui_Hoehenmanager.ui | 22 +++++++- XPImport.py | 2 +- XPTools.py | 2 - XPlan.py | 21 ++++---- XPlanDialog.py | 119 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 155 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 3e786b1..428d99e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,9 @@ tools/*.py images/ Ui*.py xplanung.zip +schema/* +__pycache__/* +.settings +.pydevproject +.project +.gitignore \ No newline at end of file diff --git a/Ui_Hoehenmanager.ui b/Ui_Hoehenmanager.ui index 1395007..1cf3ddf 100644 --- a/Ui_Hoehenmanager.ui +++ b/Ui_Hoehenmanager.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 397 + 462 @@ -54,6 +54,16 @@ + + + + + 0 + 250 + + + + @@ -66,6 +76,14 @@ + + + QgsMapCanvas + QWidget +
qgis.gui
+ 1 +
+
diff --git a/XPImport.py b/XPImport.py index 0c0aaff..a80071a 100644 --- a/XPImport.py +++ b/XPImport.py @@ -68,7 +68,7 @@ def importGml(self): commands = ['ogr2ogr'] + arguments fused_command = ' '.join([str(c) for c in commands]) - + self.tools.showWarning(fused_command) try: proc = subprocess.check_output( fused_command, diff --git a/XPTools.py b/XPTools.py index 7987354..dd7c007 100644 --- a/XPTools.py +++ b/XPTools.py @@ -568,8 +568,6 @@ def createFeature(self, layer, fid = None): newFeaturesetId(fid) provider = layer.dataProvider() - - fields = layer.fields() newFeature.initAttributes(fields.count()) diff --git a/XPlan.py b/XPlan.py index f4dceeb..9e392c9 100644 --- a/XPlan.py +++ b/XPlan.py @@ -27,10 +27,8 @@ from qgis.PyQt import QtCore, QtWidgets, QtSql from qgis.core import * from qgis.gui import * -# import importlib try: - ## importlib.reload(DataDrivenInputMask) from DataDrivenInputMask.ddattribute import DdTable except: pass @@ -910,16 +908,21 @@ def loadTable(self, schemaName, tableName, geomColumn, schemaName, tableName, withOid = False, withComment = False) - isView = ddTable == None + isView = ddTable is None if isView: ddTable = DdTable(schemaName = schemaName, tableName = tableName) if self.app.xpManager.existsInDb(ddTable, self.db): - thisLayer = self.app.xpManager.loadPostGISLayer(self.db, - ddTable, displayName = displayName, - geomColumn = geomColumn, keyColumn = "gid", - whereClause = filter, intoDdGroup = False) + thisLayer = self.app.xpManager.loadPostGISLayer( + self.db, + ddTable, + displayName = displayName, + geomColumn = geomColumn, + keyColumn = "gid", + whereClause = filter, + intoDdGroup = False + ) return [thisLayer, isView] @@ -1129,7 +1132,7 @@ def layerStyleSlot(self): self.tools.useStyle(layer, stil) def getLayerForTable(self, schemaName, tableName, - geomColumn = None, showMsg = True): + geomColumn = None, showMsg = True, filterOnNew=""): '''Den Layer schemaName.tableName finden bzw. laden. Wenn geomColumn == None wird geoemtrielos geladen''' @@ -1143,7 +1146,7 @@ def getLayerForTable(self, schemaName, tableName, if layer == None: layer = self.loadTable(schemaName, tableName, - geomColumn = geomColumn)[0] + geomColumn = geomColumn, filter=filterOnNew)[0] if layer == None: if showMsg: diff --git a/XPlanDialog.py b/XPlanDialog.py index a93ad7b..a1802c6 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -21,6 +21,7 @@ """ # Import the PyQt and QGIS libraries from qgis.PyQt import QtCore, QtWidgets, QtSql, uic +from qgis.PyQt.QtWidgets import QAction from builtins import str from builtins import range from qgis.core import * @@ -737,7 +738,7 @@ def accept(self): self.selected = item.id self.done(self.selected) - + class HoehenmanagerDialog(QtWidgets.QDialog, HOEHENMANAGER_CLASS): def __init__(self, xplanplugin, hoehenLayer): QtWidgets.QDialog.__init__(self) @@ -745,6 +746,41 @@ def __init__(self, xplanplugin, hoehenLayer): self.setupUi(self) self.xplanplugin = xplanplugin self.hoehenLayer = hoehenLayer + + #canvas + self.canvas.setCanvasColor(QtCore.Qt.white) #does this work like this? + self.canvas.enableAntiAliasing(True) + + # self.setCentralWidget(self.canvas) + + self.actionZoomIn = QAction("Zoom in", self) + self.actionZoomOut = QAction("Zoom out", self) + self.actionPan = QAction("Pan", self) + + self.actionZoomIn.setCheckable(True) + self.actionZoomOut.setCheckable(True) + self.actionPan.setCheckable(True) + + self.actionZoomIn.triggered.connect(self.zoomIn) + self.actionZoomOut.triggered.connect(self.zoomOut) + self.actionPan.triggered.connect(self.pan) +# + # self.toolbar = self.addToolBar("Canvas actions") + # self.toolbar.addAction(self.actionZoomIn) + # self.toolbar.addAction(self.actionZoomOut) + # self.toolbar.addAction(self.actionPan) + + # create the map tools + self.toolPan = QgsMapToolPan(self.canvas) + self.toolPan.setAction(self.actionPan) + self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in + self.toolZoomIn.setAction(self.actionZoomIn) + self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out + self.toolZoomOut.setAction(self.actionZoomOut) + + self.pan() + #!canvas + self.hoehen.customContextMenuRequested.connect(self.on_hoehen_customContextMenuRequested) self.hoehen.contextMenu = QtWidgets.QMenu(self.hoehen) self.editAction = QtWidgets.QAction("Bearbeiten", self.hoehen.contextMenu) @@ -758,7 +794,16 @@ def __init__(self, xplanplugin, hoehenLayer): self.hoehen.contextMenu.addAction(self.newAction) self.buttonBox.button(QtWidgets.QDialogButtonBox.Reset).clicked.connect(self.initialize) self.initialize() + + def zoomIn(self): + self.canvas.setMapTool(self.toolZoomIn) + + def zoomOut(self): + self.canvas.setMapTool(self.toolZoomOut) + def pan(self): + self.canvas.setMapTool(self.toolPan) + def initialize(self): self.txlFilter.setText("") #self.btnFilter.setEnabled(False) @@ -781,13 +826,77 @@ def fillHoehen(self): anItem = QtWidgets.QListWidgetItem(str( ( aFeat["id"], aFeat['hoehenbezug'], aFeat['bezugspunkt'], (aFeat['h'],aFeat['hMin'],aFeat['hMax'],aFeat['hZwingend'])))) anItem.feature = aFeat self.hoehen.addItem(anItem) + + #necessary data + """ + select * from "XP_Sonstiges"."XP_Hoehenangabe" a + right join + (select * from "XP_Basisobjekte"."XP_Objekt_hoehenangabe") b + on a.id=b.hoehenangabe + right join + (select * from "XP_Basisobjekte"."XP_Objekt") c + on b."XP_Objekt_gid"=c.gid + left join + (select * from "BP_Basisobjekte"."BP_Flaechenobjekte") d + on c.gid=d.gid + --left join + --(select * from "BP_Basisobjekte"."BP_Linienobjekte") e + --on c.gid=e.gid + --left join + --(select * from "BP_Basisobjekte"."BP_Punktobjekte") f + --on c.gid=f.gid + left join + (select * from "XP_Basisobjekte"."XP_Objekt_gehoertZuBereich") g + on c.gid=g."XP_Objekt_gid" + left join + (select gid, nummer, name from "XP_Basisobjekte"."XP_Bereich") h + on g."gehoertZuBereich"=h.gid + """ + # refSchema = "XP_Basisobjekte" + # refTable = "XP_Objekt_hoehenangabe" + # hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) + + + refSchema = "BP_Basisobjekte" + refTable = "BP_Flaechenobjekte" #this is a view for qgis! + if list(self.xplanplugin.aktiveBereicheGids())==[]: + filter='' + else: + filter = self.xplanplugin.getBereichFilter(refSchema, refTable, self.xplanplugin.aktiveBereicheGids()) + # filter = filter + """ AND "Objektartengruppe"=='BP_Bebauung'""" + # self.showError(filter) + # flaechenobjekteLayer = self.xplanplugin.getLayerForTable( + # refSchema, + # refTable, + # # filterOnNew=filter + # ) + flaechenobjekteLayer, isView = self.xplanplugin.loadTable( + refSchema, + refTable, + 'position', + displayName = refTable + " (nur Objektgruppe BP_Bebauung)", + filter = filter + ) + #self.tools.showWarning(u"") + self.canvas.setExtent(flaechenobjekteLayer.extent()) + self.canvas.setLayers([flaechenobjekteLayer]) + # QgsProject.instance().removeMapLayer(flaechenobjekteLayer) + + + # refSchema = "XP_Basisobjekte" + # refTable = "XP_Objekt_hoehenangabe" + # hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) + # self.canvas.setLayers([hoehenAngLayer]) self.hoehen.sortItems() def editFeature(self, thisFeature): self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) self.fillHoehen() - + + def highlightFeature(self, thisFeature): + pass + def editHoehen(self): self.editFeature(self.hoehen.currentItem().feature) @@ -799,7 +908,7 @@ def newHoehen(self): refSchema = "XP_Basisobjekte" refTable = "XP_Objekt_hoehenangabe" hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) - + if hoehenAngLayer != None: maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, refTable, pkFieldName = "XP_Objekt_gid") @@ -860,6 +969,10 @@ def on_btnFilter_clicked(self): @QtCore.pyqtSlot( QtWidgets.QListWidgetItem ) def on_hoehen_itemDoubleClicked(self, clickedItem): self.editFeature(clickedItem.feature) + + @QtCore.pyqtSlot( QtWidgets.QListWidgetItem ) + def on_hoehen_itemClicked(self, clickedItem): + self.highlightFeature(clickedItem.feature) @QtCore.pyqtSlot( QtCore.QPoint) def on_hoehen_customContextMenuRequested(self, atPoint): From ab2eac1740660d43fd13b0096fafb09a07505ad9 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Thu, 26 Jan 2023 15:39:15 +0100 Subject: [PATCH 4/9] =?UTF-8?q?Die=20Bearbeitung=20von=20H=C3=B6henangaben?= =?UTF-8?q?=20ist=20jetzt=20m=C3=B6glich.=20Neue=20anlegen=20noch=20nicht.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ui_Hoehenmanager.ui | 20 ++-- XPlan.py | 3 +- XPlanDialog.py | 258 ++++++++++++++++++++++++++++---------------- 3 files changed, 178 insertions(+), 103 deletions(-) diff --git a/Ui_Hoehenmanager.ui b/Ui_Hoehenmanager.ui index 1cf3ddf..696661e 100644 --- a/Ui_Hoehenmanager.ui +++ b/Ui_Hoehenmanager.ui @@ -41,6 +41,16 @@ + + + + + 0 + 250 + + + + @@ -54,16 +64,6 @@ - - - - - 0 - 250 - - - - diff --git a/XPlan.py b/XPlan.py index 9e392c9..24bcd92 100644 --- a/XPlan.py +++ b/XPlan.py @@ -716,7 +716,8 @@ def hoehenmanagerStarten(self): refSchema = "XP_Sonstiges" refTable = "XP_Hoehenangabe" extRefLayer = self.getLayerForTable(refSchema, refTable) - + # self.tools.debug(str(type(extRefLayer))) + if extRefLayer != None: self.app.xpManager.moveLayerToGroup(extRefLayer, refSchema) dlg = HoehenmanagerDialog(self, extRefLayer) diff --git a/XPlanDialog.py b/XPlanDialog.py index a1802c6..1cb71e6 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -115,7 +115,7 @@ def initialize(self): parentItem.addChild(childItem) query.finish() else: - self.showQueryError(query) + self.xplanplugin.tools.showQueryError(query) query.finish() self.layerChooser.resizeColumnToContents(0) @@ -739,60 +739,98 @@ def accept(self): self.done(self.selected) + + class HoehenmanagerDialog(QtWidgets.QDialog, HOEHENMANAGER_CLASS): + + class featureSelector(QgsMapToolIdentifyFeature): + + def __init__(self, canvas, layer, manager): + super().__init__(canvas) + self.layer = layer + self.manager = manager + + def canvasReleaseEvent(self, e): + super().canvasReleaseEvent(e) + ident_result = self.identify( + e.pixelPoint().x(), + e.pixelPoint().y(), + mode = self.IdentifyMode(3), + layerList= [self.layer] + ) + if len(ident_result)>0: + sfeature = ident_result[0].mFeature + self.manager.selectedFeature = sfeature + self.featureIdentified.emit(sfeature) + def __init__(self, xplanplugin, hoehenLayer): QtWidgets.QDialog.__init__(self) # Set up the user interface from Designer. self.setupUi(self) self.xplanplugin = xplanplugin self.hoehenLayer = hoehenLayer + self.selectedFeature = None + self.relator = None #canvas + refSchema = "BP_Basisobjekte" + refTable = "BP_Flaechenobjekte" #this is a view for qgis! + if list(self.xplanplugin.aktiveBereicheGids())==[]: + filter='' + else: + filter = self.xplanplugin.getBereichFilter(refSchema, refTable, self.xplanplugin.aktiveBereicheGids()) + self.flaechenobjekteLayer, isView = self.xplanplugin.loadTable( + refSchema, + refTable, + 'position', + displayName = refTable + " (für Höheneditor - temporär)", + filter = filter + ) + self.canvas.setExtent(self.flaechenobjekteLayer.extent()) + self.canvas.setLayers([self.flaechenobjekteLayer]) + # QgsProject.instance().removeMapLayer(flaechenobjekteLayer) self.canvas.setCanvasColor(QtCore.Qt.white) #does this work like this? self.canvas.enableAntiAliasing(True) - # self.setCentralWidget(self.canvas) - + # create the map tools self.actionZoomIn = QAction("Zoom in", self) - self.actionZoomOut = QAction("Zoom out", self) - self.actionPan = QAction("Pan", self) - - self.actionZoomIn.setCheckable(True) - self.actionZoomOut.setCheckable(True) - self.actionPan.setCheckable(True) - self.actionZoomIn.triggered.connect(self.zoomIn) - self.actionZoomOut.triggered.connect(self.zoomOut) - self.actionPan.triggered.connect(self.pan) -# - # self.toolbar = self.addToolBar("Canvas actions") - # self.toolbar.addAction(self.actionZoomIn) - # self.toolbar.addAction(self.actionZoomOut) - # self.toolbar.addAction(self.actionPan) - - # create the map tools - self.toolPan = QgsMapToolPan(self.canvas) - self.toolPan.setAction(self.actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in self.toolZoomIn.setAction(self.actionZoomIn) + + self.actionZoomOut = QAction("Zoom out", self) + self.actionZoomOut.triggered.connect(self.zoomOut) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out self.toolZoomOut.setAction(self.actionZoomOut) - - self.pan() + + self.actionPan = QAction("Pan", self) + self.actionPan.triggered.connect(self.pan) + self.toolPan = QgsMapToolPan(self.canvas) + self.toolPan.setAction(self.actionPan) + + self.toolIdentify = self.featureSelector(self.canvas, self.flaechenobjekteLayer, self) + self.toolIdentify.featureIdentified.connect(self.showRelatedHoehen) + + self.identify() #!canvas self.hoehen.customContextMenuRequested.connect(self.on_hoehen_customContextMenuRequested) self.hoehen.contextMenu = QtWidgets.QMenu(self.hoehen) + self.editAction = QtWidgets.QAction("Bearbeiten", self.hoehen.contextMenu) self.editAction.triggered.connect(self.editHoehen) self.hoehen.contextMenu.addAction(self.editAction) + self.removeAction = QtWidgets.QAction(u"Löschen", self.hoehen.contextMenu) self.removeAction.triggered.connect(self.removeHoehen) self.hoehen.contextMenu.addAction(self.removeAction) + self.newAction = QtWidgets.QAction("Neue externeHoehen", self.hoehen.contextMenu) self.newAction.triggered.connect(self.newHoehen) self.hoehen.contextMenu.addAction(self.newAction) + self.buttonBox.button(QtWidgets.QDialogButtonBox.Reset).clicked.connect(self.initialize) + self.initialize() def zoomIn(self): @@ -803,94 +841,130 @@ def zoomOut(self): def pan(self): self.canvas.setMapTool(self.toolPan) + + def identify(self): + self.canvas.setMapTool(self.toolIdentify) + + def showRelatedHoehen(self, sfeature): + """Code called when the feature is selected by the user""" + self.selectedFeature = sfeature + self.flaechenobjekteLayer.deselect(self.flaechenobjekteLayer.selectedFeatureIds()) + self.flaechenobjekteLayer.select([sfeature.id()]) #id is correct + self.fillHoehen([sfeature['gid']]) #gid is correct + + def unselectFeature(self): + self.flaechenobjekteLayer.removeSelection() def initialize(self): self.txlFilter.setText("") #self.btnFilter.setEnabled(False) self.setTitle = "Hoehenmanager" self.fillHoehen() - - def fillHoehen(self): + + def getRelatorTable(self): + sql = """ +SELECT + a.id, + --a.*, + b."XP_Objekt_gid", + --c.uuid, c.gml_id, + --d.position as geom_poly, + --e.position as geom_line, + --f.position as geom_point, + g."gehoertZuBereich"--, + --h."nummer" as nr_bereich, h."name" as name_bereich +FROM +(select * from "XP_Sonstiges"."XP_Hoehenangabe") a + right join +(select * from "XP_Basisobjekte"."XP_Objekt_hoehenangabe") b +on a.id=b.hoehenangabe + left join +(select * from "XP_Basisobjekte"."XP_Objekt") c +on b."XP_Objekt_gid"=c.gid +-- left join +--(select * from "BP_Basisobjekte"."BP_Flaechenobjekte") d +--on c.gid=d.gid +-- left join +--(select * from "BP_Basisobjekte"."BP_Linienobjekte") e +--on c.gid=e.gid +-- left join +--(select * from "BP_Basisobjekte"."BP_Punktobjekte") f +--on c.gid=f.gid + left join +(select * from "XP_Basisobjekte"."XP_Objekt_gehoertZuBereich") g +on c.gid=g."XP_Objekt_gid" + left join +(select gid, nummer, name from "XP_Basisobjekte"."XP_Bereich") h +on g."gehoertZuBereich"=h.gid +""" + addendum = """where "gehoertZuBereich" = ANY( {}::int[] ); + """.format("'" + str(tuple(self.xplanplugin.aktiveBereicheGids())).replace('(','{').rsplit(',',1)[0] + "}'") + if (len(self.xplanplugin.aktiveBereicheGids())>0): + sql = sql + addendum + # self.showError(sql) + + if (self.relator is None): + query = QtSql.QSqlQuery(self.xplanplugin.db) + query.prepare(sql) + query.exec_() + + if query.isActive(): + table = {} + lastId = -1 + while query.next(): # returns false when all records are done + rec_dict = {} + for i in range(query.record().count()): + rec_dict[query.record().field(i).name()] = query.record().value(i) + table[query.record().value("id")] = rec_dict + lastId = query.record().value("id") + + query.finish() + self.relator = table, lastId + return self.relator + else: + self.xplanplugin.tools.showQueryError(query) + return None + else: + # self.showError('relator is loaded from cache') + return self.relator + + def fillHoehen(self, xp_objekt_gids =[]): self.hoehen.clear() filter = self.txlFilter.text() - + if filter == "": self.hoehenLayer.removeSelection() self.hoehenLayer.invertSelection() else: abfrage = "\"id\" like '%" + filter + "%'" self.hoehenLayer.selectByExpression(abfrage) - - for aFeat in self.hoehenLayer.selectedFeatures(): - if aFeat.id() > 0: - anItem = QtWidgets.QListWidgetItem(str( ( aFeat["id"], aFeat['hoehenbezug'], aFeat['bezugspunkt'], (aFeat['h'],aFeat['hMin'],aFeat['hMax'],aFeat['hZwingend'])))) - anItem.feature = aFeat - self.hoehen.addItem(anItem) - - #necessary data - """ - select * from "XP_Sonstiges"."XP_Hoehenangabe" a - right join - (select * from "XP_Basisobjekte"."XP_Objekt_hoehenangabe") b - on a.id=b.hoehenangabe - right join - (select * from "XP_Basisobjekte"."XP_Objekt") c - on b."XP_Objekt_gid"=c.gid - left join - (select * from "BP_Basisobjekte"."BP_Flaechenobjekte") d - on c.gid=d.gid - --left join - --(select * from "BP_Basisobjekte"."BP_Linienobjekte") e - --on c.gid=e.gid - --left join - --(select * from "BP_Basisobjekte"."BP_Punktobjekte") f - --on c.gid=f.gid - left join - (select * from "XP_Basisobjekte"."XP_Objekt_gehoertZuBereich") g - on c.gid=g."XP_Objekt_gid" - left join - (select gid, nummer, name from "XP_Basisobjekte"."XP_Bereich") h - on g."gehoertZuBereich"=h.gid - """ - # refSchema = "XP_Basisobjekte" - # refTable = "XP_Objekt_hoehenangabe" - # hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) - - refSchema = "BP_Basisobjekte" - refTable = "BP_Flaechenobjekte" #this is a view for qgis! - if list(self.xplanplugin.aktiveBereicheGids())==[]: - filter='' + try: + relator, lastId = self.getRelatorTable() + except TypeError as e: + self.showError('An TypeError occured unexpected. Please fix this!') + relator = self.getRelatorTable() + relator_selector = {} else: - filter = self.xplanplugin.getBereichFilter(refSchema, refTable, self.xplanplugin.aktiveBereicheGids()) - # filter = filter + """ AND "Objektartengruppe"=='BP_Bebauung'""" - # self.showError(filter) - # flaechenobjekteLayer = self.xplanplugin.getLayerForTable( - # refSchema, - # refTable, - # # filterOnNew=filter - # ) - flaechenobjekteLayer, isView = self.xplanplugin.loadTable( - refSchema, - refTable, - 'position', - displayName = refTable + " (nur Objektgruppe BP_Bebauung)", - filter = filter - ) - #self.tools.showWarning(u"") - self.canvas.setExtent(flaechenobjekteLayer.extent()) - self.canvas.setLayers([flaechenobjekteLayer]) - # QgsProject.instance().removeMapLayer(flaechenobjekteLayer) - + if (xp_objekt_gids==[]): + relator_selector = relator + else: + relator_selector = {k: v for k, v in relator.items() if v['XP_Objekt_gid'] in xp_objekt_gids} - # refSchema = "XP_Basisobjekte" - # refTable = "XP_Objekt_hoehenangabe" - # hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) - # self.canvas.setLayers([hoehenAngLayer]) - + for i, aFeat in enumerate(self.hoehenLayer.selectedFeatures()): + # self.showError('feat nr: ' + str(i)) + # self.showError('id: ' + str(aFeat["id"])) + if aFeat.id() > 0 and aFeat["id"] in relator_selector.keys(): + # if xp_objekt_gids!=[]: self.showError('found id: ' + str(aFeat["id"])) + anItem = QtWidgets.QListWidgetItem(str( ( aFeat["id"], aFeat['hoehenbezug'], aFeat['bezugspunkt'], (aFeat['h'],aFeat['hMin'],aFeat['hMax'],aFeat['hZwingend'])))) + anItem.feature = aFeat + self.hoehen.addItem(anItem) self.hoehen.sortItems() - + def editFeature(self, thisFeature): + # self.showError(str(thisFeature.id())) + # self.showError(str(thisFeature.attributes())) + # self.showError(str(self.hoehenLayer)) self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) self.fillHoehen() From 47ec7b548dfc1164c624a359ddedecae39ea8b67 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Thu, 26 Jan 2023 16:52:12 +0100 Subject: [PATCH 5/9] almost there with new Hoehen, but only almost... --- XPTools.py | 2 +- XPlanDialog.py | 89 +++++++++++++++++++++++++++++++------------------- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/XPTools.py b/XPTools.py index dd7c007..c9238bb 100644 --- a/XPTools.py +++ b/XPTools.py @@ -565,7 +565,7 @@ def createFeature(self, layer, fid = None): newFeature = QgsVectorLayerUtils.createFeature(layer) if fid: - newFeaturesetId(fid) + newFeaturesetId(fid) #is this defined? provider = layer.dataProvider() fields = layer.fields() diff --git a/XPlanDialog.py b/XPlanDialog.py index 1cb71e6..373da19 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -845,8 +845,9 @@ def pan(self): def identify(self): self.canvas.setMapTool(self.toolIdentify) - def showRelatedHoehen(self, sfeature): + def showRelatedHoehen(self, sfeature=None): """Code called when the feature is selected by the user""" + if sfeature is None: sfeature =self.selectedFeature self.selectedFeature = sfeature self.flaechenobjekteLayer.deselect(self.flaechenobjekteLayer.selectedFeatureIds()) self.flaechenobjekteLayer.select([sfeature.id()]) #id is correct @@ -966,7 +967,7 @@ def editFeature(self, thisFeature): # self.showError(str(thisFeature.attributes())) # self.showError(str(self.hoehenLayer)) self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) - self.fillHoehen() + self.showRelatedHoehen() def highlightFeature(self, thisFeature): pass @@ -979,44 +980,67 @@ def newHoehen(self): self.showError(u"Es ist keine Datenbank verbunden") self.done(0) else: - refSchema = "XP_Basisobjekte" - refTable = "XP_Objekt_hoehenangabe" - hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) + if not (self.selectedFeature is None): + + firstItem = next(self.hoehenLayer.getFeatures()) + self.showError(str(dict(firstItem.attributeMap()))) + newFeat = QgsFeature(firstItem.fields(),-1) + + if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): + self.hoehenLayer.addFeature(newFeat) + if self.hoehenLayer.commitChanges(): + maxIdHoehe = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Sonstiges", + "XP_Hoehenangabe", pkFieldName = "id") + expr = '"id" >= ' + str(maxIdHoehe) + self.hoehenLayer.selectByExpression(expr) + + if len(self.hoehenLayer.selectedFeatures()) == 1: + thisFeat = self.hoehenLayer.selectedFeatures()[0] + self.editFeature(thisFeat) + + + refSchema = "XP_Basisobjekte" + refTable = "XP_Objekt_hoehenangabe" + hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) + + if hoehenAngLayer != None: + maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, + refTable, pkFieldName = "XP_Objekt_gid") + + if not (maxId is None): + newLink = self.xplanplugin.tools.createFeature(hoehenAngLayer) + newLink.setAttribute("XP_Objekt_gid", self.selectedFeature['gid']) + newLink.setAttribute("hoehenangabe", thisFeat['id']) + + if self.xplanplugin.tools.setEditable(hoehenAngLayer, True, self.xplanplugin.iface): + if hoehenAngLayer.addFeature(newLink): + + if hoehenAngLayer.commitChanges(): ## THIS doesn't work, because if using XP_Objekt_hohenangabe, + ## the related XP_Objekt must be known (and associated) already. + ## So wee need a chooser dialog in between + ## ("click the XP_Object you like to relate to"?) + hoehenAngLayer.reload() + expr = '"XP_Objekt_gid" >= ' + str(maxId) + hoehenAngLayer.selectByExpression(expr) - if hoehenAngLayer != None: - maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, - refTable, pkFieldName = "XP_Objekt_gid") - - if maxId != None: - newFeat = self.xplanplugin.tools.createFeature(hoehenAngLayer) - - if self.xplanplugin.tools.setEditable(hoehenAngLayer, True, self.xplanplugin.iface): - if hoehenAngLayer.addFeature(newFeat): - if hoehenAngLayer.commitChanges(): ## THIS doesn't work, because if using XP_Objekt_hohenangabe, - ## the related XP_Objekt must be known (and associated) already. - ## So wee need a chooser dialog in between - ## ("click the XP_Object you like to relate to"?) - hoehenAngLayer.reload() - self.hoehenLayer.reload() - expr = '"XP_Objekt_gid" > ' + str(maxId) - self.hoehenLayer.selectByExpression(expr) - - if len(self.hoehenLayer.selectedFeatures()) == 1: - thisFeat = self.hoehenLayer.selectedFeatures()[0] - self.editFeature(thisFeat) + if len(hoehenAngLayer.selectedFeatures()) == 1: + linkFeat = hoehenAngLayer.selectedFeatures()[0] + self.editFeature(linkFeat) + else: + self.showError(u"Neues Feature nicht gefunden! " + expr) + else: + self.showError(u"Kann in Tabelle " + refSchema + "." + refTable + \ + u" kein Feature einfügen!") else: - self.showError(u"Neues Feature nicht gefunden! " + expr) - else: - self.showError(u"Kann in Tabelle " + refSchema + "." + refTable + \ - u" kein Feature einfügen!") - + self.showError(u"Zuerst muss ein Bezugsobjekt auf der Karte ausgewählt werden!") + def removeHoehen(self): feat2Remove = self.hoehen.currentItem().feature if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): if self.hoehenLayer.deleteFeature(feat2Remove.id()): if self.hoehenLayer.commitChanges(): - self.fillHoehen() + self.showRelatedHoehen() else: self.showError(u"Konnte Änderungen nicht speichern") else: @@ -1132,7 +1156,6 @@ def newReferenz(self): if maxId != None: newFeat = self.xplanplugin.tools.createFeature(extRefLayer) - if self.xplanplugin.tools.setEditable(extRefLayer, True, self.xplanplugin.iface): if extRefLayer.addFeature(newFeat): if extRefLayer.commitChanges(): From 10c0f54c96d4295c5e6b0d89c8fef241d207a945 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Fri, 27 Jan 2023 11:00:29 +0100 Subject: [PATCH 6/9] New heights can be added, edited, but yet not deleted. BP_Flaechenobjekte is now reused if already in layer list. --- Ui_Hoehenmanager.ui | 13 +++++++ XPlan.py | 68 +++++++++++++++++++++++++++------ XPlanDialog.py | 92 +++++++++++++++++++++++++-------------------- 3 files changed, 122 insertions(+), 51 deletions(-) diff --git a/Ui_Hoehenmanager.ui b/Ui_Hoehenmanager.ui index 696661e..be0f057 100644 --- a/Ui_Hoehenmanager.ui +++ b/Ui_Hoehenmanager.ui @@ -41,6 +41,19 @@ + + + + Bitte wählen Sie ein Flächenobjekt aus, um die dazugehörige Höhe zu bearbeiten bzw. ein neues Höhenobjekt anzulegen. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + diff --git a/XPlan.py b/XPlan.py index 24bcd92..0ca8760 100644 --- a/XPlan.py +++ b/XPlan.py @@ -1132,30 +1132,76 @@ def layerStyleSlot(self): if stil != None: self.tools.useStyle(layer, stil) - def getLayerForTable(self, schemaName, tableName, - geomColumn = None, showMsg = True, filterOnNew=""): + def findPostgresLayer(self, db, ddTable=None, schemaName=None, tableName=None): + """partly borrowed from ddmanager""" + if not (ddTable is None): + return self.app.xpManager.findPostgresLayer(self.db, ddTable) + elif not (schemaName is None or tableName is None): + for aTreeLayer in QgsProject.instance().layerTreeRoot().findLayers(): + layer = aTreeLayer.layer() + if not (layer is None): + if 0 == layer.type(): # vectorLayer + src = layer.source() + if ( + ("table=\"" + schemaName + "\".\"" + tableName + "\"" in src) and + (db.databaseName() in src) and + (db.hostName() in src) + ): + return layer + return None + else: + return None + + def getQgisLayerForTable(self, schemaName, tableName, **kwargs): + """workaround name for method""" + kwargs['ignoreDD']=True + return self.getLayerForTable(schemaName, tableName, **kwargs) + + def getDDCoveredLayerForTable(self, schemaName, tableName, **kwargs): + """more name for method""" + kwargs['ignoreDD']=False + return self.getLayerForTable(schemaName, tableName, **kwargs) + + def getLayerForTable(self, schemaName, tableName, **kwargs): '''Den Layer schemaName.tableName finden bzw. laden. Wenn geomColumn == None wird geoemtrielos geladen''' - + + #manage defaults/kwargs + geomColumn = kwargs.get('geomColumn', None) + showMsg = kwargs.get('showMsg', True) + filterOnNew = kwargs.get('filterOnNew', "") + displayName = kwargs.get('displayName', None) + ignoreDD = kwargs.get('ignoreDD', False) + #end kwargs + + if displayName is None: + displayName = tableName ddTable = self.app.xpManager.createDdTable( self.db, schemaName, tableName, withOid = False, withComment = False) - if ddTable != None: - layer = self.app.xpManager.findPostgresLayer( - self.db, ddTable) - - if layer == None: - layer = self.loadTable(schemaName, tableName, - geomColumn = geomColumn, filter=filterOnNew)[0] + if (not (ddTable is None)) or ignoreDD: + layer = self.findPostgresLayer( + self.db, ddTable, schemaName=schemaName, tableName=tableName) + + if layer is None: + layer = self.loadTable( + schemaName, + tableName, + geomColumn = geomColumn, + filter=filterOnNew, + displayName=displayName + )[0] - if layer == None: + if layer is None: if showMsg: XpError(u"Kann Tabelle %(schema)s.%(table)s nicht laden!" % \ {"schema":schemaName, "table":tableName}, self.iface) return None else: + self.app.xpManager.createGroup(schemaName, False) #doesn't add group if already exists. + self.app.xpManager.moveLayerToGroup(layer, schemaName) return layer else: return layer diff --git a/XPlanDialog.py b/XPlanDialog.py index 373da19..fd92915 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -779,12 +779,15 @@ def __init__(self, xplanplugin, hoehenLayer): filter='' else: filter = self.xplanplugin.getBereichFilter(refSchema, refTable, self.xplanplugin.aktiveBereicheGids()) - self.flaechenobjekteLayer, isView = self.xplanplugin.loadTable( + # self.flaechenobjekteLayer, isView = self.xplanplugin.loadTable( + self.flaechenobjekteLayer = self.xplanplugin.getQgisLayerForTable( + # self, schemaName, tableName, geomColumn = None, showMsg = True, filterOnNew=""): refSchema, refTable, - 'position', + geomColumn='position', displayName = refTable + " (für Höheneditor - temporär)", - filter = filter + # filter=filter, + filterOnNew = filter ) self.canvas.setExtent(self.flaechenobjekteLayer.extent()) self.canvas.setLayers([self.flaechenobjekteLayer]) @@ -966,7 +969,14 @@ def editFeature(self, thisFeature): # self.showError(str(thisFeature.id())) # self.showError(str(thisFeature.attributes())) # self.showError(str(self.hoehenLayer)) - self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) + try: + self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) + except Exception as e: + self.showError(str(e)) + self.showError(str(thisFeature.attributeMap())) + self.showError(str(self.xplanplugin.db)) + self.showError(str(self.hoehenLayer)) + raise e self.showRelatedHoehen() def highlightFeature(self, thisFeature): @@ -981,14 +991,15 @@ def newHoehen(self): self.done(0) else: if not (self.selectedFeature is None): - firstItem = next(self.hoehenLayer.getFeatures()) - self.showError(str(dict(firstItem.attributeMap()))) + # self.showError(str(dict(firstItem.attributeMap()))) newFeat = QgsFeature(firstItem.fields(),-1) - if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): self.hoehenLayer.addFeature(newFeat) + # there should be a block on the db enabled here, so we really get our maxId + # not the one added by an other person simultaniously... if self.hoehenLayer.commitChanges(): + maxIdHoehe = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Sonstiges", "XP_Hoehenangabe", pkFieldName = "id") expr = '"id" >= ' + str(maxIdHoehe) @@ -999,40 +1010,41 @@ def newHoehen(self): self.editFeature(thisFeat) - refSchema = "XP_Basisobjekte" - refTable = "XP_Objekt_hoehenangabe" - hoehenAngLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) - - if hoehenAngLayer != None: - maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, - refTable, pkFieldName = "XP_Objekt_gid") - - if not (maxId is None): - newLink = self.xplanplugin.tools.createFeature(hoehenAngLayer) - newLink.setAttribute("XP_Objekt_gid", self.selectedFeature['gid']) - newLink.setAttribute("hoehenangabe", thisFeat['id']) - - if self.xplanplugin.tools.setEditable(hoehenAngLayer, True, self.xplanplugin.iface): - if hoehenAngLayer.addFeature(newLink): - - if hoehenAngLayer.commitChanges(): ## THIS doesn't work, because if using XP_Objekt_hohenangabe, - ## the related XP_Objekt must be known (and associated) already. - ## So wee need a chooser dialog in between - ## ("click the XP_Object you like to relate to"?) - hoehenAngLayer.reload() - expr = '"XP_Objekt_gid" >= ' + str(maxId) - hoehenAngLayer.selectByExpression(expr) - - if len(hoehenAngLayer.selectedFeatures()) == 1: - linkFeat = hoehenAngLayer.selectedFeatures()[0] - self.editFeature(linkFeat) - else: - self.showError(u"Neues Feature nicht gefunden! " + expr) + refSchema = "XP_Basisobjekte" + refTable = "XP_Objekt_hoehenangabe" + linkLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) + + if linkLayer != None: + maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, + refTable, pkFieldName = "XP_Objekt_gid") + + if not (maxId is None): + newLink = self.xplanplugin.tools.createFeature(linkLayer) + newLink.setAttribute("XP_Objekt_gid", self.selectedFeature['gid']) + newLink.setAttribute("hoehenangabe", thisFeat['id']) + + if self.xplanplugin.tools.setEditable(linkLayer, True, self.xplanplugin.iface): + if linkLayer.addFeature(newLink): + + if linkLayer.commitChanges(): ## THIS doesn't work, because if using XP_Objekt_hohenangabe, + ## the related XP_Objekt must be known (and associated) already. + ## So wee need a chooser dialog in between + ## ("click the XP_Object you like to relate to"?) + linkLayer.reload() + expr = '"XP_Objekt_gid" >= ' + str(maxId) + linkLayer.selectByExpression(expr) + + if len(linkLayer.selectedFeatures()) == 1: + self.showError(u"Zuordnung Höhe->Flächenobjekt wurde eingefügt") + # linkFeat = hoehenAngLayer.selectedFeatures()[0] + # self.editFeature(linkFeat) + else: + self.showError(u"Neues Feature nicht gefunden! " + expr) + else: + self.showError(u"Kann in Tabelle " + refSchema + "." + refTable + \ + u" kein Feature einfügen!") else: - self.showError(u"Kann in Tabelle " + refSchema + "." + refTable + \ - u" kein Feature einfügen!") - else: - self.showError(u"Zuerst muss ein Bezugsobjekt auf der Karte ausgewählt werden!") + self.showError(u"Zuerst muss ein Bezugsobjekt auf der Karte ausgewählt werden!") def removeHoehen(self): feat2Remove = self.hoehen.currentItem().feature From b4dadbd06228e783bcd924b7ca9c258589951633 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Fri, 27 Jan 2023 11:40:45 +0100 Subject: [PATCH 7/9] deletion should work now, but some testing is required, as we use connection to dd occasionally. --- XPlan.py | 11 ++++--- XPlanDialog.py | 78 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/XPlan.py b/XPlan.py index 0ca8760..de7e4cb 100644 --- a/XPlan.py +++ b/XPlan.py @@ -1181,8 +1181,10 @@ def getLayerForTable(self, schemaName, tableName, **kwargs): withOid = False, withComment = False) if (not (ddTable is None)) or ignoreDD: - layer = self.findPostgresLayer( - self.db, ddTable, schemaName=schemaName, tableName=tableName) + layer = self.findPostgresLayer( #not using app.xpManager/ddmanager directly + self.db, + ddTable, #if not None, following parameters are ignored + schemaName=schemaName, tableName=tableName) if layer is None: layer = self.loadTable( @@ -1200,8 +1202,9 @@ def getLayerForTable(self, schemaName, tableName, **kwargs): self.iface) return None else: - self.app.xpManager.createGroup(schemaName, False) #doesn't add group if already exists. - self.app.xpManager.moveLayerToGroup(layer, schemaName) + if (ddTable is None): #for views + self.app.xpManager.createGroup(schemaName, False) #doesn't add group if already exists. + self.app.xpManager.moveLayerToGroup(layer, schemaName) return layer else: return layer diff --git a/XPlanDialog.py b/XPlanDialog.py index fd92915..d007931 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -789,6 +789,11 @@ def __init__(self, xplanplugin, hoehenLayer): # filter=filter, filterOnNew = filter ) + + linkSchema = "XP_Basisobjekte" + linkTable = "XP_Objekt_hoehenangabe" + self.linkLayer = self.xplanplugin.getDDCoveredLayerForTable(linkSchema, linkTable) + self.canvas.setExtent(self.flaechenobjekteLayer.extent()) self.canvas.setLayers([self.flaechenobjekteLayer]) # QgsProject.instance().removeMapLayer(flaechenobjekteLayer) @@ -974,8 +979,7 @@ def editFeature(self, thisFeature): except Exception as e: self.showError(str(e)) self.showError(str(thisFeature.attributeMap())) - self.showError(str(self.xplanplugin.db)) - self.showError(str(self.hoehenLayer)) + self.showError(str(self.hoehenLayer.name())) raise e self.showRelatedHoehen() @@ -1008,33 +1012,25 @@ def newHoehen(self): if len(self.hoehenLayer.selectedFeatures()) == 1: thisFeat = self.hoehenLayer.selectedFeatures()[0] self.editFeature(thisFeat) - - - refSchema = "XP_Basisobjekte" - refTable = "XP_Objekt_hoehenangabe" - linkLayer = self.xplanplugin.getLayerForTable(refSchema, refTable) - if linkLayer != None: - maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, refSchema, - refTable, pkFieldName = "XP_Objekt_gid") + if self.linkLayer != None: + maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Basisobjekte", + "XP_Objekt_hoehenangabe", pkFieldName = "XP_Objekt_gid") if not (maxId is None): newLink = self.xplanplugin.tools.createFeature(linkLayer) newLink.setAttribute("XP_Objekt_gid", self.selectedFeature['gid']) newLink.setAttribute("hoehenangabe", thisFeat['id']) - if self.xplanplugin.tools.setEditable(linkLayer, True, self.xplanplugin.iface): - if linkLayer.addFeature(newLink): + if self.xplanplugin.tools.setEditable(self.linkLayer, True, self.xplanplugin.iface): + if self.linkLayer.addFeature(newLink): - if linkLayer.commitChanges(): ## THIS doesn't work, because if using XP_Objekt_hohenangabe, - ## the related XP_Objekt must be known (and associated) already. - ## So wee need a chooser dialog in between - ## ("click the XP_Object you like to relate to"?) - linkLayer.reload() + if self.linkLayer.commitChanges(): + self.linkLayer.reload() expr = '"XP_Objekt_gid" >= ' + str(maxId) - linkLayer.selectByExpression(expr) + self.linkLayer.selectByExpression(expr) - if len(linkLayer.selectedFeatures()) == 1: + if len(self.linkLayer.selectedFeatures()) == 1: self.showError(u"Zuordnung Höhe->Flächenobjekt wurde eingefügt") # linkFeat = hoehenAngLayer.selectedFeatures()[0] # self.editFeature(linkFeat) @@ -1048,17 +1044,45 @@ def newHoehen(self): def removeHoehen(self): feat2Remove = self.hoehen.currentItem().feature - - if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): - if self.hoehenLayer.deleteFeature(feat2Remove.id()): - if self.hoehenLayer.commitChanges(): - self.showRelatedHoehen() + + """Erst Link(s) zerstören...""" + if not (self.linkLayer is None): + expr = '"hoehenangabe" = ' + str(feat2remove['id']) + self.linkLayer.selectByExpression(expr) + if self.xplanplugin.tools.setEditable(self.linkLayer, True, self.xplanplugin.iface): + if ( + (self.selectedFeature is None) or # makes sure entries with a 1:m relation can only be deleted, if no Flächenobjekt is selected. or + len(self.linkLayer.selectedFeatures()) == 1 #fallback: makes sure only entries with a 1:1 relation are deleted easily + ): + for link2remove in self.linkLayer.selectedFeatures(): + if self.linkLayer.deleteFeature(link2remove['id']): + if self.linkLayer.commitChanges(): + self.linkLayer.reload() + self.showRelatedHoehen() + + """... dann die eigenentliche Hoehenangabe entfernen""" + if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): + if self.hoehenLayer.deleteFeature(feat2Remove.id()): + if self.hoehenLayer.commitChanges(): + self.showRelatedHoehen() + else: + self.showError(u"Konnte Änderungen nicht speichern") + else: + self.showError(u"Konnte Hoehen nicht löschen") + else: + self.showError(u"Kann Layer " + self.hoehenLayer.name() + u" nicht editieren") + + else: + self.showError(u"Konnte Änderungen in der LinkTabelle nicht speichern") else: - self.showError(u"Konnte Änderungen nicht speichern") + #todo: create button for deselect + self.showError('Die ausgewählte Höhenangabe wird von mehreren Flächenobjekten referenziert und kann aus Sicherheitsgründen nur gelöscht werden, wenn oben in der Karte kein Flächenobjekt ausgewählt ist.') else: - self.showError(u"Konnte Hoehen nicht löschen") + self.showError(u"Kann Layer " + self.linkLayer.name() + u" nicht editieren") else: - self.showError(u"Kann Layer " + self.hoehenLayer.name() + " nicht editieren") + self.showError('') + + def showError(self, msg): self.xplanplugin.tools.showError(msg) From a162ac49b9fb3558878dfe6cb56cfdd378887a08 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Mon, 6 Feb 2023 15:18:28 +0100 Subject: [PATCH 8/9] beta-testing will start soon (some refresh-glitches still left to do) --- XPTools.py | 14 ++++- XPlan.py | 26 ++++---- XPlanDialog.py | 159 +++++++++++++++++++++++++++++++++---------------- 3 files changed, 136 insertions(+), 63 deletions(-) diff --git a/XPTools.py b/XPTools.py index c9238bb..5f9f03d 100644 --- a/XPTools.py +++ b/XPTools.py @@ -31,6 +31,10 @@ from .XPlanDialog import BereichsauswahlDialog from .XPlanDialog import StilauswahlDialog +from traceback import format_stack +import inspect +from pprint import pformat + class XPTools(): def __init__(self, iface, standardName, simpleStyleName): self.iface = iface @@ -649,9 +653,15 @@ def showWarning(self, msg, title = "XPlanung"): #self.log(msg, "warn") def showError(self, msg, title = "XPlanung"): + t_ = [ + x[0].f_locals for x in inspect.trace() + ] + if len(t_) >=10: + t_ = ['...'] + t_[-10:] self.iface.messageBar().pushMessage(title, - msg, level=Qgis.Critical, duration = 10) - self.log(msg, "error") + msg + " (more in log)", level=Qgis.Critical, duration = 10) + self.log(msg +'\n' + str(format_stack()), "error") + self.debug( pformat( t_ ) ) def noStyleWarning(self, layer): self.showWarning(u"Für den Layer " + layer.name() + u" sind keine Stile gespeichert") diff --git a/XPlan.py b/XPlan.py index de7e4cb..fbbca83 100644 --- a/XPlan.py +++ b/XPlan.py @@ -30,6 +30,7 @@ try: from DataDrivenInputMask.ddattribute import DdTable + from DataDrivenInputMask.dderror import FatalError except: pass @@ -908,22 +909,25 @@ def loadTable(self, schemaName, tableName, geomColumn, ddTable = self.app.xpManager.createDdTable(self.db, schemaName, tableName, withOid = False, withComment = False) - - isView = ddTable is None + + isView = ddTable is None #Why does this not hit on "BP_Basisobjekte.BP_Flaechenobjekte"? if isView: ddTable = DdTable(schemaName = schemaName, tableName = tableName) if self.app.xpManager.existsInDb(ddTable, self.db): - thisLayer = self.app.xpManager.loadPostGISLayer( - self.db, - ddTable, - displayName = displayName, - geomColumn = geomColumn, - keyColumn = "gid", - whereClause = filter, - intoDdGroup = False - ) + try: + thisLayer = self.app.xpManager.loadPostGISLayer( + self.db, + ddTable, + displayName = displayName, + geomColumn = geomColumn, + keyColumn = "gid", + whereClause = filter, + intoDdGroup = False + ) + except FatalError as fa: + raise fa return [thisLayer, isView] diff --git a/XPlanDialog.py b/XPlanDialog.py index d007931..3fabd96 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -22,6 +22,8 @@ # Import the PyQt and QGIS libraries from qgis.PyQt import QtCore, QtWidgets, QtSql, uic from qgis.PyQt.QtWidgets import QAction +from qgis.PyQt.QtGui import QFont +from qgis.core import QgsFillSymbol from builtins import str from builtins import range from qgis.core import * @@ -779,17 +781,38 @@ def __init__(self, xplanplugin, hoehenLayer): filter='' else: filter = self.xplanplugin.getBereichFilter(refSchema, refTable, self.xplanplugin.aktiveBereicheGids()) - # self.flaechenobjekteLayer, isView = self.xplanplugin.loadTable( + + text_format = QgsTextFormat() + text_format.setFont(QFont("Liberation Mono", 10)) + text_format.setSize(10) + + setting = QgsPalLayerSettings() + setting.setFormat(text_format) + setting.fieldName = "gid" + setting.placement = 0 + setting.fitInPolygonOnly = 0 + setting.polygonPlacementFlags = 2 + setting.centroidWhole = 1 + setting.enabled = True + setting = QgsVectorLayerSimpleLabeling(setting) + + fsymb = QgsFillSymbol.createSimple({'color': '#c9c9c9', 'outline_color': 'black'}) + self.flaechenobjekteLayer = self.xplanplugin.getQgisLayerForTable( - # self, schemaName, tableName, geomColumn = None, showMsg = True, filterOnNew=""): refSchema, refTable, geomColumn='position', displayName = refTable + " (für Höheneditor - temporär)", - # filter=filter, filterOnNew = filter ) - + self.flaechenobjekteLayer.setLabeling(setting) + self.flaechenobjekteLayer.setLabelsEnabled(True) + + renderer = self.flaechenobjekteLayer.renderer() + renderer.setSymbol(fsymb) + + self.flaechenobjekteLayer.triggerRepaint() + linkSchema = "XP_Basisobjekte" linkTable = "XP_Objekt_hoehenangabe" self.linkLayer = self.xplanplugin.getDDCoveredLayerForTable(linkSchema, linkTable) @@ -857,6 +880,7 @@ def showRelatedHoehen(self, sfeature=None): """Code called when the feature is selected by the user""" if sfeature is None: sfeature =self.selectedFeature self.selectedFeature = sfeature + self.flaechenobjekteLayer.reload() self.flaechenobjekteLayer.deselect(self.flaechenobjekteLayer.selectedFeatureIds()) self.flaechenobjekteLayer.select([sfeature.id()]) #id is correct self.fillHoehen([sfeature['gid']]) #gid is correct @@ -965,7 +989,19 @@ def fillHoehen(self, xp_objekt_gids =[]): # self.showError('id: ' + str(aFeat["id"])) if aFeat.id() > 0 and aFeat["id"] in relator_selector.keys(): # if xp_objekt_gids!=[]: self.showError('found id: ' + str(aFeat["id"])) - anItem = QtWidgets.QListWidgetItem(str( ( aFeat["id"], aFeat['hoehenbezug'], aFeat['bezugspunkt'], (aFeat['h'],aFeat['hMin'],aFeat['hMax'],aFeat['hZwingend'])))) + anItem = QtWidgets.QListWidgetItem( + str( ( + aFeat["id"], + aFeat['hoehenbezug'], + aFeat['bezugspunkt'], + ( + aFeat['h'], + aFeat['hMin'], + aFeat['hMax'], + aFeat['hZwingend'] + ) + ) ) + ) anItem.feature = aFeat self.hoehen.addItem(anItem) self.hoehen.sortItems() @@ -978,8 +1014,8 @@ def editFeature(self, thisFeature): self.xplanplugin.app.xpManager.showFeatureForm(self.hoehenLayer, thisFeature) except Exception as e: self.showError(str(e)) - self.showError(str(thisFeature.attributeMap())) - self.showError(str(self.hoehenLayer.name())) + self.showInfo(str(thisFeature.attributeMap())) + self.showInfo(str(self.hoehenLayer.name())) raise e self.showRelatedHoehen() @@ -1003,51 +1039,68 @@ def newHoehen(self): # there should be a block on the db enabled here, so we really get our maxId # not the one added by an other person simultaniously... if self.hoehenLayer.commitChanges(): - - maxIdHoehe = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Sonstiges", - "XP_Hoehenangabe", pkFieldName = "id") - expr = '"id" >= ' + str(maxIdHoehe) - self.hoehenLayer.selectByExpression(expr) - - if len(self.hoehenLayer.selectedFeatures()) == 1: - thisFeat = self.hoehenLayer.selectedFeatures()[0] - self.editFeature(thisFeat) + try: + self.hoehenLayer.reload() + maxIdHoehe = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Sonstiges", + "XP_Hoehenangabe", pkFieldName = "id") + expr = '"id" >= ' + str(maxIdHoehe) + self.hoehenLayer.selectByExpression(expr) - if self.linkLayer != None: - maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Basisobjekte", - "XP_Objekt_hoehenangabe", pkFieldName = "XP_Objekt_gid") - - if not (maxId is None): - newLink = self.xplanplugin.tools.createFeature(linkLayer) - newLink.setAttribute("XP_Objekt_gid", self.selectedFeature['gid']) - newLink.setAttribute("hoehenangabe", thisFeat['id']) - - if self.xplanplugin.tools.setEditable(self.linkLayer, True, self.xplanplugin.iface): - if self.linkLayer.addFeature(newLink): - - if self.linkLayer.commitChanges(): - self.linkLayer.reload() - expr = '"XP_Objekt_gid" >= ' + str(maxId) - self.linkLayer.selectByExpression(expr) - - if len(self.linkLayer.selectedFeatures()) == 1: - self.showError(u"Zuordnung Höhe->Flächenobjekt wurde eingefügt") - # linkFeat = hoehenAngLayer.selectedFeatures()[0] - # self.editFeature(linkFeat) - else: - self.showError(u"Neues Feature nicht gefunden! " + expr) - else: - self.showError(u"Kann in Tabelle " + refSchema + "." + refTable + \ - u" kein Feature einfügen!") - else: - self.showError(u"Zuerst muss ein Bezugsobjekt auf der Karte ausgewählt werden!") + if len(self.hoehenLayer.selectedFeatures()) == 1: + thisFeat = self.hoehenLayer.selectedFeatures()[0] + self.editFeature(thisFeat) + + if self.linkLayer != None: + maxId = self.xplanplugin.tools.getMaxGid(self.xplanplugin.db, "XP_Basisobjekte", + "XP_Objekt_hoehenangabe", pkFieldName = "XP_Objekt_gid") + + if not (maxId is None): #TODO: What happens on empty table? + newLink = self.xplanplugin.tools.createFeature(self.linkLayer) + newLink.setAttribute("XP_Objekt_gid", self.selectedFeature['gid']) + newLink.setAttribute("hoehenangabe", thisFeat['id']) + + if self.xplanplugin.tools.setEditable(self.linkLayer, True, self.xplanplugin.iface): + if self.linkLayer.addFeature(newLink): + + if self.linkLayer.commitChanges(): + try: + self.linkLayer.reload() + expr = '"XP_Objekt_gid" = ' + str(maxId) + self.linkLayer.selectByExpression(expr) + + if len(self.linkLayer.selectedFeatures()) >= 1: + self.showInfo(u"Zuordnung Höhe->Flächenobjekt wurde eingefügt") + # linkFeat = hoehenAngLayer.selectedFeatures()[0] + # self.editFeature(linkFeat) + else: + errortext = u"Neues Feature nicht gefunden! " + expr + self.showError(errortext) + raise Exception(errortext) + except Exception as e: + self.linkLayer.deleteFeature(newLink.id()) + self.linkLayer.commitChanges() + raise e + + else: + errortext = u"Kann in Tabelle " + refSchema + "." + refTable + \ + u" kein Feature einfügen!" + self.showError(errortext) + raise Exception(errortext) + else: + raise Exception('Die Datenbank scheint fehlerhaft zu sein, self.linkLayer ist None') + else: + self.showError(u"Zuerst muss ein Bezugsobjekt auf der Karte ausgewählt werden!") + except: + self.showError('Ein unerwarteter Fehler ist aufgetreten, das Hinzufügen der neuen Höhenangabe wurde zurückgenommen.') + self.hoehenLayer.deleteFeature(newFeat.id()) + self.hoehenLayer.commitChanges() def removeHoehen(self): - feat2Remove = self.hoehen.currentItem().feature + feat2remove = self.hoehen.currentItem().feature """Erst Link(s) zerstören...""" if not (self.linkLayer is None): - expr = '"hoehenangabe" = ' + str(feat2remove['id']) + expr = '"hoehenangabe" = ' + str(feat2remove.id()) self.linkLayer.selectByExpression(expr) if self.xplanplugin.tools.setEditable(self.linkLayer, True, self.xplanplugin.iface): if ( @@ -1055,14 +1108,14 @@ def removeHoehen(self): len(self.linkLayer.selectedFeatures()) == 1 #fallback: makes sure only entries with a 1:1 relation are deleted easily ): for link2remove in self.linkLayer.selectedFeatures(): - if self.linkLayer.deleteFeature(link2remove['id']): + if self.linkLayer.deleteFeature(link2remove.id()): if self.linkLayer.commitChanges(): self.linkLayer.reload() self.showRelatedHoehen() """... dann die eigenentliche Hoehenangabe entfernen""" if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): - if self.hoehenLayer.deleteFeature(feat2Remove.id()): + if self.hoehenLayer.deleteFeature(feat2remove.id()): if self.hoehenLayer.commitChanges(): self.showRelatedHoehen() else: @@ -1086,6 +1139,12 @@ def removeHoehen(self): def showError(self, msg): self.xplanplugin.tools.showError(msg) + + def showWarning(self, msg): + self.xplanplugin.tools.showWarning(msg) + + def showInfo(self, msg): + self.xplanplugin.tools.showInfo(msg) @QtCore.pyqtSlot( str ) def on_txlFilter_textChanged(self, currentText): @@ -1210,10 +1269,10 @@ def newReferenz(self): u" kein Feature einfügen!") def removeReferenz(self): - feat2Remove = self.referenzen.currentItem().feature + feat2remove = self.referenzen.currentItem().feature if self.xplanplugin.tools.setEditable(self.referenzenLayer, True, self.xplanplugin.iface): - if self.referenzenLayer.deleteFeature(feat2Remove.id()): + if self.referenzenLayer.deleteFeature(feat2remove.id()): if self.referenzenLayer.commitChanges(): self.fillReferenzen() else: From c27a1454d6a6dfb4d1b9a6688e2c0ddcc2fcbbe9 Mon Sep 17 00:00:00 2001 From: Janne Jakob Fleischer Date: Mon, 6 Feb 2023 17:07:24 +0100 Subject: [PATCH 9/9] added right click menu for deselect, fixed deleting objects (mostly...) --- XPTools.py | 40 +++++++++++---------- XPlan.py | 4 +-- XPlanDialog.py | 97 +++++++++++++++++++++++++++++++------------------- 3 files changed, 85 insertions(+), 56 deletions(-) diff --git a/XPTools.py b/XPTools.py index 5f9f03d..ad007b3 100644 --- a/XPTools.py +++ b/XPTools.py @@ -635,6 +635,27 @@ def setEditable(self, layer, showErrorMsg = False, iface = None): def noActiveLayerWarning(self): self.showWarning(u"Kein aktiver Layer") + def debug(self, msg, stacksize=0): + t_ = [ + x[0].f_locals for x in inspect.trace() + ] + if stacksize==0: + self.log("Debug" + "\n" + msg) + elif len(t_) >=stacksize: + t_ = ['...'] + t_[-1*stacksize:] + self.log("Debug" + "\n" + msg + ' | ' + pformat( t_ )) + else: + self.log("Debug" + "\n" + msg + ' | ' + pformat( t_ )) + + def log(self, msg, type = 'info'): + if type == 'info': + msgType = Qgis.Info + if type == 'warn': + msgType = Qgis.Warning + if type == 'error': + msgType = Qgis.Critical + QgsMessageLog.logMessage(msg, "XPlanung", msgType) + def showQueryError(self, query): self.showError( "%(error)s" % {"error": query.lastError().text()}, "DB-Fehler") @@ -653,31 +674,14 @@ def showWarning(self, msg, title = "XPlanung"): #self.log(msg, "warn") def showError(self, msg, title = "XPlanung"): - t_ = [ - x[0].f_locals for x in inspect.trace() - ] - if len(t_) >=10: - t_ = ['...'] + t_[-10:] self.iface.messageBar().pushMessage(title, msg + " (more in log)", level=Qgis.Critical, duration = 10) self.log(msg +'\n' + str(format_stack()), "error") - self.debug( pformat( t_ ) ) + self.debug(msg, 2) def noStyleWarning(self, layer): self.showWarning(u"Für den Layer " + layer.name() + u" sind keine Stile gespeichert") - def debug(self, msg): - self.log("Debug" + "\n" + msg) - - def log(self, msg, type = 'info'): - if type == 'info': - msgType = Qgis.Info - if type == 'warn': - msgType = Qgis.Warning - if type == 'error': - msgType = Qgis.Critical - QgsMessageLog.logMessage(msg, "XPlanung", msgType) - def getAuthUserNamePassword(self, authcfg): username = None password = None diff --git a/XPlan.py b/XPlan.py index fbbca83..227389b 100644 --- a/XPlan.py +++ b/XPlan.py @@ -252,8 +252,8 @@ def unload(self): except: pass - def debug(self, msg): - self.tools.log("Debug" + "\n" + msg) + def debug(self, msg, stacksize=0): + self.tools.debug(msg, stacksize=stacksize) def loadLayerLayer(self): self.layerLayer = self.getLayerForTable("QGIS", "layer") diff --git a/XPlanDialog.py b/XPlanDialog.py index 3fabd96..3255c0e 100644 --- a/XPlanDialog.py +++ b/XPlanDialog.py @@ -355,9 +355,6 @@ def initializeValues(self): self.fillBereichTree() - def debug(self, msg): - QtWidgets.QMessageBox.information(None, "Debug", msg) - def fillBereichTree(self): self.bereich.clear() planArt = self.planArt @@ -754,16 +751,19 @@ def __init__(self, canvas, layer, manager): def canvasReleaseEvent(self, e): super().canvasReleaseEvent(e) - ident_result = self.identify( - e.pixelPoint().x(), - e.pixelPoint().y(), - mode = self.IdentifyMode(3), - layerList= [self.layer] - ) - if len(ident_result)>0: - sfeature = ident_result[0].mFeature - self.manager.selectedFeature = sfeature - self.featureIdentified.emit(sfeature) + if e.button()==2: #rightclick + self.manager.canvas.contextMenu.exec_(e.globalPos()) + else: + ident_result = self.identify( + e.pixelPoint().x(), + e.pixelPoint().y(), + mode = self.IdentifyMode(3), + layerList= [self.layer] + ) + if len(ident_result)>0: + sfeature = ident_result[0].mFeature + self.manager.selectedFeature = sfeature + self.featureIdentified.emit(sfeature) def __init__(self, xplanplugin, hoehenLayer): QtWidgets.QDialog.__init__(self) @@ -774,6 +774,8 @@ def __init__(self, xplanplugin, hoehenLayer): self.selectedFeature = None self.relator = None + self.debug = self.xplanplugin.debug + #canvas refSchema = "BP_Basisobjekte" refTable = "BP_Flaechenobjekte" #this is a view for qgis! @@ -824,25 +826,35 @@ def __init__(self, xplanplugin, hoehenLayer): self.canvas.enableAntiAliasing(True) # create the map tools - self.actionZoomIn = QAction("Zoom in", self) - self.actionZoomIn.triggered.connect(self.zoomIn) - self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in - self.toolZoomIn.setAction(self.actionZoomIn) - - self.actionZoomOut = QAction("Zoom out", self) - self.actionZoomOut.triggered.connect(self.zoomOut) - self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out - self.toolZoomOut.setAction(self.actionZoomOut) + # self.actionZoomIn = QAction("Hineinzoomen", self) + # self.actionZoomIn.triggered.connect(self.zoomIn) + # self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # false = in + # self.toolZoomIn.setAction(self.actionZoomIn) + # + # self.actionZoomOut = QAction("Herauszoomen", self) + # self.actionZoomOut.triggered.connect(self.zoomOut) + # self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # true = out + # self.toolZoomOut.setAction(self.actionZoomOut) self.actionPan = QAction("Pan", self) self.actionPan.triggered.connect(self.pan) self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) + self.actionDeselect = QAction("Auswahl aufheben", self) + self.actionDeselect.triggered.connect(self.deselectFlaeche) + + self.canvas.contextMenu = QtWidgets.QMenu(self.canvas) + self.canvas.contextMenu.addAction(self.actionDeselect) + # self.canvas.contextMenu.addAction(self.actionZoomIn) + # self.canvas.contextMenu.addAction(self.actionZoomOut) + self.toolIdentify = self.featureSelector(self.canvas, self.flaechenobjekteLayer, self) - self.toolIdentify.featureIdentified.connect(self.showRelatedHoehen) + self.toolIdentify.featureIdentified.connect(self.fillRelatedHoehen) self.identify() + + #!canvas self.hoehen.customContextMenuRequested.connect(self.on_hoehen_customContextMenuRequested) @@ -863,6 +875,9 @@ def __init__(self, xplanplugin, hoehenLayer): self.buttonBox.button(QtWidgets.QDialogButtonBox.Reset).clicked.connect(self.initialize) self.initialize() + + def deselectFlaeche(self): + self.flaechenobjekteLayer.removeSelection() def zoomIn(self): self.canvas.setMapTool(self.toolZoomIn) @@ -876,15 +891,6 @@ def pan(self): def identify(self): self.canvas.setMapTool(self.toolIdentify) - def showRelatedHoehen(self, sfeature=None): - """Code called when the feature is selected by the user""" - if sfeature is None: sfeature =self.selectedFeature - self.selectedFeature = sfeature - self.flaechenobjekteLayer.reload() - self.flaechenobjekteLayer.deselect(self.flaechenobjekteLayer.selectedFeatureIds()) - self.flaechenobjekteLayer.select([sfeature.id()]) #id is correct - self.fillHoehen([sfeature['gid']]) #gid is correct - def unselectFeature(self): self.flaechenobjekteLayer.removeSelection() @@ -960,7 +966,20 @@ def getRelatorTable(self): else: # self.showError('relator is loaded from cache') return self.relator + + def fillRelatedHoehen(self, sfeature=None): + """Code called when the feature is selected by the user""" + if sfeature is None: sfeature =self.selectedFeature + self.selectedFeature = sfeature + self.flaechenobjekteLayer.reload() + self.flaechenobjekteLayer.deselect(self.flaechenobjekteLayer.selectedFeatureIds()) + if not (sfeature is None): + self.flaechenobjekteLayer.select([sfeature.id()]) #id is correct + self.fillHoehen([sfeature['gid']]) #gid is correct + else: + self.fillHoehen() + def fillHoehen(self, xp_objekt_gids =[]): self.hoehen.clear() filter = self.txlFilter.text() @@ -1017,7 +1036,7 @@ def editFeature(self, thisFeature): self.showInfo(str(thisFeature.attributeMap())) self.showInfo(str(self.hoehenLayer.name())) raise e - self.showRelatedHoehen() + self.fillRelatedHoehen() def highlightFeature(self, thisFeature): pass @@ -1101,6 +1120,7 @@ def removeHoehen(self): """Erst Link(s) zerstören...""" if not (self.linkLayer is None): expr = '"hoehenangabe" = ' + str(feat2remove.id()) + self.debug(expr) self.linkLayer.selectByExpression(expr) if self.xplanplugin.tools.setEditable(self.linkLayer, True, self.xplanplugin.iface): if ( @@ -1111,13 +1131,13 @@ def removeHoehen(self): if self.linkLayer.deleteFeature(link2remove.id()): if self.linkLayer.commitChanges(): self.linkLayer.reload() - self.showRelatedHoehen() + self.fillRelatedHoehen() """... dann die eigenentliche Hoehenangabe entfernen""" if self.xplanplugin.tools.setEditable(self.hoehenLayer, True, self.xplanplugin.iface): if self.hoehenLayer.deleteFeature(feat2remove.id()): if self.hoehenLayer.commitChanges(): - self.showRelatedHoehen() + self.fillRelatedHoehen() else: self.showError(u"Konnte Änderungen nicht speichern") else: @@ -1129,7 +1149,9 @@ def removeHoehen(self): self.showError(u"Konnte Änderungen in der LinkTabelle nicht speichern") else: #todo: create button for deselect - self.showError('Die ausgewählte Höhenangabe wird von mehreren Flächenobjekten referenziert und kann aus Sicherheitsgründen nur gelöscht werden, wenn oben in der Karte kein Flächenobjekt ausgewählt ist.') + self.showError('Die ausgewählte Höhenangabe wird von mehreren Flächenobjekten referenziert '+ + 'und kann aus Sicherheitsgründen nur gelöscht werden, wenn oben in der Karte '+ + 'kein Flächenobjekt ausgewählt ist.') else: self.showError(u"Kann Layer " + self.linkLayer.name() + u" nicht editieren") else: @@ -1145,6 +1167,9 @@ def showWarning(self, msg): def showInfo(self, msg): self.xplanplugin.tools.showInfo(msg) + + def debug(self, msg, stacksize=0): + self.xplanplugin.tools.debug(msg, stacksize=stacksize) @QtCore.pyqtSlot( str ) def on_txlFilter_textChanged(self, currentText):