class Navigator: def __init__(self, dbname: str): """ Constructor :param dbname: Entspricht dem Datei-Pfad zur SpatiaLite-Datenbank. """ self.__dbname = dbname self.__error_msg = "" self.db = DBConnection(dbname) if not self.db.connected: main_logger.error( ( "Fehler in navigation:\n" + "QKan-Datenbank {:s} wurde nicht gefunden oder war nicht aktuell!\nAbbruch!" ).format(dbname) ) raise Exception() # TODO: ??? self.log = logging.getLogger("QKan.navigation.Navigator") def calculate_route_schacht( self, nodes: List[str] ) -> Optional[Dict[str, Union[List[str], Dict[str, Union[str, float]]]]]: """ * Wird ausgeführt, wenn eine Route zwischen Schächten gefunden werden soll. * Berechnet die Route aus Start- und Endpunkt, prüft am Ende, ob alle anderen Schächte innerhalb der berechneten Route liegen. * Benötigt mindestens zwei Schächte :param nodes: Entspricht einer Liste von den selektierten Schacht-Namen aus QGIS. :return: Gibt ein Routen-Objekt zurück mit allen Haltungen und Schächten """ self.log.debug("Übergebene Schächte:\t{}".format(nodes)) endpoint = nodes[0] startpoint = nodes[0] statement = """ SELECT sohlhoehe FROM schaechte WHERE schnam="{}" """ self.db.sql(statement.format(nodes[0])) (min_value,) = self.db.fetchone() max_value = min_value for n in nodes: self.db.sql(statement.format(n)) (value,) = self.db.fetchone() if value < min_value: min_value = value endpoint = n elif value > max_value: max_value = value startpoint = n self.log.info("Start- und Endpunkt wurden gesetzt") self.log.debug("Startpunkt:\t{}\nEndpunkt:\t{}".format(startpoint, endpoint)) nodes.remove(startpoint) nodes.remove(endpoint) self.log.debug(u"Zusätzliche Punkte:\t{}".format(nodes)) return self.__calculate_route_schacht( startpoint, endpoint, additional_points=nodes ) def __calculate_route_schacht( self, startpoint: str, endpoint: str, additional_points: List[str] ) -> Optional[Dict[str, Union[List[str], Dict[str, Union[str, float]]]]]: """ Berechnet die Schächte und Haltungen, die zwischen einem Start- und Endpunkt liegen. * Start- und Endhöhe müssen nicht in der richtigen Reihenfolge übergeben werden. * Zusätzliche Punkte müssen nur übergeben werden, wenn der Endpunkt über mehrere Wege zu erreichen ist. :param startpoint: Entspricht dem Schacht-Namen aus QGIS. :param endpoint: Entspricht dem Schacht-Namen aus QGIS. :param additional_points: Entspricht einer Liste von Schacht-Namen, die zusätzlich ausgewählt wurden. :return: Gibt ein Routen-Objekt zurück, bestehend aus allen Haltungen und Schächten """ statement = u""" SELECT name FROM (SELECT haltnam AS name, schoben FROM haltungen UNION SELECT wnam AS name, schoben FROM wehre UNION SELECT pnam AS name, schoben FROM pumpen) WHERE schoben ="{}" """ self.db.sql(statement.format(startpoint)) start_haltungen = [h[0] for h in self.db.fetchall()] self.log.debug(u"Start-Haltungen:\t{}".format(start_haltungen)) statement_2 = u""" SELECT name FROM (SELECT haltnam AS name, schunten FROM haltungen UNION SELECT wnam AS name, schunten FROM wehre UNION SELECT pnam AS name, schunten FROM pumpen) WHERE schunten ="{}" """ self.db.sql(statement_2.format(endpoint)) end_haltungen = [h[0] for h in self.db.fetchall()] self.log.debug(u"End-Haltungen:\t{}".format(end_haltungen)) nodes = [] if len(additional_points) > 0: for p in additional_points: self.db.sql(statement.format(p)) nodes.append([h[0] for h in self.db.fetchall()]) permutations = cast(List[List[float]], itertools.product(*nodes)) permutations = [list(p) for p in permutations] possibilities = 0 route = None self.log.debug(u"Zusätzliche Haltungen:\t{}".format(nodes)) self.log.info(u"Alle nötigen Haltungen gesetzt") for start_haltung in start_haltungen: for end_haltung in end_haltungen: for permutation in permutations: _nodes = list(set([start_haltung, end_haltung] + list(permutation))) self.log.debug(u"Aktuelle Haltungen:\t{}".format(_nodes)) _route = self.calculate_route_haltung(_nodes) if _route: self.log.info(u"Aktuelle Route ist valide") possibilities += 1 if possibilities > 1: self.log.error( u"Zu viele Möglichkeiten zwischen Start- und End-Haltung." ) self.__error_msg = ( u"Zu viele Möglichkeiten. Bitte wählen Sie einen Wegpunkt auf" u" dem kritischen Pfad!" ) return None route = _route return route def calculate_route_haltung( self, nodes: List[str] ) -> Optional[Dict[str, Union[List[str], Dict[str, Union[str, float]]]]]: """ Berechnet eine Route zwischen mehreren Haltungen. :param nodes: Alle selektierten Haltungs-Namen aus QGIS :return: Gibt eine Routen-Objekt mit allen Haltungen und Schächten zurück """ if len(nodes) == 1: routes = [nodes] else: tasks = Tasks(self.__dbname, nodes) self.log.info(u"Tasks wurden initialisiert") routes = tasks.start() self.log.info(u"Alle möglichen Routen ({}) berechnet".format(len(routes))) if len(routes) == 1: self.log.info(u"Eine einzige mögliche Route gefunden") return self.__fetch_data(routes[0]) elif len(routes) == 0: self.log.error(u"Keine Route gefunden. Pfad ist fehlerhaft!") self.__error_msg = u"Übergebener Pfad ist fehlerhaft." return None else: self.log.error( u"Es gibt {} mögliche Routen. Der Pfad muss spezifiziert werden".format( len(routes) ) ) self.__error_msg = ( u"Mehrere Möglichkeiten ({}) den Endpunkt zu erreichen. " u"Bitte spezifizieren Sie die Route." ).format(len(routes)) return None def __fetch_data( self, haltungen: List[str] ) -> Dict[str, Union[List[str], Dict[str, Union[str, float]]]]: """ Fragt die Datenbank nach den benötigten Attributen ab und speichert sie in einem Dictionary. Das Dictionary hat folgende Struktur: *{haltungen:[haltungsnamen], schaechte:[schachtnamen], schachtinfo:{schachtname: {sohlhoehe:float, deckelhoehe:float} }, haltunginfo:{haltungsname: {schachtoben: schachtname, schachtunten: schachtname, laenge: float, sohlhoeheoben: float, sohlhoeheunten: float, querschnitt: float} } } :param haltungen: Liste aller Haltungs-Namen aus QGIS :return: Gibt ein Routen-Objekt zurück. """ statement = u""" SELECT schoben FROM (SELECT haltnam AS name, schoben FROM haltungen UNION SELECT wnam AS name, schoben FROM wehre UNION SELECT pnam AS name, schoben FROM pumpen) WHERE name = "{}" """ schaechte = [] self.log.debug(u"Haltungen:\t{}".format(haltungen)) self.db.sql(statement.format(haltungen[0])) schaechte.append(self.db.fetchone()[0]) statement = u""" SELECT schunten FROM (SELECT haltnam AS name, schunten FROM haltungen UNION SELECT wnam AS name, schunten FROM wehre UNION SELECT pnam AS name, schunten FROM pumpen) WHERE name = "{}" """ for h in haltungen: self.db.sql(statement.format(h)) schaechte.append(self.db.fetchone()[0]) self.log.debug(u"Schächte:\t{}".format(schaechte)) route = {"haltungen": haltungen, "schaechte": schaechte} rinfo = self.get_info(route) rval: Dict[str, Union[List[str], Dict[str, Union[str, float]]]] = { "haltungen": haltungen, "schaechte": schaechte, "schachtinfo": rinfo[0], "haltunginfo": rinfo[1], } self.log.info("Route wurde erfolgreich erstellt!") return rval def get_info(self, route: Dict[str, List[str]]) -> Tuple[Dict, Dict]: """ Methode muss überschrieben werden bei Verwendung dieses Moduls :param route: Die Haltungen und Schächte in einem Dictionary :type route: dict :return Gibt zwei Dictionaries mit zusätzlichen Informationen aus der Datenbank zurück :rtype: dict, dict """ def get_error_msg(self) -> str: """ Getter der Error-Message. :return: Gibt die Error-Message zurück """ return self.__error_msg
class CreateUnbefFl: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'CreateUnbefFl_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = CreateUnbefFlDialog() # Anfang Eigene Funktionen ------------------------------------------------- # (jh, 12.06.2017) logger.info(u'\n\nQKan_CreateUnbefFlaechen initialisiert...') # -------------------------------------------------------------------------- # Pfad zum Arbeitsverzeichnis sicherstellen wordir = os.path.join(site.getuserbase(), u'qkan') if not os.path.isdir(wordir): os.makedirs(wordir) # -------------------------------------------------------------------------------------------------- # Konfigurationsdatei qkan.json lesen # self.configfil = os.path.join(wordir, u'qkan.json') if os.path.exists(self.configfil): with open(self.configfil, 'r') as fileconfig: self.config = json.loads(fileconfig.read()) else: self.config = {'epsg': '25832'} # Projektionssystem with open(self.configfil, 'w') as fileconfig: fileconfig.write(json.dumps(self.config)) # Formularereignisse anbinden ---------------------------------------------- self.dlg.tw_selAbflparamTeilgeb.itemClicked.connect( self.tw_selAbflparamTeilgebClick) self.dlg.cb_selActive.stateChanged.connect(self.selActiveClick) self.dlg.button_box.helpRequested.connect(self.helpClick) # Ende Eigene Funktionen --------------------------------------------------- # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('CreateUnbefFl', message) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/qkan/createunbeffl/icon.png' Dummy.instance.add_action( icon_path, text=self.tr(u'Erzeuge unbefestigte Flächen...'), callback=self.run, parent=self.iface.mainWindow()) def unload(self): pass # ------------------------------------------------------------------------- # Formularfunktionen def helpClick(self): """Reaktion auf Klick auf Help-Schaltfläche""" helpfile = os.path.join( self.plugin_dir, '../doc/sphinx/build/html/Qkan_Formulare.html#erzeugen-der-unbefestigten-flachen' ) webbrowser.open_new_tab(helpfile) def tw_selAbflparamTeilgebClick(self): """Reaktion auf Klick in Tabelle""" self.dlg.cb_selActive.setChecked(True) self.countselection() def selActiveClick(self): """Reagiert auf Checkbox zur Aktivierung der Auswahl""" # Checkbox hat den Status nach dem Klick if self.dlg.cb_selActive.isChecked(): # Nix tun ... logger.debug('\nChecked = True') else: # Auswahl deaktivieren und Liste zurücksetzen anz = self.dlg.tw_selAbflparamTeilgeb.rowCount() range = QTableWidgetSelectionRange(0, 0, anz - 1, 4) self.dlg.tw_selAbflparamTeilgeb.setRangeSelected(range, False) logger.debug('\nChecked = False\nQWidget: anzahl = {}'.format(anz)) # Anzahl in der Anzeige aktualisieren self.countselection() def countselection(self): """Zählt nach Änderung der Auswahlen in den Listen im Formular die Anzahl der betroffenen TEZG-Flächen""" liste_selAbflparamTeilgeb = self.listselectedTabitems( self.dlg.tw_selAbflparamTeilgeb) # logger.debug(u'QKan.createunbeffl.application.countselection (1)\nlen(liste_selAbflparamTeilgeb) = {}'.format(len(liste_selAbflparamTeilgeb))) # logger.debug(u'QKan.createunbeffl.application.countselection (2)\nliste_selAbflparamTeilgeb = {}'.format(str(liste_selAbflparamTeilgeb))) # Aufbereiten für SQL-Abfrage # Unterschiedliches Vorgehen, je nachdem ob mindestens eine oder keine Zeile # ausgewählt wurde # if len(liste_selAbflparamTeilgeb) == 0: # anzahl = sum([int(attr[-2]) for attr in self.listetezg]) # else: # anzahl = sum([int(attr[-2]) for attr in liste_selAbflparamTeilgeb]) # Vorbereitung des Auswahlkriteriums für die SQL-Abfrage: Kombination aus abflussparameter und teilgebiet # Dieser Block ist identisch in k_unbef und in application enthalten if len(liste_selAbflparamTeilgeb) == 0: auswahl = u'' elif len(liste_selAbflparamTeilgeb) == 1: auswahl = u' AND' elif len(liste_selAbflparamTeilgeb) >= 2: auswahl = u' AND (' else: fehlermeldung(u"Interner Fehler", u"Fehler in Fallunterscheidung!") return False # Anfang SQL-Krierien zur Auswahl der tezg-Flächen first = True for attr in liste_selAbflparamTeilgeb: if attr[4] == u'None' or attr[1] == u'None': fehlermeldung( u'Datenfehler: ', u'In den ausgewählten Daten sind noch Datenfelder nicht definiert ("NULL").' ) return False if first: first = False auswahl += u""" (tezg.abflussparameter = '{abflussparameter}' AND tezg.teilgebiet = '{teilgebiet}')""".format( abflussparameter=attr[0], teilgebiet=attr[1]) else: auswahl += u""" OR\n (tezg.abflussparameter = '{abflussparameter}' AND tezg.teilgebiet = '{teilgebiet}')""".format( abflussparameter=attr[0], teilgebiet=attr[1]) if len(liste_selAbflparamTeilgeb) >= 2: auswahl += u")" # Ende SQL-Krierien zur Auswahl der tezg-Flächen # Ende SQL-Krierien zur Auswahl der tezg-Flächen # Trick: Der Zusatz "WHERE 1" dient nur dazu, dass der Block zur Zusammenstellung von 'auswahl' identisch mit dem # Block in 'k_unbef.py' bleiben kann... sql = u"""SELECT count(*) AS anz FROM tezg WHERE 1{auswahl} """.format(auswahl=auswahl) if not self.dbQK.sql(sql, u"QKan.CreateUnbefFlaechen (5)"): return False data = self.dbQK.fetchone() if not (data is None): self.dlg.lf_anzahl_tezg.setText(u'{}'.format(data[0])) else: self.dlg.lf_anzahl_tezg.setText(u'0') # ------------------------------------------------------------------------- # Funktion zur Zusammenstellung einer Auswahlliste für eine SQL-Abfrage def listselectedTabitems(self, tableWidget, nCols=5): """Erstellt eine Liste aus den in einem Auswahllisten-Widget angeklickten Objektnamen :param tableWidget: Tabelle zur Auswahl der Arten von Haltungsflächen. :type tableWidget: QTableWidget :param nCols: Anzahl Spalten des tableWidget-Elements :type nCols: integer :returns: Tuple mit ausgewählten Abflussparametern :rtype: tuple """ items = tableWidget.selectedItems() anz = len(items) nRows = anz // nCols if len(items) > nCols: # mehr als eine Zeile ausgewählt if tableWidget.row(items[1]) == 1: # Elemente wurden spaltenweise übergeben liste = [[el.text() for el in items][i:anz:nRows] for i in range(nRows)] else: # Elemente wurden zeilenweise übergeben liste = [[el.text() for el in items][i:i + 5] for i in range(0, anz, 5)] else: # Elemente wurden zeilenweise übergeben oder Liste ist leer liste = [[el.text() for el in items][i:i + 5] for i in range(0, anz, 5)] return liste # ------------------------------------------------------------------------------------------------------------ # Vorbereiten und Öffnen des Formulars def run(self): """Run method that performs all the real work""" database_QKan, epsg = get_database_QKan() if not database_QKan: fehlermeldung( u"Fehler in CreateUnbefFl", u"database_QKan konnte nicht aus den Layern ermittelt werden. Abbruch!" ) logger.error( u"CreateUnbefFl: database_QKan konnte nicht aus den Layern ermittelt werden. Abbruch!" ) return False # Abfragen der Tabelle tezg nach verwendeten Abflussparametern self.dbQK = DBConnection( dbname=database_QKan ) # Datenbankobjekt der QKan-Datenbank zum Lesen if self.dbQK is None: fehlermeldung( u"Fehler in QKan_CreateUnbefFl", u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format( database_QKan)) iface.messageBar().pushMessage(u"Fehler in QKan_Import_from_HE", u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format( \ database_QKan), level=QgsMessageBar.CRITICAL) return None # Kontrolle, ob in Tabelle "abflussparameter" ein Datensatz für unbefestigte Flächen vorhanden ist # (Standard: apnam = '$Default_Unbef') sql = u"""SELECT apnam FROM abflussparameter WHERE bodenklasse IS NOT NULL AND trim(bodenklasse) <> ''""" if not self.dbQK.sql(sql, u'createunbeffl.run (1)'): return False data = self.dbQK.fetchone() if data is None: if autokorrektur: daten = [ u"'$Default_Unbef', u'von QKan ergänzt', 0.5, 0.5, 2, 5, 0, 0, 'LehmLoess', '13.01.2011 08:44:50'" ] for ds in daten: sql = u"""INSERT INTO abflussparameter ( 'apnam', 'kommentar', 'anfangsabflussbeiwert', 'endabflussbeiwert', 'benetzungsverlust', 'muldenverlust', 'benetzung_startwert', 'mulden_startwert', 'bodenklasse', 'createdat') Values ({})""".format(ds) if not self.dbQK.sql(sql, u'createunbeffl.run (2)'): return False else: fehlermeldung( u'Datenfehler: ', u'Bitte ergänzen Sie in der Tabelle "abflussparameter" einen Datensatz für unbefestigte Flächen ("bodenklasse" darf nicht leer oder NULL sein)' ) # # Kontrolle, ob noch Flächen in Tabelle "tezg" ohne Zuordnung zu einem Abflussparameter oder zu einem # # Abflussparameter, bei dem keine Bodenklasse definiert ist (Kennzeichen für undurchlässige Flächen). # sql = u"""SELECT te.abflussparameter, te.teilgebiet, count(*) AS anz # FROM tezg AS te # LEFT JOIN abflussparameter AS ap # ON te.abflussparameter = ap.apnam # WHERE ap.bodenklasse IS NULL # GROUP BY abflussparameter, teilgebiet""" # if not self.dbQK.sql(sql, u'createunbeffl.run (3)'): # return False # data = self.dbQK.fetchall() # if len(data) > 0: # liste = [u'{}\t{}\t{}'.format(el1, el2, el3) for el1, el2, el3 in data] # liste.insert(0, u'\nAbflussparameter\tTeilgebiet\tAnzahl') # fehlermeldung(u'In Tabelle "tezg" fehlen Abflussparameter oder gehören zu befestigten Flächen (Bodenklasse = NULL):\n', # u'\n'.join(liste)) # return False sql = u"""SELECT te.abflussparameter, te.teilgebiet, bk.bknam, count(*) AS anz, CASE WHEN te.abflussparameter ISNULL THEN 'Fehler: Kein Abflussparameter angegeben' ELSE CASE WHEN bk.infiltrationsrateanfang ISNULL THEN 'Fehler: Keine Bodenklasse angegeben' WHEN bk.infiltrationsrateanfang < 0.00001 THEN 'Fehler: undurchlässige Bodenart' ELSE '' END END AS status FROM tezg AS te LEFT JOIN abflussparameter AS ap ON te.abflussparameter = ap.apnam LEFT JOIN bodenklassen AS bk ON bk.bknam = ap.bodenklasse GROUP BY abflussparameter, teilgebiet""" if not self.dbQK.sql(sql, u'createunbeffl.run (4)'): return None self.listetezg = self.dbQK.fetchall() nzeilen = len(self.listetezg) self.dlg.tw_selAbflparamTeilgeb.setRowCount(nzeilen) self.dlg.tw_selAbflparamTeilgeb.setHorizontalHeaderLabels([ u"Abflussparameter", u"Teilgebiet", u"Bodenklasse", u"Anzahl", u"Anmerkungen" ]) self.dlg.tw_selAbflparamTeilgeb.setColumnWidth( 0, 144) # 17 Pixel für Rand und Nummernspalte (und je Spalte?) self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(1, 140) self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(2, 90) self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(3, 50) self.dlg.tw_selAbflparamTeilgeb.setColumnWidth(4, 200) for i, elem in enumerate(self.listetezg): for j, item in enumerate(elem): cell = u'{}'.format(elem[j]) self.dlg.tw_selAbflparamTeilgeb.setItem( i, j, QTableWidgetItem(cell)) self.dlg.tw_selAbflparamTeilgeb.setRowHeight(i, 20) # config in Dialog übernehmen # Autokorrektur if 'autokorrektur' in self.config: autokorrektur = self.config['autokorrektur'] else: autokorrektur = True self.dlg.cb_autokorrektur.setChecked(autokorrektur) self.countselection() # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() logger.debug('\n\nresult = {}'.format(repr(result))) # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. # pass # Start der Verarbeitung liste_selAbflparamTeilgeb = self.listselectedTabitems( self.dlg.tw_selAbflparamTeilgeb) logger.debug(u'\nliste_selAbflparamTeilgeb (1): {}'.format( liste_selAbflparamTeilgeb)) autokorrektur = self.dlg.cb_autokorrektur.isChecked() self.config['autokorrektur'] = autokorrektur with open(self.configfil, 'w') as fileconfig: fileconfig.write(json.dumps(self.config)) createUnbefFlaechen(self.dbQK, liste_selAbflparamTeilgeb, autokorrektur)
def qgsadapt(projectTemplate, qkanDB, epsg, projectFile, setPathToTemplateDir=True, dbtyp=u'SpatiaLite'): '''Lädt eine (Vorlage-) Projektdatei (*.qgs) und adaptiert diese auf eine QKan-Datenbank an. Anschließend wird dieses Projekt geladen. Voraussetzungen: keine :projectTemplate: Vorlage-Projektdatei :type database: String :qkanDB: Ziel-Datenbank, auf die die Projektdatei angepasst werden soll :type qkanDB: String :projectFile: Zu Erzeugende Projektdatei :type projectFile: String :setPathToTemplateDir: Option, ob das Suchverzeichnis auf das Template-Verzeichnis gesetzt werden soll. :type setPathToTemplateDir: Boolean :dbtyp: Typ der Datenbank (SpatiaLite, PostGIS) :type dbtyp: String :returns: void ''' # ------------------------------------------------------------------------------ # Datenbankverbindungen dbQK = DBConnection( dbname=qkanDB, epsg=epsg) # Datenbankobjekt der QKan-Datenbank zum Schreiben if dbQK is None: fehlermeldung( u"Fehler in qgsadapt", u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format( qkanDB)) iface.messageBar().pushMessage(u"Fehler in qgsadapt", u'QKan-Datenbank {:s} wurde nicht gefunden!\nAbbruch!'.format( \ qkanDB), level=QgsMessageBar.CRITICAL) return None # -------------------------------------------------------------------------- # Zoom-Bereich für die Projektdatei vorbereiten sql = u'''SELECT min(xsch) AS xmin, max(xsch) AS xmax, min(ysch) AS ymin, max(ysch) AS ymax FROM schaechte''' try: dbQK.sql(sql) except BaseException as e: fehlermeldung('SQL-Fehler', str(e)) fehlermeldung("Fehler in qgsadapt", u"\nFehler in sql_zoom: \n" + sql + '\n\n') daten = dbQK.fetchone() try: zoomxmin, zoomxmax, zoomymin, zoomymax = daten except BaseException as e: fehlermeldung('SQL-Fehler', str(e)) fehlermeldung("Fehler in qgsadapt", u"\nFehler in sql_zoom; daten= " + str(daten) + '\n') # -------------------------------------------------------------------------- # Projektionssystem für die Projektdatei vorbereiten sql = """SELECT srid FROM geom_cols_ref_sys WHERE Lower(f_table_name) = Lower('schaechte') AND Lower(f_geometry_column) = Lower('geom')""" if not dbQK.sql(sql, 'importkanaldaten_dyna (37)'): return None srid = dbQK.fetchone()[0] try: crs = QgsCoordinateReferenceSystem( srid, QgsCoordinateReferenceSystem.EpsgCrsId) srsid = crs.srsid() proj4text = crs.toProj4() description = crs.description() projectionacronym = crs.projectionAcronym() if 'ellipsoidacronym' in dir(crs): ellipsoidacronym = crs.ellipsoidacronym() else: ellipsoidacronym = None except BaseException as e: srid, srsid, proj4text, description, projectionacronym, ellipsoidacronym = \ 'dummy', 'dummy', 'dummy', 'dummy', 'dummy', 'dummy' fehlermeldung('\nFehler in "daten"', str(e)) fehlermeldung("Fehler in qgsadapt", u"\nFehler bei der Ermittlung der srid: \n" + str(daten)) # -------------------------------------------------------------------------- # Datenbankverbindungen schliessen del dbQK # -------------------------------------------------------------------------- # Projektdatei schreiben, falls ausgewählt if projectFile is None or projectFile == u'': fehlermeldung(u'Bedienerfehler!', u'Es wurde keine Projektdatei ausgewählt') return False if setPathToTemplateDir: templatepath = os.path.join(pluginDirectory('qkan'), u"database/templates") projectpath = os.path.dirname(projectFile) if os.path.dirname(qkanDB) == projectpath: datasource = qkanDB.replace(os.path.dirname(qkanDB), u'.') else: datasource = qkanDB # Liste der Geotabellen aus QKan, um andere Tabellen von der Bearbeitung auszuschliessen # Liste steht in 3 Modulen: tools.k_tools, importdyna.import_from_dyna, importhe.import_from_he tabliste = [ u'einleit', u'einzugsgebiete', u'flaechen', u'haltungen', u'linkfl', u'linksw', u'pumpen', u'schaechte', u'teilgebiete', u'tezg', u'wehre' ] # Liste der QKan-Formulare, um individuell erstellte Formulare von der Bearbeitung auszuschliessen formsliste = [ 'qkan_abflussparameter.ui', 'qkan_anbindungageb.ui', 'qkan_anbindungeinleit.ui', 'qkan_anbindungflaechen.ui', 'qkan_auslaesse.ui', 'qkan_auslasstypen.ui', 'qkan_aussengebiete.ui', 'qkan_bodenklassen.ui', 'qkan_einleit.ui', 'qkan_einzugsgebiete.ui', 'qkan_entwaesserungsarten.ui', 'qkan_flaechen.ui', 'qkan_haltungen.ui', 'qkan_profildaten.ui', 'qkan_profile.ui', 'qkan_pumpen.ui', 'qkan_pumpentypen.ui', 'qkan_schaechte.ui', 'qkan_simulationsstatus.ui', 'qkan_speicher.ui', 'qkan_speicherkennlinien.ui', 'qkan_swref.ui', 'qkan_teilgebiete.ui', 'qkan_tezg.ui', 'qkan_wehre.ui' ] # Lesen der Projektdatei ------------------------------------------------------------------ qgsxml = ET.parse(projectTemplate) root = qgsxml.getroot() # Projektionssystem anpassen -------------------------------------------------------------- for tag_maplayer in root.findall(u".//projectlayers/maplayer"): tag_datasource = tag_maplayer.find(u"./datasource") tex = tag_datasource.text # Nur QKan-Tabellen bearbeiten if tex[tex.index(u'table="') + 7:].split(u'" ')[0] in tabliste: # <extend> löschen for tag_extent in tag_maplayer.findall(u"./extent"): tag_maplayer.remove(tag_extent) for tag_spatialrefsys in tag_maplayer.findall( u"./srs/spatialrefsys"): tag_spatialrefsys.clear() elem = ET.SubElement(tag_spatialrefsys, u'proj4') elem.text = proj4text elem = ET.SubElement(tag_spatialrefsys, u'srsid') elem.text = u'{}'.format(srsid) elem = ET.SubElement(tag_spatialrefsys, u'srid') elem.text = u'{}'.format(srid) elem = ET.SubElement(tag_spatialrefsys, u'authid') elem.text = u'EPSG: {}'.format(srid) elem = ET.SubElement(tag_spatialrefsys, u'description') elem.text = description elem = ET.SubElement(tag_spatialrefsys, u'projectionacronym') elem.text = projectionacronym if ellipsoidacronym is not None: elem = ET.SubElement(tag_spatialrefsys, u'ellipsoidacronym') elem.text = ellipsoidacronym # Pfad zu Formularen auf plugin-Verzeichnis setzen ----------------------------------------- formspath = os.path.join(pluginDirectory('qkan'), u"forms") for tag_maplayer in root.findall(u".//projectlayers/maplayer"): tag_editform = tag_maplayer.find(u"./editform") dateiname = os.path.basename(tag_editform.text) if dateiname in formsliste: # Nur QKan-Tabellen bearbeiten tag_editform.text = os.path.join(formspath, dateiname) # Zoom für Kartenfenster einstellen ------------------------------------------------------- for tag_extent in root.findall(u".//mapcanvas/extent"): elem = tag_extent.find(u"./xmin") elem.text = u'{:.3f}'.format(zoomxmin) elem = tag_extent.find(u"./ymin") elem.text = u'{:.3f}'.format(zoomymin) elem = tag_extent.find(u"./xmax") elem.text = u'{:.3f}'.format(zoomxmax) elem = tag_extent.find(u"./ymax") elem.text = u'{:.3f}'.format(zoomymax) # Projektionssystem anpassen -------------------------------------------------------------- for tag_spatialrefsys in root.findall( u".//mapcanvas/destinationsrs/spatialrefsys"): tag_spatialrefsys.clear() elem = ET.SubElement(tag_spatialrefsys, u'proj4') elem.text = proj4text elem = ET.SubElement(tag_spatialrefsys, u'srid') elem.text = u'{}'.format(srid) elem = ET.SubElement(tag_spatialrefsys, u'authid') elem.text = u'EPSG: {}'.format(srid) elem = ET.SubElement(tag_spatialrefsys, u'description') elem.text = description elem = ET.SubElement(tag_spatialrefsys, u'projectionacronym') elem.text = projectionacronym if ellipsoidacronym is not None: elem = ET.SubElement(tag_spatialrefsys, u'ellipsoidacronym') elem.text = ellipsoidacronym # Pfad zur QKan-Datenbank anpassen for tag_datasource in root.findall( u".//projectlayers/maplayer/datasource"): text = tag_datasource.text tag_datasource.text = u"dbname='" + datasource + u"' " + text[ text.find(u'table='):] qgsxml.write(projectFile) # writing modified project file logger.debug(u'Projektdatei: {}'.format(projectFile)) # logger.debug(u'encoded string: {}'.format(tex)) # ------------------------------------------------------------------------------ # Abschluss: Ggfs. Protokoll schreiben und Datenbankverbindungen schliessen iface.mainWindow().statusBar().clearMessage() iface.messageBar().pushMessage( "Information", "Projektdatei ist angepasst und muss neu geladen werden!", level=QgsMessageBar.INFO)