Beispiel #1
0
    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',
            'KKGPlugin_{}.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
        # TODO für unittest auskommentiert
        self.dlg = KKGPluginDialog()

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&kkgplugin')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'KKGPlugin')
        self.toolbar.setObjectName(u'KKGPlugin')
        # Referenz für Interaktion zwischen Handler und QGIS
        Handler.QGIS = self
        # Start server
        self.server = Server(10000)
        self.server.start()
Beispiel #2
0
class KKGPlugin:
    """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',
            'KKGPlugin_{}.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
        # TODO für unittest auskommentiert
        self.dlg = KKGPluginDialog()

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&kkgplugin')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'KKGPlugin')
        self.toolbar.setObjectName(u'KKGPlugin')
        # Referenz für Interaktion zwischen Handler und QGIS
        Handler.QGIS = self
        # Start server
        self.server = Server(10000)
        self.server.start()

    # 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('KKGPlugin', message)

    def add_action(
            self,
            icon_path,
            text,
            callback,
            enabled_flag=True,
            add_to_menu=True,
            add_to_toolbar=True,
            status_tip=None,
            whats_this=None,
            parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/KKGPlugin/img/ic_settings_black_24px.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Layereinstellungen'),
            callback=self.run,
            parent=self.iface.mainWindow()
        )

        icon_path = ':/plugins/KKGPlugin/img/ic_email_black_24px.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Fläche an KKG senden'),
            callback=self.send_area,
            parent=self.iface.mainWindow()
        )

        icon_path = ':/plugins/KKGPlugin/img/ic_playlist_add_black_24px.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Tabellenspalten einfügen'),
            callback=self.add_table_columns,
            parent=self.iface.mainWindow()
        )

        icon_path = ':/plugins/KKGPlugin/img/ic_call_made_black_24px.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Exportieren'),
            callback=self.export_features,
            parent=self.iface.mainWindow()
        )

        icon_path = ':/plugins/KKGPlugin/img/ic_info_black_24px.svg'
        self.add_action(
            icon_path,
            text=self.tr(u'Eigentümerinformationen'),
            callback=self.get_owner_info,
            parent=self.iface.mainWindow()
        )

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&kkgplugin'),
                action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar
        # Server beenden
        self.server.stop()
        self.server.join()
        QgsMessageLog.logMessage("joined", "KKG Plugin Debug", QgsMessageLog.INFO)

    def set_selected_features(self, features):
        """
        wählt die aus der XML von KKG gesendeten Flurstücke in QGIS aus
        :param features: Dictionary der auszuwählenden Features
        :type: dictionary
        :return:
        """
        # Layer soll erzwungen werden
        cond1 = self.dlg.forceCheckBox.isChecked()
        # keine Informationen zum Layer in Daten vorhanden
        cond2 = features['column'] is None or features['layer'] is None


        # Daten aus UI verwenden
        if cond1 or cond2:
            layer = self.dlg.layerCombo.currentText()
            col = self.dlg.keyCombo.currentText()
        # Daten aus XML verwenden
        else:
            col = features['column']
            layer = features['layer']

        assert col is not None and layer is not None

        if col is None or layer is None:
            # TODO raise message
            pass

        # Auswahlstring für QGIS
        filter_expression = u'"{field}" = \'{value}\''

        selection_string = ''.join(filter_expression.format(field=col, value=elem) + " OR " for elem in
                                   features['elems'])
        # Abschließendes " OR " entfernen
        selection_string = selection_string[:-4]
        QgsMessageLog.logMessage(selection_string, "KKG Plugin Debug", QgsMessageLog.INFO)

        layers = QgsMapLayerRegistry.instance().mapLayersByName(layer)
        selection_layer = layers[0]

        selected_elements = selection_layer.getFeatures(QgsFeatureRequest().setFilterExpression(selection_string))


        # Falls Auswahl besteht -> Aufheben
        selection = []
        for elem in selected_elements:
            selection.append(int(elem.id()))
        try:
            # QgsMessageLog.logMessage(selection, "KKG Plugin Debug", QgsMessageLog.INFO)
            selection_layer.setSelectedFeatures([])
            selection_layer.setSelectedFeatures(selection)
            self.iface.setActiveLayer(selection_layer)
            selection_layer.triggerRepaint()
        except Exception as e:
            # TODO logging
            pass

        return self.iface.activeLayer().selectedFeatures()

    def send_area(self, sending="sending"):
        """
        Sendet die aus der ausgewählten Geometrie ermittelten Fläche an KKG
        :return:
        """
        # Fehlermeldung, falls kein Layer oder kein Feature ausgewählt ist.
        active_layer = self.iface.activeLayer()
        if active_layer is None:
            self.raise_message("no_active_layer")
            return
        elif active_layer.selectedFeatureCount() == 0:
            self.raise_message("no_features_selected")
            return
        else:
            selected_features = active_layer.selectedFeatures()
            xml = self._create_xml_to_send(selected_features)
            # None, wenn XML-Generierung fehlschlägt
            if xml is not None:
                self.server.send(config.host, config.out_port, xml)
                return True
            else:
                return False

    def _create_xml_to_send(self, selected_features):
        """

        :param selected_features:
        :return:
        :rtype: String
        """

        event = ElementTree.Element('event', attrib={'xmlns': 'http://gvsigce/ExternalComm'})
        ElementTree.SubElement(event, 'name', attrib={'name': 'KKG-Ereignis', 'version': '1.0.0'})
        actions = ElementTree.SubElement(event, 'actions')
        for feature in selected_features:
            try:
                area = ElementTree.SubElement(actions, 'area', attrib={'value': str(feature.geometry().area())})
                fltr = ElementTree.SubElement(area, 'filter')
                equals = ElementTree.SubElement(fltr, 'property')
                prop = ElementTree.SubElement(equals, 'property')
                # Spaltennamen übergeben?

                if self.dlg.keyCombo.currentText() == "":
                    self.raise_message("no_column_defined")
                    return
                else:
                    prop.text = self.dlg.keyCombo.currentText()

                string = ElementTree.SubElement(equals, 'string')
                string.text = feature.attribute(self.dlg.keyCombo.currentText())
            except KeyError as e:
                QgsMessageLog.logMessage("Fehler bei XML-Erzeugung: " + e.message, "KKG Plugin", QgsMessageLog.WARNING)
                return

        # File vortäuschen, da andernfalls die XML-Declaration nicht erzeugt wird
        fake_file = BytesIO()
        doc = ElementTree.ElementTree(event)
        doc.write(fake_file, encoding='utf-8', xml_declaration=True)
        return fake_file.getvalue()

    def add_table_columns(self):
        """
        Fügt die benötigten Tabellenfelder in die Attributtabelle ein
        :return:
        """

        layer = self.iface.activeLayer()
        QgsMessageLog.logMessage(u"Tabellenfelder werden für " + unicode(layer.name()) + u" erzeugt.")
        if layer is None:
            self.raise_message("no_active_layer")
            return
        else:
            capabilities = layer.dataProvider().capabilities
            field_names = ["geschosse", "gewerbe", "ecke", "lfd. nr."]
            for field in layer.pendingFields():
                if field.name().lower() in field_names:
                    reply = self.raise_message("fields_already_existing")
                    # Überschreiben?
                    if reply == QMessageBox.Yes:
                        if capabilities and QgsVectorDataProvider.DeleteAttributes:
                            data_provider = layer.dataProvider()
                            field_names = data_provider.fieldNameMap()
                            try:
                                data_provider.deleteAttributes([
                                    field_names['geschosse'],
                                    field_names['gewerbe'],
                                    field_names['ecke'],
                                    field_names['lfd. nr.'],
                                    field_names['flaeche'],
                                    field_names['flsnr']
                                ])
                            except KeyError:
                                pass
                            break
                    else:
                        return

        layer.dataProvider().addAttributes([
            QgsField("geschosse", QVariant.Int),
            QgsField("gewerbe", QVariant.Int),
            QgsField("ecke", QVariant.Int),
            QgsField("lfd. nr.", QVariant.String),
            QgsField("flaeche", QVariant.Double),
            QgsField("flsnr", QVariant.String)
        ])
        # Geschosse initial mit 0 belegen
        layer.startEditing()
        field_id = layer.dataProvider().fieldNameMap()[u'geschosse']
        field_id2 = layer.dataProvider().fieldNameMap()[u'flsnr']
        iterator = layer.getFeatures()
        for feature in iterator:
            layer.changeAttributeValue(feature.id(), field_id, 0)
            gml_id = feature.attribute('gml_id')
            fsn = self._get_fsn_from_gml_id(gml_id)[0]['flsnr']
            layer.changeAttributeValue(feature.id(), field_id2, fsn)
        layer.commitChanges()
        layer.updateFields()
        self.raise_message("columns_added")
        QgsMessageLog.logMessage("Tabellenfelder erfolgreich erzeugt", "KKG Plugin", QgsMessageLog.INFO)

    def move_line(self):
        raise NotImplementedError

    def export_features(self):
        """
        Exportiert die Datenbanklayer als ESRI-Shapefile
        :return:
        """
        directory = QFileDialog.getExistingDirectory()
        if not directory:
            return

        # Abfrage, ob Daten überschrieben werden sollen, wenn Verzeichnis nicht leer
        override = True
        if os.listdir(directory):
            reply = self.raise_message("dir_not_empty")
            if reply == QMessageBox.Yes:
                pass
            else:
                override = False

        # Verzeichnis leer oder override = True
        if override:
            # progress bar
            QgsMessageLog.logMessage("Exportiere nach " + directory, "KKG Plugin", QgsMessageLog.INFO)
            layers = QgsMapLayerRegistry.instance().mapLayers().values()
            progress_message_bar = self.iface.messageBar().createMessage("Exportiere...")
            progress = QProgressBar()
            progress.setMaximum(len(layers))
            progress.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
            progress_message_bar.layout().addWidget(progress)
            self.iface.messageBar().pushWidget(progress_message_bar, self.iface.messageBar().INFO)
            # current extent
            extent = self.iface.mapCanvas().extent()

            for i in range(0, len(layers)):
                layer = layers[i]
                file_path = directory + "\\" + layer.name()

                errors = QgsVectorFileWriter.writeAsVectorFormat(layer,
                                                                 file_path,
                                                                 "UTF-8",
                                                                 None,
                                                                 "ESRI Shapefile",
                                                                 filterExtent=extent,
                                                                 symbologyExport=QgsVectorFileWriter.NoSymbology)
                if errors:
                    QgsMessageLog.logMessage(layer.name() + " konnte nicht geschrieben werden.", "KKG Plugin",
                                             QgsMessageLog.WARNING)
                else:
                    QgsMessageLog.logMessage(layer.name() + " erfolgreich geschrieben", "KKG Plugin",
                                             QgsMessageLog.INFO)

                progress.setValue(i + 1)

        self.iface.messageBar().clearWidgets()
        QgsMessageLog.logMessage("Export abgeschlossen", "KKG Plugin", QgsMessageLog.INFO)
        self._create_project_from_export(directory)

    def _create_project_from_export(self, directory):
        """
        Erzeugt eine .qgs-Projektdatei aus den im Verzeichnis enthaltenen Shapefiles, weist die zugehörigen Legenden
        zu und ruft das erzeugte Projekt in einer neuen QGIS-Instanz auf.
        :param directory: Verzeichnis, in dem das Projekt erzeugt werden soll und welches die Shapefiles für das
        Projekt enthält
        :return:
        """
        QgsMessageLog.logMessage("Erstelle Projektdatei...", "KKG Plugin", QgsMessageLog.INFO)
        project_name = os.path.basename(os.path.normpath(directory))
        project_file_name = os.path.basename(os.path.normpath(directory)) + ".qgs"

        directory += "\\"
        if os.path.isfile(os.path.normpath(directory + project_file_name)):
            os.remove(directory + project_file_name)

        project = QgsProject.instance()
        project.clear()
        QgsMapLayerRegistry.instance().removeAllMapLayers()

        root = QgsProject.instance().layerTreeRoot()
        alkis = root.addGroup("ALKIS")

        flurstuecke = alkis.addGroup(u"Flurstücke")

        flaechen_flur = flurstuecke.addGroup(u"Flächen")
        layer1 = QgsVectorLayer(directory + u"Linien (Flurstücke).shp", u"Linien (Flurstücke)", "ogr")
        layer2 = QgsVectorLayer(directory + u"Grenzen (Flurstücke).shp", u"Grenzen (Flurstücke)", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + u"Linien (Flurstücke)_flaechen.qml")
        layer2.loadNamedStyle(config.legend_basepath + u"Grenzen (Flurstücke).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        QgsMapLayerRegistry.instance().addMapLayer(layer2, False)
        flaechen_flur.addLayer(layer1)
        flaechen_flur.addLayer(layer2)

        nummern_flur = flurstuecke.addGroup("Nummern")
        layer1 = QgsVectorLayer(directory + u"Beschriftungen (Flurstücke).shp", u"Beschriftungen (Flurstücke)", "ogr")
        layer2 = QgsVectorLayer(directory + u"Linien (Flurstücke).shp", u"Linien (Flustücke)", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + u"Beschriftungen (Flurstücke).qml")
        layer2.loadNamedStyle(config.legend_basepath + u"Linien (Flurstücke)_nummern.qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        QgsMapLayerRegistry.instance().addMapLayer(layer2, False)
        nummern_flur.addLayer(layer1)
        nummern_flur.addLayer(layer2)

        gebaeude = alkis.addGroup(u"Gebäude")

        gebaeude_gebaeude = gebaeude.addGroup(u"Gebäude")
        layer1 = QgsVectorLayer(directory + u"Beschriftungen (Gebäude).shp", u"Beschriftungen (Gebäude)", "ogr")
        layer2 = QgsVectorLayer(directory + u"Punkte (Gebäude).shp", u"Punkte (Gebäude)", "ogr")
        layer3 = QgsVectorLayer(directory + u"Flächen (Gebäude).shp", u"Flächen (Gebäude).shp", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + u"Beschriftungen (Gebäude).qml")
        layer2.loadNamedStyle(config.legend_basepath + u"Punkte (Gebäude).qml")
        layer3.loadNamedStyle(config.legend_basepath + u"Flächen (Gebäude).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        QgsMapLayerRegistry.instance().addMapLayer(layer2, False)
        QgsMapLayerRegistry.instance().addMapLayer(layer3, False)
        gebaeude_gebaeude.addLayer(layer1)
        gebaeude_gebaeude.addLayer(layer2)
        gebaeude_gebaeude.addLayer(layer3)

        nr_gebaeude = gebaeude.addGroup("Laufende Hausnummern")
        layer1 = QgsVectorLayer(directory + u"Beschriftungen (Gebäude).shp", u"Beschriftungen (Gebäude)", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + u"Beschriftungen (Gebäude).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        nr_gebaeude.addLayer(layer1)

        lagebezeichnung = alkis.addGroup("Lagebezeichnungen")

        beschr_lagebez = lagebezeichnung.addGroup("Beschriftungen")
        layer1 = QgsVectorLayer(directory + "Beschriftungen (Lagebezeichnungen).shp",
                                "Beschriftungen (Lagebezeichnungen)",
                                "ogr")
        layer1.loadNamedStyle(config.legend_basepath + "Beschriftungen (Lagebezeichnungen).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        beschr_lagebez.addLayer(layer1)

        verkehr = alkis.addGroup("Verkehr")
        layer1 = QgsVectorLayer(directory + u"Flächen (Verkehr).shp", u"Flächen (Verkehr)", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + u"Flächen (Verkehr).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        verkehr.addLayer(layer1)

        pol_grenzen = alkis.addGroup("Politische Grenzen")
        layer1 = QgsVectorLayer(directory + "Linien (Politische Grenzen).shp", "Linien (Politische Grenzen)", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + "Linien (Politische Grenzen).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        pol_grenzen.addLayer(layer1)

        industrie = alkis.addGroup("Industrie und Gewerbe")
        layer1 = QgsVectorLayer(directory + u"Flächen (Industrie und Gewerbe).shp",
                                u"Flächen (Industrie und Gewerbe)",
                                "ogr")
        layer1.loadNamedStyle(config.legend_basepath + u"Flächen (Industrie und Gewerbe).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        industrie.addLayer(layer1)

        sport_freizeit = alkis.addGroup("Sport und Freizeit")
        layer1 = QgsVectorLayer("Punkte (Sport und Freizeit).shp", "Punkte (Sport und Freizeit)", "ogr")
        layer1.loadNamedStyle(config.legend_basepath + "Punkte (Sport und Freizeit).qml")
        QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
        sport_freizeit.addLayer(layer1)

        project.setTitle(project_name)
        project.setFileName(directory + project_file_name)
        if project.write():
            QgsMessageLog.logMessage("Projektdatei " + directory + project_file_name + " wurde erfolgreich "
                                                                                       "geschrieben.", "KKG Plugin",
                                     QgsMessageLog.INFO)

            self.iface.messageBar().pushSuccess("Erfolgreich", "Der Inhalt wurde erfolgreich exportiert.")

        if self.raise_message("ask_if_project_start") == QMessageBox.Yes:
            self.iface.mapCanvas().clear()
            QgsMapLayerRegistry.instance().removeAllMapLayers()
            project.read(QFileInfo(directory + project_file_name))
            print project_name
            self.iface.mainWindow().setWindowTitle(project_name)

            QgsMessageLog.logMessage("Exportiertes Projekt wird gestartet", "KKG Plugin", QgsMessageLog.INFO)
            QgsMessageLog.logMessage("Export abgeschlossen, lokales Projekt geladen", "KKG Plugin", QgsMessageLog.INFO)
        else:
            QgsMessageLog.logMessage("Exportiertes Projekt wird nicht gestartet", "KKG Plugin", QgsMessageLog.INFO)

    def get_owner_info(self):
        """
        Fragt die Eigentümerinformationen aus der ALKIS-Datenbank ab und stellt sie im Stil des NorBIT-Plugins dar.
        :return:
        """

        self.map_tool = QgsMapToolEmitPoint(self.iface.mapCanvas())
        self.iface.mapCanvas().setMapTool(self.map_tool)
        self.map_tool.canvasClicked.connect(self._clicked)

    def _clicked(self, point, button):
        if self.iface.activeLayer() is None:
            self.raise_message("no_active_layer")
            return
        # Prüfe, ob Punkt innerhalb des Features
        for feature in self.iface.activeLayer().getFeatures():
            #Falls Punkt in Features
            if feature.geometry().contains(point):
                #hole gml_id
                try:
                    gml_id = feature.attribute('gml_id')
                except KeyError:
                    self.raise_message("no_gml_id_found")
                    return
                break

        # ids = tuple(str(feature.attribute('gml_id')) for feature in selected_features)
        result = self._get_fsn_from_gml_id(gml_id)
        html = self._build_html(result[0]['flsnr'])
        parent = QDialog()
        parent.setWindowTitle(u"Eigentümerinformationen")
        parent.setParent(self.iface.mainWindow())
        parent.setWindowFlags(QtCore.Qt.Window)

        textview = QTextEdit()
        textview.setReadOnly(True)
        textview.setText(html)
        layout = QGridLayout(parent)
        layout.addWidget(textview)
        parent.resize(500, 600)
        parent.show()

    def _get_fsn_from_gml_id(self, feature_list):
        """
        Ruft die Eigentümerinformaionen anhand der gml_id der Flurstücke aus der ALKIS-DB ab.
        :param features: Liste der Features, deren Eigentümerinformationen abgerufen werden sollen
        :type list
        :return: Eigentümerinformationen
        :rtype list
        """
        db = Alkis()
        query = """
        SELECT *
        FROM
	      (SELECT
		    gml_id,
		    (land ||
            gemarkungsnummer ||
            '-' ||
            trim(to_char(flurnummer, '000')) ||
            '-' || trim(to_char(zaehler, '00000')) ||
            '/000') AS flsnr
		    FROM ax_flurstueck) flur
        WHERE flur.gml_id = %s
        """
        return db.query(query, (feature_list,))

    def _build_html(self, fs):
        """
        Weitestgehend aus dem ALKIS-Plugin der Firma norBIT übernommen und auf die eigene Datenbankverbindung
        umgeschriebene Methode zum Abruf der Flurstücksinformationen, wenn die Daten aus der Datenbank ausgespielt
        worden sind.
        Credits to jef-n (https://github.com/jef-n)
        :param fs: Flurstücksnummer des betroffenen Flurstücks
        :type String
        :return: HTML-Repräsentation der Flurstücksinformationen
        :rtype String
        """
        fs = fs.rstrip(' ')
        db = Alkis()

        res = db.query("SELECT 1 FROM pg_attribute WHERE attrelid=(SELECT oid FROM pg_class WHERE "
                       "relname='eignerart') AND attname='anteil'", None)

        if res:
            exists_ea_anteil = (res[0]['?column?'] == 1)
        else:
            exists_ea_anteil = False

        html = ""

        qry = """
            SELECT
                ea.bvnr,
                '' as pz,
                (SELECT eignerart FROM eign_shl WHERE ea.b=b) as eignerart,
                %s as anteil,
                ea.ff_stand AS zhist,
                b.bestdnr,
                b.gbbz,
                b.gbblnr,
                b.bestfl,
                b.ff_stand AS bhist
            FROM eignerart ea
            JOIN bestand b ON ea.bestdnr = b.bestdnr
            WHERE ea.flsnr = '%s'
            ORDER BY zhist,bhist,b""" % ("ea.anteil" if exists_ea_anteil else "''", fs)

        best = db.query(qry, None)

        res = db.query(
            "SELECT f.*,g.gemarkung FROM flurst f LEFT OUTER JOIN gema_shl g ON (f.gemashl=g.gemashl) WHERE "
            "f.flsnr='%s' AND f.ff_stand=0" % fs, None)
        if len(res) == 1:
            res = res[0]
        else:
            QMessageBox.information(None, "Fehler", u"Flurstück %s nicht gefunden.\n[%s]" % (fs, repr(fs)))
            return

        res['datum'] = QDate.currentDate().toString("d. MMMM yyyy")
        res['hist'] = 0

        res['str'] = db.query(
            "SELECT sstr.strname,str.hausnr FROM str_shl sstr JOIN strassen str ON "
            "str.strshl=sstr.strshl WHERE str.flsnr='%s' AND str.ff_stand=0" % fs, None)
        res['nutz'] = db.query(
            "SELECT n21.*, nu.nutzshl, nu.nutzung FROM nutz_21 n21, nutz_shl nu WHERE "
            "n21.flsnr='%s' AND n21.nutzsl=nu.nutzshl AND n21.ff_stand=0" % fs, None)
        res['klas'] = db.query(
            "SELECT kl.*, kls.klf_text FROM klas_3x kl, kls_shl kls WHERE kl.flsnr='%s' AND "
            "kl.klf=kls.klf AND kl.ff_stand=0" % fs, None)
        res['afst'] = db.query(
            "SELECT au.*, af.afst_txt FROM ausfst au,afst_shl af WHERE au.flsnr='%s' AND "
            "au.ausf_st=af.ausf_st AND au.ff_stand=0" % fs, None)
        res['best'] = db.query(
            "SELECT ea.bvnr,'' as pz,(SELECT eignerart FROM eign_shl WHERE ea.b = b) as eignerart,%s as anteil,ea.ff_stand AS zhist,b.bestdnr,b.gbbz,b.gbblnr,b.bestfl,b.ff_stand AS bhist FROM eignerart ea JOIN bestand b ON ea.bestdnr = b.bestdnr WHERE ea.flsnr='%s' ORDER BY zhist,bhist,b" %
            ("ea.anteil" if exists_ea_anteil else "''", fs), None)

        for b in res['best']:
            b['bse'] = db.query("SELECT * FROM eigner WHERE bestdnr='%s' AND ff_stand=0" % b['bestdnr'], None)

        html = u"""
    <HTML xmlns="http://www.w3.org/1999/xhtml">
      <HEAD>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      </HEAD>
      <BODY>
    <style>
    .fls_tab{width:100%%;empty-cells:show}
    .fls_time{text-align:right;width:100%%}
    .fls_headline_col{background-color:#EEEEEE;width:100%%;height:30px;text-align:center;}
    .fls_headline{font-weight:bold;font-size:24px;}
    .fls_col_names{font-weight:bold;}
    .fls_col_values{vertical-align:top;}
    .fls_bst{width:100%%;empty-cells:show}
    .fls_hr{border:dotted 1px;color:#080808;}
    </style>

    <TABLE class="fls_tab" border="0">
        <TR><TD>Flurst&uuml;cksnachweis</TD><TD class="fls_time" colspan="6"><span>%(datum)s</TD></TR>
        <TR><TD colspan="7"><hr style="width:100%%"></TD></TR>
        <TR class="fls_headline_col">
            <TD colspan="7"><span class="fls_headline">Flurst&uuml;cksnachweis<span></TD>
        </TR>
        <TR><TD colspan="7">&nbsp;</TD></TR>
        <TR>
            <TD colspan="7"><h3>Flurst&uuml;ck<hr style="width:100%%"></h3></TD>
        </TR>
        <TR class="fls_col_names">
            <TD width="15%%">Gemarkung</TD>
            <TD width="6%%">Flur</TD>
            <TD width="15%%">Flurst&uuml;ck</TD>
            <TD width="20%%">Flurkarte</TD>
            <TD width="17%%">Entstehung</TD>
            <TD width="17%%">Fortf&uuml;hrung</TD>
            <TD width="5%%">Fl&auml;che</TD>
        </TR>
        <TR class="fls_col_values">
            <TD>%(gemashl)s<br>%(gemarkung)s</TD>
            <TD>%(flr)s</TD>
            <TD>%(flsnrk)s</TD>
            <TD>%(flurknr)s</TD>
            <TD>%(entst)s</TD>
            <TD>%(fortf)s</TD>
            <TD nowrap>%(flsfl)s m&sup2;</TD>
        </TR>
    </TABLE>
    """ % res

        if res['blbnr']:
            html += """
<TABLE border="0" class="fls_tab">
    <TR class="fls_col_names">
        <TD width="21%%"></TD>
        <TD width="79%%">Baulastenblattnr.</TD>
    </TR>
    <TR class="fls_col_values">
        <TD></TD>
        <TD>%(blbnr)s</TD>
    </TR>
</TABLE>
""" % res

        if res['lagebez'] or res['anl_verm']:
            html += """
<TABLE border="0" class="fls_tab">
    <TR class="fls_col_names">
        <TD width="21%%"></TD>
        <TD width="52%%">Lage</TD>
        <TD width="27%%">Anliegervermerk</TD>
    </TR>
    <TR class="fls_col_values">
        <TD></TD>
        <TD>%(lagebez)s</TD>
        <TD>%(anl_verm)s</TD>
    </TR>
</TABLE>
""" % res

        if res['str']:
            html += """
<TABLE border="0" class="fls_tab">
    <TR class="fls_col_names">
        <TD></TD><TD>Strasse</TD><TD>Hausnummer</TD>
    </TR>
"""

            for strres in res['str']:
                html += """
    <TR class="fls_col_values">
        <TD></TD><TD>%(strname)s</TD><TD>%(hausnr)s</TD></TR>
    </TR>
""" % strres

            html += """
</TABLE>
"""

        if res['nutz']:
            html += """
<TABLE border="0" class="fls_tab">
        <TR class="fls_col_names"><TD width="21%%"></TD><TD width="69%%">Nutzung</TD><TD width="10%%">Fl&auml;che</TD></TR>
"""

            for nutz in res['nutz']:
                html += """
        <TR class="fls_col_values"><TD></TD><TD>21%(nutzshl)s - %(nutzung)s</TD><TD nowrap>%(fl)s m&sup2;</TD></TR>
""" % nutz

            html += """
</TABLE>
"""
        else:
            html += """
        <p>Keine Nutzungen.</p>
"""

        if res['klas']:
            html += """
<TABLE border="0" class="fls_tab">
        <TR class="fls_col_names"><TD width="21%%"></TD><TD width="69%%">Klassifizierung</TD><TD width="10%%">Fl&auml;che</TD></TR>
"""

            for klas in res['klas']:
                html += """
        <TR class="fls_col_values"><TD></TD><TD>%(klf_text)s</TD><TD nowrap>%(fl)s m&sup2;</TD></TR>
""" % klas

            html += """
</TABLE>
"""
        else:
            html += """
        <p>Keine Klassifizierungen.</p>
"""

        if res['afst']:
            html += """
<TABLE border="0" class="fls_tab">
        <TR class="fls_col_names"><TD width="21%%"></TD><TD width="79%%">Ausf&uuml;hrende Stelle</TD></TR>
"""

            for afst in res['afst']:
                html += """
        <TR class="fls_col_values"><TD></TD><TD>%(afst_txt)s</TD></TR>
""" % afst

            html += """
</TABLE>
"""
        else:
            html += """
        <p>Keine ausf&uuml;hrenden Stellen.</p>
"""

        if res['best']:
            html += """
<TABLE border="0" class="fls_bst">
        <TR><TD colspan="6"><h3>Best&auml;nde<hr style="width:100%%"></h3></TD></TR>
"""

            for best in res['best']:
                html += """
        <TR class="fls_col_names">
                <TD>Bestandsnummer</TD>
                <TD>Grundbuchbezirk</TD>
                <TD colspan="2">Grundbuchblattnr.</TD>
                <TD>Anteil</TD>
        </TR>
        <TR class="fls_col_values">
                <TD>%(bestdnr)s</TD>
                <TD>%(gbbz)s</TD>
                <TD colspan="2">%(gbblnr)s</TD>
                <TD>%(anteil)s</TD>
        </TR>
        <TR class="fls_col_names">
                <TD></TD>
                <TD>Buchungskennz.</TD>
                <TD>BVNR</TD>
                <TD>PZ</TD>
""" % best

                if res['hist']:
                    html += """
                <TD>Hist. Bestand</TD><TD>Hist. Zuordnung</TD>
"""
                else:
                    html += """
                <TD></TD><TD></TD>
"""

                html += """
        </TR>
        <TR class="fls_col_values">
                <TD></TD>
                <TD>%(eignerart)s</TD>
                <TD>%(bvnr)s</TD>
                <TD>%(pz)s</TD>
""" % best

                html += "<TD>%s</TD>" % ("ja" if res['hist'] and best['bhist'] else "")
                html += "<TD>%s</TD>" % ("ja" if res['hist'] and best['zhist'] else "")

                html += """
        </TR>
"""

                if best['bse']:
                    html += """
        <TR class="fls_col_names"><TD>Anteil</TD><TD colspan="5">Namensinformation</TD></TR>
"""

                    for bse in best['bse']:
                        html += """
        <TR class="fls_col_values">
                <TD>%(antverh)s</TD>
                <TD colspan="5">%(name1)s %(name2)s<br>%(name3)s<br>%(name4)s</TD>
        </TR>
""" % bse
                else:
                    html += """
        <p>Keine Eigner gefunden.</p>
"""

                html += """
        <TR><TD colspan="6"><hr class="fls_hr"></TD></TR>
"""

        html += """
        </TABLE>
</BODY>
</HTML>
"""
        return html

    def raise_message(self, string):
        """
        Sammelmethode für die Ausgabe von MessageBoxes

        :param string: Identifier welche Information auszugeben ist
        :type string: String
        """

        if string == "no_listener_registered":
            text = u'Es wurde ein Event empfangen, es ist jedoch kein Layer registriert. '
            u'Bitte wählen Sie einen Layer und eine Schlüsselspalte in den '
            u'Layereinstellungen (Zahnradsymbol) aus.'
            self.iface.messageBar().pushMessage("Achtung", text, level=QgsMessageBar.WARNING, duration=10)

        elif string == "layer_registered":
            text = u'Der Listener wurde erfolgreich auf die Spalte "%s" im Layer "%s" registiert.' % (
                self.dlg.keyCombo.currentText(), self.dlg.layerCombo.currentText())
            self.iface.messageBar().pushMessage("Info", text, level=QgsMessageBar.INFO, duration=5)

        elif string == "columns_added":
            text = u'Die Spalten wurden der Tabelle erfolgreich hinzugefügt.'
            self.iface.messageBar().pushMessage("Info", text, level=QgsMessageBar.INFO, duration=5)

        elif string == "no_side":
            text = u'Bitte wählen Sie eine Seite aus.'
            self.iface.messageBar().pushMesssage("Fehler", text, level=QgsMessageBar.WARNING, duration=10)


        elif string == "fields_already_existing":
            return \
                QMessageBox.question(
                    self.iface.mainWindow(),
                    u"Felder bereits vorhanden",
                    u"Eines oder mehrere Felder sind bereits vorhanden oder wurden\n"
                    u"bereits hinzugefügt. Sollen die Felder trotzdem hinzugefügt werden?\n"
                    u"VORSICHT: Vorhandene Daten werden dabei überschrieben!",
                    QMessageBox.Yes,
                    QMessageBox.No
                )

        elif string == "no_column_defined":
            QMessageBox.warning(
                self.iface.mainWindow(),
                u'Fehler',
                u'Es wurde keine Schlüsselspalte ausgewählt. Bitte wählen Sie einen Layer und eine\n'
                u'Schlüsselspalte in den Layereinstellungen (Zahnradsymbol) aus.'
            )

        elif string == "no_active_layer":
            text = u'Es ist kein Layer ausgewählt.'
            self.iface.messageBar().pushMessage("Fehler", text, level=QgsMessageBar.WARNING, duration=10)

        elif string == "no_features_selected":
            text = u'Es können keine Daten gesendet werden, da keine Features ausgewählt sind.'
            self.iface.messageBar().pushMessage("Fehler", text, level=QgsMessageBar.WARNING, duration=10)

        elif string == "no_gml_id_found":
            text = u'Die Abfrage der Eigentümerdaten ist fehlgeschlagen, da das benötigte Tabellenfeld nicht gefunden wurde'
            self.iface.messageBar().pushMessage("Fehler", text, level=QgsMessageBar.WARNING, duration=10)

        elif string == "mem_layer_not_supported":
            QMessageBox.information(
                self.iface.mainWindow(),
                u'Memorylayer nicht unterstützt!',
                u'Der verwendete Layer ist ein temporärer Layer, mit\n'
                u'dem die gewünschte Operation nicht möglich ist.\n'
                u'Speichern Sie den Layer als Shapefile (Rechtsklick -> Speichern als...)\n'
                u'und starten Sie den Vorgang erneut'
            )

        elif string == "dir_not_empty":
            return QMessageBox.question(
                self.iface.mainWindow(),
                u"Verzeichnis nicht leer",
                u"Das angegebene Verzeichnis ist nicht leer. Es werden möglicherweise Daten überschrieben,"
                u"was zu Datenverlust führen kann. Möchten Sie dennoch in das angegebene Verzeichnis schreiben?",
                QMessageBox.Yes,
                QMessageBox.No
            )
        elif string == "ask_if_project_start":
            return QMessageBox.question(
                self.iface.mainWindow(),
                u"Projekt öffnen?",
                u"Soll das exportierte Projekt geöffnet werden?",
                QMessageBox.Yes,
                QMessageBox.No
            )

        else:
            text = u'Es ist ein Fehler aufgetreten'
            self.iface.messageBar().pushMessage("Fehler", text, level=QgsMessageBar.CRITICAL, duration=10)

    # noinspection PyPep8Naming
    @QtCore.pyqtSlot(str)
    def onLayerSelectionChange(self, index):
        """
        Fügt die im Shapefile vorhandenen Spaltennamen in die QComboBox für die Auswahl der Schlüsselspalte ein.

        :param index: Index des ausgewählten Objekts
        :type index: Integer
        """

        # Wenn Combobox bei Layerauswahl geleert wird: Event verwerfen
        if index == -1:
            return

        self.dlg.keyCombo.clear()
        layer = self.dlg.layerCombo.itemData(index)
        # Tabellen-Header
        cols = layer.pendingFields()
        # länge ermitteln
        combo_size = self.dlg.keyCombo.count()
        # ComboBox leeren
        for i in range(0, combo_size):
            self.dlg.keyCombo.removeItem(i)
        # Spaltennamen in Header einfügen
        for col in cols:
            self.dlg.keyCombo.addItem(col.name(), layer)

    def run(self):
        """Run method that performs all the real work"""
        # Layerliste leeren
        self.dlg.layerCombo.clear()
        # Layer im Projekt
        layers = QgsMapLayerRegistry.instance().mapLayers().values()
        # Layer in Dropdown-Liste schreiben
        for l in layers:
            if l.type() == QgsMapLayer.VectorLayer:
                self.dlg.layerCombo.addItem(l.name(), l)

        # keyCombo erstmalig mit erstem Layer belegen, falls vorhanden
        index = self.dlg.layerCombo.currentIndex()
        first_layer = self.dlg.layerCombo.itemData(index)
        if first_layer is not None:
            for column in first_layer.pendingFields():
                self.dlg.keyCombo.addItem(column.name(), first_layer)
        # Signal registrieren, wenn sich die Layerauswahl ändert
        self.dlg.layerCombo.currentIndexChanged[int].connect(self.onLayerSelectionChange)
        # Falls aktiver Layer vorhanden, setze als Standard
        active_layer = self.iface.activeLayer()
        if active_layer is not None:
            active_layer_index = self.dlg.layerCombo.findText(active_layer.name())
            self.dlg.layerCombo.setCurrentIndex(active_layer_index)

        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            self.raise_message("layer_registered")