Example #1
0
    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."""
        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
Example #2
0
class QScatterPlugin:
    def __init__(self, iface):
        self.iface = iface

        overrideLocale = QSettings().value('locale/overrideFlag', False, bool)
        if not overrideLocale:
            locale = QLocale.system().name()[:2]
        else:
            locale = QSettings().value('locale/userLocale', '')

        qmPath = '{}/i18n/qscatter_{}.qm'.format(pluginPath, locale)

        if os.path.exists(qmPath):
            self.translator = QTranslator()
            self.translator.load(qmPath)
            QCoreApplication.installTranslator(self.translator)

    def initGui(self):
        self.actionRun = QAction(
            self.tr('QScatter'), self.iface.mainWindow())
        self.actionRun.setIcon(
            QIcon(os.path.join(pluginPath, 'icons', 'qscatter.svg')))
        self.actionRun.setWhatsThis(
            self.tr('Interactive scatter plot'))
        self.actionRun.setObjectName('runQScatter')

        self.actionAbout = QAction(
            self.tr('About...'), self.iface.mainWindow())
        self.actionAbout.setIcon(
            QgsApplication.getThemeIcon('/mActionHelpContents.svg'))
        self.actionAbout.setWhatsThis(self.tr('About QScatter'))
        self.actionRun.setObjectName('aboutQScatter')

        self.iface.addPluginToVectorMenu(
            self.tr('QScatter'), self.actionRun)
        self.iface.addPluginToVectorMenu(
            self.tr('QScatter'), self.actionAbout)
        self.iface.addVectorToolBarIcon(self.actionRun)

        self.actionRun.triggered.connect(self.run)
        self.actionAbout.triggered.connect(self.about)

    def unload(self):
        self.iface.removePluginVectorMenu(
            self.tr('QScatter'), self.actionRun)
        self.iface.removePluginVectorMenu(
            self.tr('QScatter'), self.actionAbout)
        self.iface.removeVectorToolBarIcon(self.actionRun)

    def run(self):
        dlg = QScatterDialog(self.iface)
        dlg.show()
        dlg.exec_()

    def about(self):
        dlg = AboutDialog()
        dlg.exec_()

    def tr(self, text):
        return QCoreApplication.translate('QScatter', text)
class Send2GE:
  def __init__(self, iface):
    """Initialize class"""
    # save reference to QGIS interface
    self.iface = iface
    self.plugin_dir = get_file_dir(__file__)

  def initGui(self):
    """Initialize graphic user interface"""
    #create action that will be run by the plugin
    self.action = QAction(
        QIcon("%s/icons/cursor2.png" % self.plugin_dir),
        "Send to Google Earth",
        self.iface.mainWindow()
    )
    self.action.setWhatsThis("Send to Google Earth")
    self.action.setStatusTip("Send coordinates of a mouse click to Google Earth")
    
    # add plugin menu to Vector toolbar
    self.iface.addPluginToMenu("Send2GoogleEarth",self.action)
    
    # add icon to new menu item in Vector toolbar
    self.iface.addToolBarIcon(self.action)

    # connect action to the run method
    self.action.triggered.connect(self.run)

    # prepare map tool
    self.mapTool = Send2GEtool(self.iface)
    #self.iface.mapCanvas().mapToolSet.connect(self.mapToolChanged)
      
  def unload(self):
    """Actions to run when the plugin is unloaded"""
    # remove menu and icon from the menu
    self.iface.removeToolBarIcon(self.action)
    self.iface.removePluginMenu("Send2GoogleEarth",self.action)

    if self.iface.mapCanvas().mapTool() == self.mapTool:
      self.iface.mapCanvas().unsetMapTool(self.mapTool)

    del self.mapTool

  def run(self):
    """Action to run"""
    # create a string and show it

    self.iface.mapCanvas().setMapTool(self.mapTool)
Example #4
0
    def add_action(
            self,
            icon_path,
            text,
            callback,
            enabled_flag=True,
            checkable=False,
            add_to_menu=True,
            add_to_toolbar=True,
            status_tip=None,
            whats_this=None,
            menu=None,
            parent=None):
        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)
        action.setCheckable(checkable)

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

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

        if menu is not None:
            action.setMenu(menu)

        if add_to_toolbar:
            self.toolbar.addAction(action)

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

        self.actions.append(action)

        return action
    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.

        Parameters
        ----------
        icon_path : str
            Path to the icon for this action. Can be a resource path
            (e.g. ':/plugins/foo/bar.png') or a normal file system path
        text : str
            Text that should be shown in menu items for this action
        callback : function
            Function to be called when the action is triggered
        enabled_flag : bool, optional
            A flag indicating if the action should be enabled by default 
            (defaults to True)
        add_to_menu : bool, optional
            Flag indicating whether the action should also be added to the menu 
            (defaults to True)
        add_to_toolbar : bool, optional
            Flag indicating whether the action should also be added to the toolbar
            (defaults to True)
        status_tip : str or None, optional
            Text to show in a popup when mouse pointer hovers over the action 
            (defaults to None)
        whats_this : str or None, optional
            Text to show in the status bar when the mouse pointer hovers over
            the action (defaults to None)
        parent : QWidget or None, optional
            Parent widget for the new action (defaults to None)
        
        Returns
        ----------
        QAction
            The action that was created. Note that the action is also added to
            self.actions list.
        """

        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:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

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

        self.actions.append(action)

        return action
Example #6
0
class HuntRegister:
    """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__)

        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None

        # This plugin depends on alkisplugin
        self.alkisplugin = None

        # Members
        self.alkisToolBar = None  # the toolbar instance where the alkisplugin and huntplugin QAction symbols are placed

        self.alkisSelectAreaLayer = None  # QgsVectorLayer selected parcels of alkisplugin
        self.huntSelectAreaLayer = None  # QgsVectorLayer selected parcels of huntplugin

        # help web view
        self.helpiew = None  # webview containing manuals

        # All actions are assigned to alter self.huntSelectAreaLayer
        self.hswapAction = None  # single QAction copy selected parcels from alkisplugin to huntplugin
        self.hAddMarkAction = None  # checkable QAction select and unselect parcels
        self.hlistAction = None  # single QAction select parcels by parcel attributes
        self.hclearAction = None  # single QAction unselect all selected parcels
        self.hownerAction = None  # single QAction get parcel certificates for all selected parcels
        self.hhuntAction = None  # single QAction create a hunt register
        self.hinfoAction = None  # single QAction get a basic summary of all selected parcels
        self.helpAction = None  # single QAction open help files webview browser window
        # self.testAction = None                                                                # single QAction used for testing program fragments

        self.hAddMarkTool = None  # click recognizing map tool for self.hAddMarkAction
        self.core = None  # function core for this plugin
        self.initTimer = QTimer(
            self.iface
        )  # timer used to init self.huntSelectAreaLayer dynamically when alkis layers are added
        self.initTimer.setInterval(1000)  # 1 sec interval
        self.initTimer.timeout.connect(self.initLayers)
        self.init()  # init main instances

    def init(self):
        """init main instances"""

        if (alkisAvailable):
            try:
                self.alkisplugin = Alkis.alkisplugin.alkisplugin(
                    self.iface)  # create alkisplugin object
                self.alkisplugin.queryOwnerAction = QAction(
                    None
                )  # this is used in akisplugin "opendb" and must therefore be set to prevent runtime errors
            except AttributeError:
                QMessageBox.critical(
                    None, "Fehler",
                    "norGIS ALKIS-Einbindung zuerst aktivieren und \"JagdKataster\" erneut aktivieren"
                )
                raise AttributeError("alkisplugin not active")
        else:
            QMessageBox.critical(
                None, "Fehler",
                "norGIS ALKIS-Einbindung installieren und zuerst aktivieren. Dann \"JagdKataster\" erneut aktivieren"
            )
            raise AttributeError("alkisplugin not installed")

        self.core = HuntCore(self)  # function core for this plugin

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

        # will be set False in run()
        self.first_start = True

        self.helpview = QWebView()
        self.helpview.resize(1280, 850)
        self.helpview.setWindowTitle("JagdKataster Anleitungen")
        help_dir = os.path.join(self.plugin_dir, "help", "build", "html",
                                "index.html")
        self.helpview.load(QUrl.fromLocalFile(help_dir))

        # the toolbar entries of this plugin should be placed alongside the alkisplugin entries
        # therefore the alkisplugin toolbar is derived
        tBars = self.iface.mainWindow().findChildren(
            QToolBar)  # get all toolbars from main window
        self.alkisToolBar = next(
            (n
             for n in tBars if n.objectName() == "norGIS_ALKIS_Toolbar"), None
        )  # find the instance of alkisplugin toolbar by its static name

        if self.alkisToolBar is None:  # in case the toolbar is not yet loaded create the instance with its static name
            # create alkis toolbar in case it is not yet loaded
            self.alkisToolBar = self.iface.addToolBar(u"norGIS: ALKIS")
            self.alkisToolBar.setObjectName("norGIS_ALKIS_Toolbar")

        #create toolbar items
        self.hswapAction = QAction(QIcon("hunt:mark_transfer.svg"),
                                   "Flächenmarkierung übertragen",
                                   self.iface.mainWindow())
        self.hswapAction.setWhatsThis(
            "Flächenmarkierung (gelb) nach Jagd-Flächenmarkierung (blau) übertragen"
        )
        self.hswapAction.setStatusTip(
            "Flächenmarkierung (gelb) nach Jagd-Flächenmarkierung (blau) übertragen"
        )
        self.hswapAction.triggered.connect(lambda: self.core.swapAlkisToHunt())
        self.alkisToolBar.addAction(self.hswapAction)

        self.hAddMarkAction = QAction(QIcon("hunt:mark_add.svg"),
                                      u"Flurstück (de)selektieren",
                                      self.iface.mainWindow())
        self.hAddMarkAction.setWhatsThis(
            "Flurstück in Jagd-Flächenmarkierung selektieren oder deselektieren"
        )
        self.hAddMarkAction.setStatusTip(
            "Flurstück in Jagd-Flächenmarkierung selektieren oder deselektieren"
        )
        self.hAddMarkAction.setCheckable(True)
        self.hAddMarkAction.triggered.connect(
            lambda: self.iface.mapCanvas().setMapTool(self.hAddMarkTool))
        self.alkisToolBar.addAction(self.hAddMarkAction)
        self.hAddMarkTool = HAdd(self)
        self.hAddMarkTool.setAction(self.hAddMarkAction)

        self.hlistAction = QAction(QIcon("hunt:mark_list.svg"),
                                   "Selektieren nach Flurstückseigenschaft",
                                   self.iface.mainWindow())
        self.hlistAction.setWhatsThis(
            "Selektierung der Flurstücke in Jagd-Flächenmarkierung anhand Flurstückseigenschaften"
        )
        self.hlistAction.setStatusTip(
            "Selektierung der Flurstücke in Jagd-Flächenmarkierung anhand Flurstückseigenschaften"
        )
        self.hlistAction.triggered.connect(
            lambda: self.core.showListSelection())
        self.alkisToolBar.addAction(self.hlistAction)

        self.hclearAction = QAction(QIcon("hunt:mark_clear.svg"),
                                    "Alle deselektieren",
                                    self.iface.mainWindow())
        self.hclearAction.setWhatsThis(
            "Alle Flurstücke in Jagd-Flächenmarkierung deselektieren")
        self.hclearAction.setStatusTip(
            "Alle Flurstücke in Jagd-Flächenmarkierung deselektieren")
        self.hclearAction.triggered.connect(lambda: self.core.clearHighlight())
        self.alkisToolBar.addAction(self.hclearAction)

        self.hownerAction = QAction(QIcon("hunt:mark_own.svg"),
                                    "Flurstücksnachweise anzeigen",
                                    self.iface.mainWindow())
        self.hownerAction.setWhatsThis(
            "Flurstücksnachweise für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen"
        )
        self.hownerAction.setStatusTip(
            "Flurstücksnachweise für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen"
        )
        self.hownerAction.triggered.connect(
            lambda: self.core.showParcelCerts())
        self.alkisToolBar.addAction(self.hownerAction)

        self.hhuntAction = QAction(QIcon("hunt:mark_hunt.svg"),
                                   "Jagdkataster erstellen",
                                   self.iface.mainWindow())
        self.hhuntAction.setWhatsThis(
            "Jagdkataster für selektierte Flurstücke in Jagd-Flächenmarkierung erstellen"
        )
        self.hhuntAction.setStatusTip(
            "Jagdkataster für selektierte Flurstücke in Jagd-Flächenmarkierung erstellen"
        )
        self.hhuntAction.triggered.connect(lambda: self.core.showHuntReg())
        self.alkisToolBar.addAction(self.hhuntAction)

        self.hinfoAction = QAction(QIcon("hunt:mark_info.svg"),
                                   "Flurstückszusammenfassung anzeigen",
                                   self.iface.mainWindow())
        self.hinfoAction.setWhatsThis(
            "Flurstückszusammenfassung für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen"
        )
        self.hinfoAction.setStatusTip(
            "Flurstückszusammenfassung für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen"
        )
        self.hinfoAction.triggered.connect(
            lambda: self.core.showSummaryDialog())
        self.alkisToolBar.addAction(self.hinfoAction)

        self.helpAction = QAction(QIcon("hunt:logo.svg"), "Anleitungen",
                                  self.iface.mainWindow())
        self.helpAction.setWhatsThis("JagdKataster-Anleitungen")
        self.helpAction.setStatusTip("JagdKataster-Anleitungen")
        self.helpAction.triggered.connect(lambda: self.helpview.show())

        # self.testAction = QAction(QIcon("hunt:test.svg"), "Test", self.iface.mainWindow())
        # self.testAction.setWhatsThis("Test action")
        # self.testAction.setStatusTip("Test action")
        # self.testAction.triggered.connect(lambda: self.core.test(self.huntSelectAreaLayer))
        # self.alkisToolBar.addAction(self.testAction)

        self.iface.addPluginToDatabaseMenu("&ALKIS", self.helpAction)

        QgsProject.instance().layersAdded.connect(
            self.initTimer.start
        )  # react to changes in the layer tree. Maybe the alkis layers were added
        QgsProject.instance().layersWillBeRemoved.connect(
            self.layersRemoved
        )  # remove entries in case this plugin layers are to be removed

    def initLayers(self):
        """init self.huntSelectAreaLayer in case the alkis layers from alkisplugin are loaded"""
        self.initTimer.stop(
        )  # this methode may be called by a timer started when layers are added => stop the timer after first timeout event
        if self.alkisSelectAreaLayer is None:  # are alkisplugin layers loaded ad readable from entry?
            (layerId,
             res) = QgsProject.instance().readEntry("alkis",
                                                    "/areaMarkerLayer")
            if res and layerId:
                self.alkisSelectAreaLayer = QgsProject.instance().mapLayer(
                    layerId)
        if self.huntSelectAreaLayer is None:  # is the huntplugin layer already loaded?
            (layerId,
             res) = QgsProject.instance().readEntry("hunt", "/areaMarkerLayer")
            if res and layerId:
                self.huntSelectAreaLayer = QgsProject.instance().mapLayer(
                    layerId)
        if self.huntSelectAreaLayer is None and self.alkisSelectAreaLayer is not None:  # alkisplugin layers are loaded but huntplugin layer is not
            self.createLayer()  # create huntplugin layer

    def layersRemoved(self, layersIds):
        """remove entries and references in case this plugin layers are to be removed"""
        if self.alkisSelectAreaLayer is not None and self.alkisSelectAreaLayer.id(
        ) in layersIds:
            self.alkisSelectAreaLayer = None
        if self.huntSelectAreaLayer is not None and self.huntSelectAreaLayer.id(
        ) in layersIds:
            QgsProject.instance().removeEntry("hunt", "/areaMarkerLayer")
            self.core.hlayer = None
            self.huntSelectAreaLayer = None

    def createLayer(self):
        """create and add huntplugin layer to the layer tree"""
        if (self.alkisSelectAreaLayer is not None):
            parent = QgsProject.instance().layerTreeRoot().findLayer(
                self.alkisSelectAreaLayer).parent()
            layeropts = QgsVectorLayer.LayerOptions(False, False)

            self.init(
            )  # reinit main instances because alkis instance conninfo might have changed
            (db, conninfo) = self.core.openDB()
            if db is None:
                return

            self.huntSelectAreaLayer = QgsVectorLayer(
                u"%s estimatedmetadata=true checkPrimaryKeyUnicity=0 key='ogc_fid' type=MULTIPOLYGON srid=%d table=%s.po_polygons (polygon) sql=false"
                % (conninfo, self.alkisplugin.epsg,
                   self.alkisplugin.quotedschema()), u"Jagd-Flächenmarkierung",
                "postgres", layeropts)

            sym = QgsSymbol.defaultSymbol(QgsWkbTypes.PolygonGeometry)
            sym.setColor(Qt.blue)
            sym.setOpacity(0.3)

            self.huntSelectAreaLayer.setRenderer(QgsSingleSymbolRenderer(sym))
            QgsProject.instance().addMapLayer(self.huntSelectAreaLayer, False)
            parent.insertLayer(0, self.huntSelectAreaLayer)

            self.core.hlayer = None
            QgsProject.instance().writeEntry("hunt", "/areaMarkerLayer",
                                             self.huntSelectAreaLayer.id())

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        if self.hswapAction:
            self.hswapAction.deleteLater()
            self.hswapAction = None
        if self.hAddMarkAction:
            self.hAddMarkAction.deleteLater()
            self.hAddMarkAction = None
        if self.hlistAction:
            self.hlistAction.deleteLater()
            self.hlistAction = None
        if self.hclearAction:
            self.hclearAction.deleteLater()
            self.hclearAction = None
        if self.hownerAction:
            self.hownerAction.deleteLater()
            self.hownerAction = None
        if self.hhuntAction:
            self.hhuntAction.deleteLater()
            self.hhuntAction = None
        if self.hinfoAction:
            self.hinfoAction.deleteLater()
            self.hinfoAction = None
        if self.helpAction:
            self.helpAction.deleteLater()
            self.helpAction = None
        # if self.testAction:
        #     self.testAction.deleteLater()
        #     self.testAction = None

        QgsProject.instance().layersAdded.disconnect(self.initTimer.start)
        QgsProject.instance().layersWillBeRemoved.disconnect(
            self.layersRemoved)

    def run(self):
        """Run method"""
        if self.first_start:
            self.first_start = False
class Cbers4aDownloader:
    """Plugin implementation
    """
    def __init__(self, iface):
        """
        Constructor

        Args:
            iface (qgis.gui.QgisInterface): a reference to the QGIS GUI interface
        """
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        self.dockwidget = None
        self.provider = None
        self.action = None
        self.name = 'CBERS4A Downloader'
        self.about = 'Search and download CBERS4A imagery'
        self.search = None
        self.collections = None
        self.result = None
        self.footprint = QgsRubberBand(iface.mapCanvas(), True)
        self.mux_grid = None
        self.wfi_grid = None
        self.downloading = False
        self.outputfolder = QgsProject.instance().absolutePath() or gettempdir(
        )

    def initProcessing(self):
        self.provider = Provider()
        QgsApplication.processingRegistry().addProvider(self.provider)

    def initGui(self):
        """
        This method is called by QGIS when the main GUI starts up or 
        when the plugin is enabled in the Plugin Manager.
        Only want to register the menu items and toolbar buttons here,
        and connects action with run method.
        """

        self.initProcessing()

        icon = QIcon(':/plugins/cbers4a/cbers4a.svg')
        self.action = QAction(icon, self.name, self.iface.mainWindow())
        self.action.setWhatsThis(self.about)
        self.action.setStatusTip(self.about)
        self.action.setCheckable(True)
        self.action.triggered.connect(self.run)

        # for raster menu/toolbar
        # self.iface.addRasterToolBarIcon(self.action)
        # self.iface.addPluginToRasterMenu(self.name, self.action)

        # for plugin menu/toolbar
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(self.name, self.action)

        # for custom toolbar
        # self.toolbar = self.iface.addToolBar('Plugin')
        # self.toolbar.setObjectName('Plugin')
        # self.toolbar.addAction(self.action)

    def unload(self):
        """
        Will be executed when the plugin is disabled. 
        Either in the Plugin Manager or when QGIS shuts down.
        It removes the previously defined QAction object from
        the menu and remove the plugin icon from the toolbar.
        """

        # disconnect triggers
        if self.search is not None:
            self.iface.mapCanvas().extentsChanged.disconnect(
                self.update_extent)
            self.iface.mapCanvas().destinationCrsChanged.disconnect(
                self.update_extent)
            self.dockwidget.startdate.dateChanged.disconnect(
                self.update_startdate)
            self.dockwidget.enddate.dateChanged.disconnect(self.update_enddate)
            self.iface.projectRead.disconnect(self.update_outputfolder)
            self.iface.newProjectCreated.disconnect(self.update_outputfolder)
            QgsProject.instance().projectSaved.disconnect(
                self.update_outputfolder)
            self.dockwidget.limit.valueChanged.disconnect(self.update_limit)
            self.dockwidget.cloudcover.valueChanged.disconnect(
                self.update_cloudcover)
            self.dockwidget.collection.currentIndexChanged.disconnect(
                self.update_collection)
            self.dockwidget.searchButton.clicked.disconnect(self.do_search)
            self.dockwidget.resultsList.itemClicked.disconnect(self.preview)
            # self.dockwidget.credential.textChanged[str].disconnect(self.credential_changed)
            # self.dockwidget.credential.editingFinished.disconnect(self.credential_filled)
            self.dockwidget.tabs.currentChanged[int].disconnect(
                self.toggle_download_button)
            self.dockwidget.downloadButton.clicked.disconnect(
                self.start_download)
            # footprint pushbutton
            self.dockwidget.footprint.clicked.disconnect(self.toggle_footprint)

            # close search session
            self.search.close()

        # for raster menu/toolbar
        # self.iface.removePluginRasterMenu(self.name, self.action)
        # self.iface.removeRasterToolBarIcon(self.action)

        # for plugin menu/toolbar
        self.iface.removeToolBarIcon(self.action)
        self.iface.removePluginMenu(self.name, self.action)

        # remove canvas item (footprint)
        self.iface.mapCanvas().scene().removeItem(self.footprint)

        if self.dockwidget is not None:
            self.dockwidget.close()
            self.dockwidget.visibilityChanged.disconnect(
                self.visibility_changed)
            self.iface.removeDockWidget(self.dockwidget)
            del self.dockwidget

        # remove custom toolbar
        # if self.toolbar is not None:
        # del self.toolbar

        # remove processing provider
        QgsApplication.processingRegistry().removeProvider(self.provider)

        # clean up task
        try:
            del globals()['cbers4a_tasks']
        except KeyError:
            pass

    def run(self):
        """
        Executes the custom plugin functionality.
        This method is called by the previously defined QAction object (callback), 
        which went into the toolbar icon and the menu entry.
        """
        if self.dockwidget is None:
            self.dockwidget = DockCbers4aDownloader()
            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
            self.dockwidget.visibilityChanged.connect(self.visibility_changed)
            self.init()
            self.dockwidget.show()
        else:
            if self.dockwidget.isVisible():
                self.dockwidget.footprint.setChecked(False)
                self.footprint.hide()
                self.dockwidget.hide()
            else:
                self.dockwidget.show()

    def visibility_changed(self, change):
        """
        Change icon checked status with dockwidget visibility
        """
        self.action.setChecked(change)

    def get_canvas_extent(self):
        """
        Return a tuple with current extent and crs
        """
        crs = self.iface.mapCanvas().mapSettings().destinationCrs()
        extent = self.iface.mapCanvas().extent()
        return extent, crs

    def update_extent(self):
        """
        Update extent from mapcanvas
        """
        current_extent, current_crs = self.get_canvas_extent()
        output_crs = QgsCoordinateReferenceSystem('EPSG:4326')  # WGS84
        transform = QgsCoordinateTransform(current_crs, output_crs,
                                           QgsProject.instance())
        extent = transform.transformBoundingBox(current_extent)
        self.dockwidget.north.setText('{0:.6f}'.format(extent.yMaximum()))
        self.dockwidget.south.setText('{0:.6f}'.format(extent.yMinimum()))
        self.dockwidget.east.setText('{0:.6f}'.format(extent.xMaximum()))
        self.dockwidget.west.setText('{0:.6f}'.format(extent.xMinimum()))
        self.search.bbox([
            extent.xMinimum(),
            extent.yMinimum(),
            extent.xMaximum(),
            extent.yMaximum()
        ])
        # also update footprint
        self.update_footprint()

    def update_startdate(self, new_date):
        defaults = QgsSettings()
        self.dockwidget.enddate.setDate(
            new_date.addDays(int(defaults.value("cbers4a/timespan", 30))))
        self.search.date(
            self.dockwidget.startdate.date().toString('yyyy-MM-dd'),
            self.dockwidget.enddate.date().toString('yyyy-MM-dd'))

    def update_enddate(self, end_date):
        if end_date <= self.dockwidget.startdate.date():
            self.dockwidget.startdate.setDate(end_date.addDays(-1))
        self.search.date(
            self.dockwidget.startdate.date().toString('yyyy-MM-dd'),
            self.dockwidget.enddate.date().toString('yyyy-MM-dd'))

    def update_outputfolder(self):
        """
        Update default output folder on new/read project
        """
        self.outputfolder = QgsProject.instance().absolutePath() or gettempdir(
        )
        self.dockwidget.outputfolder.lineEdit().setPlaceholderText(
            self.outputfolder)

    def update_limit(self):
        """
        Set max number of scenes in the search
        """
        self.search.limit(self.dockwidget.limit.value())

    def update_cloudcover(self):
        """
        Set max cloud cover in the search
        """
        self.search.cloud_cover('<=', self.dockwidget.cloudcover.value())

    def update_collection(self):
        """
        Set collection to search in and valid start and end dates for this collection
        """
        collection_id = self.dockwidget.collection.currentText()
        inpe_collections = {
            description: id
            for id, description in self.collections
        }

        # set collection to search
        self.search.collections([inpe_collections[collection_id]])

        # set valid minimum dates
        mindate = self.collections.get_temporal_extent(
            inpe_collections[collection_id])[0].split('-')
        year, month, day = int(mindate[0]), int(mindate[1]), int(mindate[2])
        self.dockwidget.startdate.setMinimumDate(QDate(year, month, day))
        self.dockwidget.enddate.setMinimumDate(QDate(year, month, day))

        # set valid maximum dates
        self.dockwidget.startdate.setMaximumDate(QDate.currentDate())
        self.dockwidget.enddate.setMaximumDate(QDate.currentDate())

    def do_search(self):
        """
        Run search in INPE STAC Catalog
        """
        self.result = self.search()
        self.dockwidget.resultsList.clear()
        # add items to result list
        # self.dockwidget.resultsList.addItems([str(item) for item in self.result])
        icon = QIcon(":/images/themes/default/mIconRaster.svg")
        for item in self.result:
            list_item = QListWidgetItem(icon, str(item.id),
                                        self.dockwidget.resultsList)
            self.dockwidget.resultsList.addItem(list_item)
        if self.result.complete:
            self.dockwidget.resultsMsg.setText('Returned {0} scenes.'.format(
                self.result.returned))
        else:
            self.dockwidget.resultsMsg.setText(
                'Returned {0} scenes from {1} matched.'.format(
                    self.result.returned, self.result.matched))
        self.dockwidget.tabs.setCurrentIndex(1)
        self.clear_preview()

    def clear_preview(self):
        """
        Clear preview tab
        """
        self.dockwidget.webView.setHtml('')
        self.dockwidget.item_id.clear()
        self.dockwidget.item_date.clear()
        self.dockwidget.item_cloudcover.clear()
        self.dockwidget.footprint.setChecked(False)
        self.footprint.hide()
        self.dockwidget.footprint.setDisabled(True)
        self.dockwidget.assetsList.clear()
        self.dockwidget.assetsList.setDefaultText('')

    def preview(self, item):
        """
        Preview selected scene
        """
        self.clear_preview()
        item_id = item.text()
        self.dockwidget.webView.setHtml(self.result[item_id].html)
        self.dockwidget.item_id.setText(item_id)
        self.dockwidget.item_date.setText('{0}'.format(
            self.result[item_id].date))
        self.dockwidget.item_cloudcover.setText('{0:.1f} %'.format(
            self.result[item_id].cloud_cover))
        self.update_footprint()
        self.dockwidget.footprint.setEnabled(True)
        self.dockwidget.assetsList.setDefaultText('ALL')
        self.dockwidget.assetsList.addItems(self.result[item_id].assets)
        self.dockwidget.tabs.setCurrentIndex(2)

    def toggle_download_button(self, tab):
        """
        Enable/disable download button and hide footprint on tab change
        """
        if tab == 2:
            item_id = self.dockwidget.item_id.text()
            credential = self.dockwidget.credential.text()
            if item_id and credential:
                self.dockwidget.downloadButton.setEnabled(True)
            elif self.downloading:
                self.dockwidget.downloadButton.setEnabled(True)
            else:
                self.dockwidget.downloadButton.setDisabled(True)
        else:
            self.dockwidget.footprint.setChecked(False)
            self.footprint.hide()

        # update valid maximum dates on tab change
        self.dockwidget.startdate.setMaximumDate(QDate.currentDate())
        self.dockwidget.enddate.setMaximumDate(QDate.currentDate())

    def start_download(self):
        """
        Start/cancel task to download item asset(s)
        """
        if self.downloading:
            globals()['cbers4a_tasks'].cancel()
        else:
            item_id = self.dockwidget.item_id.text()
            sel_assets = self.dockwidget.assetsList.checkedItems()
            if sel_assets:
                assets = [asset for asset in sel_assets]
            else:
                assets = self.result[item_id].assets

            #
            # create the task variable with global scope
            # workaround for QGIS Issue #28531
            # https://gis.stackexchange.com/questions/296175/issues-with-qgstask-and-task-manager/304801#304801
            #

            globals()['cbers4a_tasks'] = QgsTask.fromFunction(
                'Download {0}'.format(item_id),
                self.download_asset,
                on_finished=self.download_finished,
                item_id=item_id,
                assets=assets)

            # self.info('Starting task to download {} asset(s)'.format(item_id), duration=1)
            QgsApplication.taskManager().addTask(globals()['cbers4a_tasks'])

            # lock downloading
            self.downloading = True
            self.dockwidget.options.setDisabled(True)
            self.dockwidget.results.setDisabled(True)
            self.dockwidget.downloadButton.setText('Cancel Download')
            self.dockwidget.downloadButton.setStyleSheet(
                'background-color: #ff3336')
            self.dockwidget.assetsList.setDisabled(True)

    def info(self, msg, level=Qgis.Info, duration=5):
        """
        docstring
        """
        self.iface.messageBar().pushMessage(msg, level, duration)

    def log(self, msg, level=Qgis.Info):
        """
        docstring
        """
        QgsMessageLog.logMessage(msg, self.name, level)

    def download_asset(self, task, item_id, assets):
        """
        Task function to download asset(s) for a given item id
        """
        self.log('Started task {}'.format(task.description()))
        credential = self.dockwidget.credential.text()
        collection = self.result[item_id].collection
        outdir = self.dockwidget.outputfolder.lineEdit().text(
        ) or self.outputfolder
        session = self.search.session
        filenames = {}
        for asset in assets:
            url = self.result[item_id].url(asset)
            filename = url.split("/")[-1]
            outfile = os.path.join(outdir, filename)
            r = session.get(url,
                            params={
                                'email': credential,
                                'item_id': item_id,
                                'collection': collection
                            },
                            stream=True,
                            allow_redirects=True)
            if r.status_code == 200:
                total_size = int(r.headers.get('content-length'))
                size = 0
                with open(outfile + '.part', 'wb') as f:
                    for ch in r.iter_content(chunk_size=4096):  # page size 4kb
                        if ch:
                            f.write(ch)
                            size = size + len(ch)
                            progress = (size / total_size) * 100
                            # use task.setProgress to report progress
                            task.setProgress(progress)
                            # check task.isCanceled() to handle cancellation
                            if task.isCanceled():
                                self.log('Task "{name}" was canceled'.format(
                                    name=task.description()))
                                return None
                os.rename(outfile + '.part', outfile)
                self.log(
                    f'Task {task.description()}:\nDownloaded file: {outfile} ({size} of {total_size} bytes)'
                )
                filenames[asset] = outfile
            else:
                raise Exception('ERROR in ' + url + ' (' + r.reason + ')')

        return {
            'description': item_id,
            'filenames': filenames,
            'outdir': outdir
        }

    def download_finished(self, exception, result=None):
        """
        This is called when download_asset is finished.
        Exception is not None if download_asset raises an exception.
        result is the return value of download_asset.
        """

        # VERY SLOW TO DO HERE
        # def __pszXML(nbands):
        #     specband = '\n'.join([f"""<SpectralBand dstBand="{n+1}">\n</SpectralBand>""" for n in range(nbands)])
        #     return f"""<VRTDataset subClass="VRTPansharpenedDataset">
        # <PansharpeningOptions>
        # {specband}
        # </PansharpeningOptions>
        # </VRTDataset>"""

        def __add_images(images,
                         description,
                         outdir,
                         msgbar,
                         check,
                         vrt=True,
                         shown=True):
            if check.isChecked() and vrt:
                pan = images.pop('pan', None)  # take out pan
                if len(images) > 1:
                    # stack images in a VRT file if there are more than one image left
                    vrtfile = os.path.join(outdir, description + '.vrt')
                    # to sort in r/g/b/nir order here sort(images.keys, key=lambda k: rgbn[k])
                    _RGBN = {'red': 1, 'green': 2, 'blue': 3, 'nir': 4}
                    images_keys_ordered = sorted(images.keys(),
                                                 key=lambda k: _RGBN.get(k, 5))
                    filenames = [images[k] for k in images_keys_ordered
                                 ]  # filenames list in RGBN order
                    ds = gdal.BuildVRT(
                        vrtfile,
                        filenames,
                        options=gdal.BuildVRTOptions(separate=True,
                                                     resolution='highest'))
                    for i, bn in enumerate(images_keys_ordered):
                        b = ds.GetRasterBand(i + 1)
                        b.SetDescription(bn)
                    ds.FlushCache()
                    ds = None
                    if pan is None:
                        # nothing to do anymore, add VRT file
                        __add_images({'vrt': vrtfile},
                                     description,
                                     outdir,
                                     msgbar,
                                     check,
                                     vrt=False)
                    else:
                        # VERY SLOW TO DO HERE (perhaps as ProcessingProvider?)
                        # nbands = len(images)
                        # if nbands > 2: # may be a setting here for pansharpening choice
                        #     pan_ds = gdal.Open(pan)
                        #     pansharpened_ds = gdal.CreatePansharpenedVRT(__pszXML(nbands), pan_ds.GetRasterBand(1),
                        #     [ds.GetRasterBand(i + 1) for i in range(nbands)])
                        #     pansharpened_filename = os.path.join(outdir, description + '_pansharpened.vrt')
                        #     driver = gdal.GetDriverByName('VRT')
                        #     driver.CreateCopy(pansharpened_filename, pansharpened_ds, 0)
                        #     # add ALL
                        #     __add_images({'pansharpened': pansharpened_filename,
                        #                 'pan': pan, 'vrt': vrtfile}, description, outdir, msgbar, check, vrt=False, shown=False)
                        # else:
                        #     # just add pan and vrt files
                        __add_images({
                            'pan': pan,
                            'vrt': vrtfile
                        },
                                     description,
                                     outdir,
                                     msgbar,
                                     check,
                                     vrt=False)
                else:
                    # do not stack since there are not enough images
                    assert pan is not None  # 'pan' should be not 'None' here
                    images.update({'pan': pan})  # restore pan
                    __add_images(images,
                                 description,
                                 outdir,
                                 msgbar,
                                 check,
                                 vrt=False)
            else:
                for k in images.keys():
                    fn = images[k]
                    name = os.path.basename(fn).split('.')[0]
                    layer = QgsRasterLayer(fn, name)
                    if layer.isValid():
                        QgsProject.instance().addMapLayer(layer)
                        if not shown:
                            QgsProject.instance().layerTreeRoot().findLayer(
                                layer.id()).setItemVisibilityChecked(shown)
                msgbar.dismiss()

        # unlock another downloading
        self.downloading = False
        self.dockwidget.options.setEnabled(True)
        self.dockwidget.results.setEnabled(True)
        self.dockwidget.downloadButton.setText('Download')
        self.dockwidget.downloadButton.setStyleSheet(
            'background-color: None')  # restore default background color
        self.dockwidget.assetsList.setEnabled(True)

        if exception is None:
            if result is None:
                self.log(
                    'Finished with no exception and no result (probably manually canceled by the user)',
                    level=Qgis.Warning)
            else:
                assets = result['filenames'].keys()
                images = {
                    asset: result['filenames'][asset]
                    for asset in assets
                    if not asset.lower().endswith(('_xml', 'thumbnail'))
                }
                if images:
                    # ask to add image(s) to canvas
                    widget = self.iface.messageBar().createMessage(
                        f"Download {result['description']} finished")
                    button = QPushButton(widget)
                    button.setText('Add image(s)')
                    widget.layout().addWidget(button)
                    check = QCheckBox(widget)
                    check.setText('Stack in VRT file')
                    widget.layout().addWidget(check)
                    if len(images) < 2:
                        check.setDisabled(True)
                    button.clicked.connect(
                        lambda: __add_images(images, result['description'],
                                             result['outdir'], widget, check))
                    self.iface.messageBar().pushWidget(widget, Qgis.Info)
                else:
                    self.info(f"Download {result['description']} finished")
        else:
            self.log("Exception: {}".format(exception), level=Qgis.Critical)
            raise exception

    def toggle_footprint(self):
        """
        Toggle footprint image view on canvas
        """
        if self.dockwidget.footprint.isChecked():
            self.footprint.show()
        else:
            self.footprint.hide()

    def update_footprint(self):
        """
        Update image footprint (image extent)
        """
        item_id = self.dockwidget.item_id.text()
        if item_id and self.result is not None:
            try:
                if self.result[item_id].sensor == 'WFI':
                    geojson = self.wfi_grid[self.result[item_id].path_row]
                else:
                    geojson = self.mux_grid[
                        self.result[item_id].path_row]  # MUX and WPAN
                qgis_geom = QgsGeometry.fromPolygonXY([[
                    QgsPointXY(pt[0], pt[1])
                    for pt in geojson['coordinates'][0]
                ]])
            except KeyError:  # use bbox
                xmin, ymin, xmax, ymax = self.result[item_id].bbox
                qgis_geom = QgsGeometry.fromRect(
                    QgsRectangle(xmin, ymin, xmax, ymax))

            self.footprint.setToGeometry(
                qgis_geom, QgsCoordinateReferenceSystem('EPSG:4326'))
            defaults = QgsSettings()
            self.footprint.setStrokeColor(
                defaults.value("cbers4a/colorstroke", QColor(255, 255, 82)))
            self.footprint.setWidth(3)
            self.toggle_footprint()

    def load_grids(self):
        """
        Load CBERS4A MUX and WFI grids
        """
        # json files
        json_mux = os.path.join(self.plugin_dir, 'grid/cbers4a_mux.json')
        json_wfi = os.path.join(self.plugin_dir, 'grid/cbers4a_wfi.json')

        # read mux grid
        with open(json_mux) as mux:
            self.mux_grid = json.load(mux)

        # read wfi grid
        with open(json_wfi) as wfi:
            self.wfi_grid = json.load(wfi)

    def defaults_settings(self):
        """
        Init plugin settings defaults:
            - cbers4a/colorstroke
            - cbers4a/cloudcover
            - cbers4a/credential
            - cbers4a/timespan
            - cbers4a/limit
        """
        s = QgsSettings()
        if not s.contains("cbers4a/colorstroke"):
            s.setValue("cbers4a/colorstroke", QColor(255, 255, 82))
            s.setValue("cbers4a/cloudcover", 10)
            s.setValue("cbers4a/credential", '')
            s.setValue("cbers4a/timespan", 30)
            s.setValue("cbers4a/limit", 100)

    def init(self):
        """
        Fill options, default values and connect triggers of the dockwidget
        """
        # init settings
        self.defaults_settings()

        # init Search instance
        self.search = Search()

        # get collections
        self.collections = self.search.get_collections()
        inpe_collections = {
            description: id
            for id, description in self.collections
        }

        # load grids
        self.load_grids()

        # connect triggers
        self.iface.mapCanvas().extentsChanged.connect(self.update_extent)
        self.iface.mapCanvas().destinationCrsChanged.connect(
            self.update_extent)
        self.dockwidget.startdate.dateChanged.connect(self.update_startdate)
        self.dockwidget.enddate.dateChanged.connect(self.update_enddate)
        self.iface.projectRead.connect(self.update_outputfolder)
        self.iface.newProjectCreated.connect(self.update_outputfolder)
        QgsProject.instance().projectSaved.connect(self.update_outputfolder)
        self.dockwidget.limit.valueChanged.connect(self.update_limit)
        self.dockwidget.cloudcover.valueChanged.connect(self.update_cloudcover)
        self.dockwidget.collection.currentIndexChanged.connect(
            self.update_collection)
        self.dockwidget.searchButton.clicked.connect(self.do_search)
        self.dockwidget.resultsList.itemClicked.connect(self.preview)
        # self.dockwidget.credential.textChanged[str].connect(self.credential_changed)
        # self.dockwidget.credential.editingFinished.connect(self.credential_filled)
        self.dockwidget.tabs.currentChanged[int].connect(
            self.toggle_download_button)
        self.dockwidget.downloadButton.clicked.connect(self.start_download)
        self.dockwidget.footprint.clicked.connect(self.toggle_footprint)

        # fill collections combobox
        self.dockwidget.collection.addItems(inpe_collections.keys())

        # set defaults
        defaults = QgsSettings()
        self.dockwidget.cloudcover.setValue(
            int(defaults.value("cbers4a/cloudcover", 10)))
        self.dockwidget.limit.setValue(
            int(defaults.value("cbers4a/limit", 100)))
        self.dockwidget.startdate.setDate(QDate.currentDate().addDays(
            -int(defaults.value("cbers4a/timespan", 30))))
        self.dockwidget.credential.setText(
            defaults.value("cbers4a/credential", ''))
        self.update_extent()
        self.update_outputfolder()
        # disable download button
        # self.dockwidget.downloadButton.setDisabled(True)
        # validate credential (seems email)
        # self.dockwidget.credential.clear()
        # validator = QRegExpValidator(QRegExp("[^@]+@[^@]+\.[^@]+"))
        # self.dockwidget.credential.setValidator(validator)

        # disable footprint pushbutton
        self.dockwidget.footprint.setIcon(
            QIcon(':/images/themes/default/mActionShowSelectedLayers.svg'))
        self.dockwidget.footprint.setCheckable(True)
        self.dockwidget.footprint.setDisabled(True)

        self.dockwidget.downloadButton.setText('Download')
        self.dockwidget.assetsList.setDefaultText('')
        # start in first tab
        self.dockwidget.tabs.setCurrentIndex(0)
Example #8
0
class PostNAS_Search:
    def __init__(self, iface):
        # 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',
                                   'PostNAS_Search_{}.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 = PostNAS_SearchDialog(iface=self.iface)
        self.conf = PostNAS_ConfDialog(iface=self.iface)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&PostNAS_Search')

        self.searchDockWidget = None
        self.searchDockWidgetArea = Qt.LeftDockWidgetArea

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('PostNAS_Search', message)

    def initGui(self):
        # Create Conf-Action and Menuentry
        self.confAction = QAction("Einstellungen", self.iface.mainWindow())
        self.confAction.setWhatsThis("Konfiguration der PostNAS-Suche")
        self.confAction.setStatusTip("Konfiguration der PostNAS-Suche")
        self.confAction.triggered.connect(self.showConf)

        if hasattr(self.iface, "addPluginToDatabaseMenu"):
            self.iface.addPluginToDatabaseMenu("&PostNAS-Suche",
                                               self.confAction)
        else:
            self.iface.addPluginToMenu("&PostNAS-Suche", self.confAction)

        self.toggleSearchAction = QAction(u"Flurstücksuche",
                                          self.iface.mainWindow())
        self.toggleSearchAction.setWhatsThis(
            u"Starten/Schliessen der Flurstücksuche")
        self.toggleSearchAction.setStatusTip(
            u"Starten/Schliessen der Flurstücksuche")
        self.toggleSearchAction.triggered.connect(self.toggleWidget)

        if hasattr(self.iface, "addPluginToDatabaseMenu"):
            self.iface.addPluginToDatabaseMenu("&PostNAS-Suche",
                                               self.toggleSearchAction)
        else:
            self.iface.addPluginToMenu("&PostNAS-Suche",
                                       self.toggleSearchAction)

        self.fulltextindex = QAction(u"Volltextindex erstellen",
                                     self.iface.mainWindow())
        self.fulltextindex.setWhatsThis(
            u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen"
        )
        self.fulltextindex.setStatusTip(
            u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen"
        )
        self.fulltextindex.triggered.connect(self.createFulltextindex)

        if hasattr(self.iface, "addPluginToDatabaseMenu"):
            self.iface.addPluginToDatabaseMenu("&PostNAS-Suche",
                                               self.fulltextindex)
        else:
            self.iface.addPluginToMenu("&PostNAS-Suche", self.fulltextindex)

        # Create action that will start plugin configuration
        self.action = QAction(
            QIcon(":/plugins/PostNAS_Search/search_24x24.png"),
            u"Flurstücksuche", self.iface.mainWindow())
        self.action.setCheckable(True)
        # connect the action to the run method
        self.action.triggered.connect(self.toggleWidget)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)

    def toggleWidget(self, event):
        if self.searchDockWidget == None:
            self.searchDockWidget = QDockWidget(self.iface.mainWindow())
            self.searchDockWidget.setWindowTitle(self.tr(u'Suche'))
            self.searchDockWidget.setWidget(self.dlg)
            self.searchDockWidget.closeEvent = self.toggleWidget
            self.iface.addDockWidget(self.searchDockWidgetArea,
                                     self.searchDockWidget)
            self.action.setChecked(True)
        else:
            self.searchDockWidgetArea = self.iface.mainWindow().dockWidgetArea(
                self.searchDockWidget)
            self.iface.removeDockWidget(self.searchDockWidget)
            self.searchDockWidget = None
            self.action.setChecked(False)

    def showConf(self):
        dlg = PostNAS_ConfDialog(self)
        dlg.exec_()

    def createFulltextindex(self):
        dlg = PostNAS_CreateFulltextindex(self)
        dlg.exec_()

    def unload(self):
        # Remove the Toolbar Icon
        self.iface.removeToolBarIcon(self.action)
        # Remove DockWidget
        if self.searchDockWidget != None:
            self.iface.removeDockWidget(self.searchDockWidget)

        if hasattr(self.iface, "removePluginDatabaseMenu"):
            self.iface.removePluginDatabaseMenu("&PostNAS-Suche",
                                                self.confAction)
            self.iface.removePluginDatabaseMenu("&PostNAS-Suche",
                                                self.toggleSearchAction)
            self.iface.removePluginDatabaseMenu("&PostNAS-Suche",
                                                self.fulltextindex)
        else:
            self.iface.removePluginMenu("&PostNAS-Suche", self.confAction)
            self.iface.removePluginMenu("&PostNAS-Suche",
                                        self.toggleSearchAction)
            self.iface.removePluginMenu("&PostNAS-Suche", self.fulltextindex)

        if self.confAction:
            self.confAction.deleteLater()
            self.confAction = None

        if self.toggleSearchAction:
            self.toggleSearchAction.deleteLater()
            self.toggleSearchAction = None

        if self.fulltextindex:
            self.fulltextindex.deleteLater()
            self.fulltextindex = None
Example #9
0
class XYZHubConnector(object):

    """base plugin"""

    def __init__(self, iface):
        """init"""
        import sys
        print(sys.version)
        self.iface = iface
        self.web_menu = "&{name}".format(name=config.PLUGIN_FULL_NAME)
        self.hasGuiInitialized = False
        self.init_modules()
        self.obj = self

    def initGui(self):
        """startup"""

        parent = self.iface.mainWindow()

        ######## action, button

        icon = QIcon("%s/%s" % (config.PLUGIN_DIR,"images/xyz.png"))
        icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR,"images/bbox.svg"))
        self.action_connect = QAction(icon, "XYZ Hub Connection", parent)
        self.action_connect.setWhatsThis(
            QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message" ))
        self.action_connect.setStatusTip(
            QCoreApplication.translate(PLUGIN_NAME, "status tip message" ))

        self.action_sync_edit = QAction( QIcon("%s/%s" % (config.PLUGIN_DIR,"images/sync.svg")), "Push changes to XYZ Hub", parent)

        self.action_clear_cache = QAction( QIcon("%s/%s" % (config.PLUGIN_DIR,"images/delete.svg")), "Clear cache", parent)

        # self.action_sync_edit.setVisible(False) # disable magic sync
        self.edit_buffer.config_ui(self.enable_sync_btn)
        
        self.cb_layer_selected(self.iface.activeLayer())

        ######## CONNECT action, button

        self.action_connect.triggered.connect(self.open_connection_dialog)
        self.action_sync_edit.triggered.connect(self.open_sync_edit_dialog)
        self.action_clear_cache.triggered.connect( self.open_clear_cache_dialog)

        ######## Add the toolbar + button
        self.toolbar = self.iface.addToolBar(PLUGIN_NAME)
        self.toolbar.setObjectName(config.PLUGIN_FULL_NAME)

        self.actions_menu = [self.action_connect, self.action_sync_edit, self.action_clear_cache] 

        for a in [self.action_connect, self.action_sync_edit]:
            self.toolbar.addAction(a)

        for a in self.actions_menu:
            self.iface.addPluginToWebMenu(self.web_menu, a)

        # # uncomment to use menu button
        # tool_btn = QToolButton(self.toolbar)
        # tool_btn.setDefaultAction(self.action_connect)
        # tool_btn.setPopupMode(tool_btn.MenuButtonPopup)
        # self.xyz_widget_action = self.toolbar.addWidget(tool_btn) # uncomment to use menu button

        # self.toolbar.addAction(self.action_connect)

        self.action_help = None

        progress = QProgressBar()
        progress.setMinimum(0)
        progress.setMaximum(0)
        progress.reset()
        progress.hide()
        # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis
        self.iface.statusBarIface().addPermanentWidget(progress)
        self.pb = progress

        # btn_toggle_edit = self.get_btn_toggle_edit()
        # btn_toggle_edit.toggled.connect(lambda *a: print("toggled", a))

        self.hasGuiInitialized = True

    # unused
    def get_btn_toggle_edit(self):
        text_toggle_edit = "toggle editing"
        toolbar = self.iface.digitizeToolBar()
        mapping = dict(
            (w.text().lower() if hasattr(w,"text") else str(i), w)
            for i, w in enumerate(toolbar.children())
        )
        return mapping[text_toggle_edit]

    def new_session(self):
        self.con_man.reset()
        self.edit_buffer.reset()
        self.pending_delete_qnodes.clear()
        
        if self.hasGuiInitialized:
            self.pb.hide()

    def init_modules(self):
        if LOG_TO_FILE:
            QgsApplication.messageLog().messageReceived.connect(cb_log_qgis) #, Qt.QueuedConnection
        connect_global_error_signal(self.log_err_traceback)

        # util.init_module()

        # parent = self.iface.mainWindow()
        parent = QgsProject.instance()

        self.secret = Secret(config.USER_PLUGIN_DIR +"/secret.ini")
        ######## Init xyz modules
        self.map_basemap_meta = basemap.load_default_xml()
        self.auth_manager = AuthManager(config.USER_PLUGIN_DIR +"/auth.ini")
        
        self.network = NetManager(parent)
        
        self.con_man = LoaderManager()
        self.con_man.config(self.network)
        self.edit_buffer = EditBuffer()
        ######## data flow
        # self.conn_info = SpaceConnectionInfo()
        
        ######## token      
        self.token_config = ServerTokenConfig(config.USER_PLUGIN_DIR +"/token.ini", parent)
        self.token_config.set_default_servers(net_utils.API_URL)
        self.token_model = self.token_config.get_token_model()
        self.server_model = self.token_config.get_server_model()

        ######## CALLBACK
        
        self.con_man.ld_pool.signal.progress.connect( self.cb_progress_busy) #, Qt.QueuedConnection
        self.con_man.ld_pool.signal.finished.connect( self.cb_progress_done)
        
        QgsProject.instance().cleared.connect(self.new_session)
        QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.edit_buffer.remove_layers)
        # QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.layer_man.remove_layers)

        # QgsProject.instance().layersAdded.connect( self.edit_buffer.config_connection)

        self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT

        canvas = self.iface.mapCanvas()
        self.lastRect = bbox_utils.extent_to_rect(bbox_utils.get_bounding_box(canvas))
        self.iface.mapCanvas().extentsChanged.connect( self.reload_tile, Qt.QueuedConnection)

        # handle move, delete xyz layer group
        self.pending_delete_qnodes = dict()
        QgsProject.instance().layerTreeRoot().willRemoveChildren.connect(self.cb_qnodes_deleting)
        QgsProject.instance().layerTreeRoot().removedChildren.connect(self.cb_qnodes_deleted)
        QgsProject.instance().layerTreeRoot().visibilityChanged.connect(self.cb_qnode_visibility_changed)
        

        QgsProject.instance().readProject.connect( self.import_project)
        self.import_project()

    def unload_modules(self):
        # self.con_man.disconnect_ux( self.iface)
        QgsProject.instance().cleared.disconnect(self.new_session)
        QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.edit_buffer.remove_layers)
        # QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.layer_man.remove_layers)

        # QgsProject.instance().layersAdded.disconnect( self.edit_buffer.config_connection)
        self.edit_buffer.unload_connection()

        self.con_man.unload()

        self.iface.currentLayerChanged.disconnect( self.cb_layer_selected) # UNCOMMENT

        self.iface.mapCanvas().extentsChanged.disconnect( self.reload_tile)
        
        QgsProject.instance().layerTreeRoot().willRemoveChildren.disconnect(self.cb_qnodes_deleting)
        QgsProject.instance().layerTreeRoot().removedChildren.disconnect(self.cb_qnodes_deleted)
        QgsProject.instance().layerTreeRoot().visibilityChanged.disconnect(self.cb_qnode_visibility_changed)

        QgsProject.instance().readProject.disconnect( self.import_project)
        
        # utils.disconnect_silent(self.iface.currentLayerChanged)

        self.secret.deactivate()
        
        disconnect_global_error_signal()
        if LOG_TO_FILE:
            QgsApplication.messageLog().messageReceived.disconnect(cb_log_qgis)
        # close_file_logger()
        pass
    def unload(self):
        """teardown"""
        self.unload_modules()
        # remove the plugin menu item and icon
        self.iface.removePluginWebMenu(self.web_menu, self.action_help)

        self.toolbar.clear() # remove action from custom toolbar (toolbar still exist)
        self.toolbar.deleteLater()

        for a in self.actions_menu:
            self.iface.removePluginWebMenu(self.web_menu, a)
        # remove progress
        self.iface.statusBarIface().removeWidget(self.pb)

    ############### 
    # Callback
    ###############
    def cb_layer_selected(self, qlayer):
        flag_xyz = True if qlayer is not None and is_xyz_supported_layer(qlayer) else False
        if flag_xyz: 
            self.edit_buffer.config_connection([qlayer])
            self.edit_buffer.enable_ui(qlayer.id())
        else:
            msg = "No XYZHub Layer selected"
            self.enable_sync_btn(False, msg)
        # disable magic sync
        # self.action_sync_edit.setEnabled(flag_xyz)
    def enable_sync_btn(self, flag, msg=""):
        msg = msg or ("No changes detected since last push" if not flag else "Push changes")
        self.action_sync_edit.setToolTip(msg)
        self.action_sync_edit.setEnabled(flag)
        
    ############### 
    # Callback of action (main function)
    ###############
    
    def show_info_msgbar(self, title, msg="", dt=3):
        self.iface.messageBar().pushMessage(
            config.TAG_PLUGIN, ": ".join([title,msg]),
            Qgis.Info, dt
        )

    def show_warning_msgbar(self, title, msg="", dt=3):
        self.iface.messageBar().pushMessage(
            config.TAG_PLUGIN, ": ".join([title,msg]),
            Qgis.Warning, dt
        )

    def show_success_msgbar(self, title, msg="", dt=3):
        self.iface.messageBar().pushMessage(
            config.TAG_PLUGIN, ": ".join([title,msg]),
            Qgis.Success, dt
        )

    def make_cb_success(self, title, msg="", dt=3):
        def _cb_success_msg():
            self.show_success_msgbar(title, msg, dt=dt)
        return _cb_success_msg
        
    def make_cb_success_args(self, title, msg="", dt=3):
        def _cb_success_msg(args):
            a, kw = parse_qt_args(args)
            txt = ". ".join(map(str,a))
            self.show_success_msgbar(title, txt, dt=dt)
        return _cb_success_msg

    def make_cb_info_args(self, title, msg="", dt=3):
        def _cb_info_msg(args):
            a, kw = parse_qt_args(args)
            txt = ". ".join(map(str,a))
            self.show_info_msgbar(title, txt, dt=dt)
        return _cb_info_msg

    def cb_handle_error_msg(self, e):
        err = parse_exception_obj(e)
        if isinstance(err, ChainInterrupt):
            e0, idx = err.args[0:2]
        else:
            e0 = err
        if isinstance(e0, (net_handler.NetworkError, net_handler.NetworkTimeout)):
            ok = self.show_net_err(e0)
            if ok: return
        elif isinstance(e0, EmptyXYZSpaceError):
            ret = exec_warning_dialog("XYZ Hub","Requested query returns no features")
            return
        elif isinstance(e0, ManualInterrupt):
            self.log_err_traceback(e0)
            return
        self.show_err_msgbar(err)

    def show_net_err(self, err):
        reply_tag, status, reason, body, err_str, url = err.args[:6]
        if reply_tag in ["count", "statistics"]: # too many error
            # msg = "Network Error: %s: %s. %s"%(status, reason, err_str)
            return 1
            
        detail = "\n". join(["Request:", url,"","Response:", body])
        msg = (
            "%s: %s\n"%(status,reason) + 
            "There was a problem connecting to the server"
        )
        if status in [401,403]:
            msg += ("\n\n" + "Please input valid token with correct permissions." + "\n" +
            "Token is generated via " +
            "<a href='https://xyz.api.here.com/token-ui/'>https://xyz.api.here.com/token-ui/</a>")
        ret = exec_warning_dialog("Network Error",msg, detail)
        return 1

    def show_err_msgbar(self, err):
        self.iface.messageBar().pushMessage(
            config.TAG_PLUGIN, repr(err),
            Qgis.Warning, 3
        )
        self.log_err_traceback(err)

    def log_err_traceback(self, err):
        msg = format_traceback(err)
        QgsMessageLog.logMessage( msg, config.TAG_PLUGIN, Qgis.Warning)

    def cb_progress_busy(self, n_active):
        if n_active > 1: return
        self.flag_pb_show=True
        self.cb_progress_refresh()

    def cb_progress_done(self):
        self.flag_pb_show=False
        self.cb_progress_refresh()

    def cb_progress_refresh(self):
        if not hasattr(self,"flag_pb_show"): return

        pb = self.pb
        if self.flag_pb_show:
            pb.show()
            # print_qgis("show",pb)
        else:
            pb.hide()        
            # print_qgis("hide")
            
    ############### 
    # Action (main function)
    ###############

    # UNUSED
    def refresh_canvas(self):
        # self.iface.activeLayer().triggerRepaint()
        self.iface.mapCanvas().refresh()
    def previous_canvas_extent(self):
        self.iface.mapCanvas().zoomToPreviousExtent()
    #
    
    def new_main_dialog(self):
        parent = self.iface.mainWindow()
        dialog = MainDialog(parent)

        dialog.config(self.token_model, self.server_model)
        # dialog.config_secret(self.secret)
        auth = self.auth_manager.get_auth()
        dialog.config_basemap(self.map_basemap_meta, auth)

        con = self.con_man.make_con("create")
        con.signal.finished.connect( dialog.btn_use.clicked.emit ) # can be optimized !!
        con.signal.error.connect( self.cb_handle_error_msg )

        con = self.con_man.make_con("list")
        con.signal.results.connect( make_fun_args(dialog.cb_display_spaces) )
        con.signal.error.connect( self.cb_handle_error_msg )
        con.signal.error.connect( lambda e: dialog.cb_enable_token_ui() )
        con.signal.finished.connect( dialog.cb_enable_token_ui )
        con.signal.finished.connect( dialog.ui_valid_token )

        con = self.con_man.make_con("edit")
        con.signal.finished.connect( dialog.btn_use.clicked.emit )
        con.signal.error.connect( self.cb_handle_error_msg )

        con = self.con_man.make_con("delete")
        con.signal.results.connect( dialog.btn_use.clicked.emit )
        con.signal.error.connect( self.cb_handle_error_msg )

        con = self.con_man.make_con("stat")
        con.signal.results.connect( make_fun_args(dialog.cb_display_space_count) )
        con.signal.error.connect( self.cb_handle_error_msg )

        ############ clear cache btn
        dialog.signal_clear_cache.connect( self.open_clear_cache_dialog)
        
        ############ add map tile btn
        dialog.signal_add_basemap.connect( self.add_basemap_layer)
        
        ############ btn: new, edit, delete space   
        dialog.signal_new_space.connect(self.start_new_space)
        dialog.signal_edit_space.connect(self.start_edit_space)
        dialog.signal_del_space.connect(self.start_delete_space)

        ############ Use Token btn        
        dialog.signal_use_token.connect( lambda a: self.con_man.finish_fast())
        dialog.signal_use_token.connect(self.start_use_token)

        ############ get count        
        dialog.signal_space_count.connect(self.start_count_feat, Qt.QueuedConnection) # queued -> non-blocking ui

        ############ connect btn        
        # dialog.signal_space_connect.connect(self.start_load_layer)
        dialog.signal_space_connect.connect(self.start_loading)
        dialog.signal_space_tile.connect(self.start_load_tile)

        ############ upload btn        
        dialog.signal_upload_space.connect(self.start_upload_space)
        
        return dialog
    def start_new_space(self, args):
        con = self.con_man.get_con("create")
        con.start_args(args)

    def start_edit_space(self, args):
        con = self.con_man.get_con("edit")
        con.start_args(args)

    def start_delete_space(self, args):
        con = self.con_man.get_con("delete")
        con.start_args(args)

    def start_use_token(self, args):
        con = self.con_man.get_con("list")
        con.start_args(args)

    def start_count_feat(self, args):
        con = self.con_man.get_con("stat")
        con.start_args(args)

    def start_upload_space(self, args):
        con_upload = UploadLayerController(self.network, n_parallel=2)
        self.con_man.add_on_demand_controller(con_upload)
        # con_upload.signal.finished.connect( self.make_cb_success("Uploading finish") )
        con_upload.signal.results.connect( self.make_cb_success_args("Uploading finish", dt=4))
        con_upload.signal.error.connect( self.cb_handle_error_msg )
        
        con = InitUploadLayerController(self.network)
        self.con_man.add_on_demand_controller(con)

        con.signal.results.connect( con_upload.start_args)
        con.signal.error.connect( self.cb_handle_error_msg )

        con.start_args(args)
    def start_load_layer(self, args):
        # create new con
        # config
        # run
        
        ############ connect btn        
        con_load = LoadLayerController(self.network, n_parallel=1)
        self.con_man.add_on_demand_controller(con_load)
        # con_load.signal.finished.connect( self.make_cb_success("Loading finish") )
        con_load.signal.results.connect( self.make_cb_success_args("Loading finish") )
        # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_load.signal.error.connect( self.cb_handle_error_msg )

        con_load.start_args(args)

        # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT
    def start_load_tile(self, args):
        # rect = (-180,-90,180,90)
        # level = 0
        a, kw = parse_qt_args(args)
        kw.update(self.make_tile_params())
        # kw["limit"] = 100

        ############ connect btn        
        con_load = TileLayerLoader(self.network, n_parallel=1)
        self.con_man.add_persistent_loader(con_load)
        # con_load.signal.finished.connect( self.make_cb_success("Tiles loaded") )
        con_load.signal.results.connect( self.make_cb_success_args("Tiles loaded", dt=2) )
        # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_load.signal.error.connect( self.cb_handle_error_msg )

        con_load.start_args( make_qt_args(*a, **kw))

    def make_tile_params(self, rect=None, level=None):
        if not rect:
            canvas = self.iface.mapCanvas()
            rect = bbox_utils.extent_to_rect(
                bbox_utils.get_bounding_box(canvas))
            level = tile_utils.get_zoom_for_current_map_scale(canvas)
        schema = "web"
        kw = dict()
        kw["tile_schema"] = schema
        kw["tile_ids"] = tile_utils.bboxToListColRow(*rect,level, schema=schema)
        return kw

    def start_loading(self, args):
        a, kw = parse_qt_args(args)
        loading_mode = kw.get("loading_mode")
        try:
            con_load = self.make_loader_from_mode(loading_mode)
        except Exception as e:
            self.show_err_msgbar(e)
            return

        if loading_mode == LOADING_MODES.STATIC:
            con_load.start_args(args)
        else:
            kw.update(self.make_tile_params())
            con_load.start_args( make_qt_args(*a, **kw))


    def iter_checked_xyz_subnode(self):
        """ iterate through visible xyz nodes (vector layer and group node)
        """
        root = QgsProject.instance().layerTreeRoot()
        for vl in root.checkedLayers():
            if is_xyz_supported_layer(vl):
                yield vl
        for g in iter_group_node(root):
            if (len(g.findLayers()) == 0 
                and g.isVisible()
                and is_xyz_supported_node(g)):
                yield g

    def iter_all_xyz_node(self):
        """ iterate through xyz group nodes
        """
        for qnode in self._iter_all_xyz_node():
            yield qnode

    def iter_update_all_xyz_node(self):
        """ iterate through xyz group nodes, with meta version check and updated.
        """
        for qnode in self._iter_all_xyz_node(fn_node=updated_xyz_node):
            yield qnode

    def _iter_all_xyz_node(self, fn_node=lambda a: None):
        """ iterate through xyz group nodes, with custom function fn_node applied to every node
        """
        root = QgsProject.instance().layerTreeRoot()
        for g in iter_group_node(root):
            fn_node(g)
            if is_xyz_supported_node(g):
                yield g
    
    def extent_action(self, rect0, rect1):
        diff = [r0 - r1 for r0,r1 in zip(rect0,rect1)]
        x_sign = diff[0] * diff[2]
        y_sign = diff[1] * diff[3]
        if x_sign >= 0 and y_sign >= 0: # same direction
            return "pan"
        elif x_sign < 0 and y_sign < 0:
            return "zoom"
        elif x_sign * y_sign == 0 and x_sign + y_sign < 0:
            return "resize"
        else:
            return "unknown"

    def reload_tile(self):
        canvas = self.iface.mapCanvas()
        rect = bbox_utils.extent_to_rect(bbox_utils.get_bounding_box(canvas))
        ext_action = self.extent_action(rect,self.lastRect)
        print_qgis("Extent action: ", ext_action,rect)
        self.lastRect = rect
        if ext_action not in ["pan", "zoom"]: 
            return
        level = tile_utils.get_zoom_for_current_map_scale(canvas)
        kw = self.make_tile_params(rect, level)
        # kw["limit"] = 100

        lst_con = self._get_lst_reloading_con()
        for con in lst_con:
            print_qgis(con.status)
            print_qgis("loading tile", level, rect)
            con.restart(**kw)

    def _get_lst_reloading_con(self):
        """ Return list of loader to be reload, that has
        + any vlayer in group is visible
        + and no vlayer in group is in edit mode
        """
        editing_xid = set()
        unique_xid = set()
        for qnode in self.iter_checked_xyz_subnode():
            xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
            if xlayer_id in editing_xid: continue
            if hasattr(qnode, "isEditable") and qnode.isEditable():
                editing_xid.add(xlayer_id)
                continue
            con = self.con_man.get_interactive_loader(xlayer_id)
            if (con and con.layer and
                self.is_all_layer_edit_buffer_empty(con.layer)
            ):
                unique_xid.add(xlayer_id)
            else:
                continue
        
        # print_qgis(editing_xid, unique_xid)
        # print_qgis(unique_xid.difference(editing_xid))
        # print_qgis(self.con_man._layer_ptr)
        
        return [
            self.con_man.get_interactive_loader(xlayer_id)
            for xlayer_id in unique_xid.difference(editing_xid)
        ]
                

    def is_all_layer_edit_buffer_empty(self, layer: XYZLayer) -> bool:
        return all(
            layer_buffer.is_empty()
            for layer_buffer in (
                self.edit_buffer.get_layer_buffer(vlayer.id())
                for vlayer in layer.iter_layer()
            ) if layer_buffer
        )

    def add_basemap_layer(self, args):
        a, kw = parse_qt_args(args)
        meta, app_id, app_code, api_key = a
        self.auth_manager.save(app_id, app_code, api_key)
        basemap.add_basemap_layer( meta, app_id, app_code, api_key)

    ############### 
    # import project function
    ###############

    def import_project(self):
        self.init_all_layer_loader()

        # # restart static loader once
        # for con in self.con_man.get_all_static_loader():
        #     # truncate all feature 
        #     con.restart()

    def make_loader_from_mode(self, loading_mode, layer=None):
        if loading_mode not in LOADING_MODES:
            raise InvalidLoadingMode(loading_mode)
        option = dict(zip(LOADING_MODES, [
            (LiveTileLayerLoader, self.con_man.add_persistent_loader, self.make_cb_success_args("Tiles loaded", dt=2)),
            (TileLayerLoader, self.con_man.add_persistent_loader, self.make_cb_success_args("Tiles loaded", dt=2)),
            (LoadLayerController, self.con_man.add_static_loader, self.make_cb_success_args("Loading finish", dt=3))
            ])).get(loading_mode)
        if not option:
            return

        loader_class, fn_register, cb_success_args = option
        con_load = loader_class(self.network, n_parallel=1, layer=layer)
        con_load.signal.results.connect( cb_success_args)
        con_load.signal.error.connect( self.cb_handle_error_msg )

        cb_info = self.make_cb_info_args("Loading status", dt=3)
        con_load.signal.info.connect( cb_info)

        ptr = fn_register(con_load)
        return con_load


    def init_layer_loader(self, qnode):
        layer = XYZLayer.load_from_qnode(qnode)
        loading_mode = layer.loader_params.get("loading_mode")
        if loading_mode not in LOADING_MODES:
            # # approach 1: backward compatible, import project
            # # invalid loading mode default to live
            # old = loading_mode
            # loading_mode = LOADING_MODES.LIVE
            # layer.update_loader_params(loading_mode=loading_mode) # save new loading_mode to layer
            # # TODO prompt user for handling invalid loading mode layer
            # self.show_info_msgbar("Import XYZ Layer", 
            #     "Undefined loading mode: %s, " % old +  
            #     "default to %s loading " % (loading_mode) +
            #     "(layer: %s)" % layer.get_name())

            # approach 2: not backward compatible, but no data loss
            self.show_warning_msgbar("Import XYZ Layer", 
                "Undefined loading mode: %s, " % loading_mode + 
                "loading disabled " +
                "(layer: %s)" % layer.get_name())
            return
            
        return self.make_loader_from_mode(loading_mode, layer=layer)

    def init_all_layer_loader(self):
        cnt = 0
        for qnode in self.iter_update_all_xyz_node():
            xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
            con = self.con_man.get_loader(xlayer_id)
            if con: continue
            try: 
                con = self.init_layer_loader(qnode)
                if not con: continue
                cnt += 1
            except Exception as e:
                self.show_err_msgbar(e)
                

        # print_qgis(self.con_man._layer_ptr)
        self.show_success_msgbar("Import XYZ Layer", "%s XYZ Layer imported"%cnt, dt=2)


    def cb_qnode_visibility_changed(self, qnode):
        if qnode.isVisible(): return
        xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
        con = self.con_man.get_interactive_loader(xlayer_id)
        if con:
            con.stop_loading()

    def cb_qnodes_deleting(self, parent, i0, i1):
        key = (parent,i0,i1)
        is_parent_root = not parent.parent()
        lst = parent.children()
        for i in range(i0, i1+1):
            qnode = lst[i]
            if (is_parent_root and is_xyz_supported_node(qnode)):
                xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
                self.pending_delete_qnodes.setdefault(key, list()).append(xlayer_id)
                self.con_man.remove_persistent_loader(xlayer_id)
            # is possible to handle vlayer delete here
            # instead of handle in layer.py via callbacks

    def cb_qnodes_deleted(self, parent, i0, i1):
        key = (parent,i0,i1)
        for xlayer_id in self.pending_delete_qnodes.pop(key, list()):
            self.con_man.remove_persistent_loader(xlayer_id)

    ############### 
    # Open dialog
    ###############
    def open_clear_cache_dialog(self):
        dialog = ConfirmDialog("Delete cache will make loaded layer unusable !!")
        ret = dialog.exec_()
        if ret != dialog.Ok: return
        
        utils.clear_cache()

    def open_connection_dialog(self):
        dialog = self.new_main_dialog()
        
        vlayer = self.iface.activeLayer()
        dialog.set_layer( vlayer)
        
        dialog.exec_()
        self.con_man.finish_fast()
        # self.startTime = time.time()
    def open_sync_edit_dialog(self):
        vlayer = self.iface.activeLayer()
        layer_buffer = self.edit_buffer.get_layer_buffer(vlayer.id())

        lst_added_feat, removed_ids = layer_buffer.get_sync_feat()
        conn_info = layer_buffer.get_conn_info()

        # print_qgis("lst_added_feat: ",lst_added_feat)
        # print_qgis("removed_feat: ", removed_ids)

        con = EditSyncController(self.network)
        self.con_man.add_on_demand_controller(con)
        con.signal.finished.connect( layer_buffer.sync_complete)
        con.signal.results.connect( self.make_cb_success_args("Sync edit finish") )
        con.signal.error.connect( self.cb_handle_error_msg )

        con.start(conn_info, layer_buffer, lst_added_feat, removed_ids)
class CreatePoint:
    """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',
                                   'CreatePoint_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Obtaining the map canvas
        self.canvas = iface.mapCanvas()

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

        icon_path = ':/plugins/Create_Point/icon.png'
        #create action that will be run by the plugin
        self.action = QAction("Create Point", self.iface.mainWindow())
        self.action.setIcon(QIcon(icon_path))
        self.action.setWhatsThis("Create Point")
        self.action.setStatusTip("Click On Map And Draw Point")

        # add plugin menu to Vector toolbar
        self.iface.addPluginToMenu("Create_Point", self.action)

        # add icon to new menu item in Vector toolbar
        self.iface.addToolBarIcon(self.action)

        # connect action to the run method
        self.action.triggered.connect(self.run)

        # prepare map tool
        self.mapTool = Map_Tool(self.iface)
        #self.iface.mapCanvas().mapToolSet.connect(self.mapToolChanged)

    def unload(self):
        """Actions to run when the plugin is unloaded"""
        # remove menu and icon from the menu
        self.iface.removeToolBarIcon(self.action)
        self.iface.removePluginMenu("Create_Point", self.action)

        if self.iface.mapCanvas().mapTool() == self.mapTool:
            self.iface.mapCanvas().unsetMapTool(self.mapTool)
        del self.mapTool

    def run(self):
        #Check Active Layer Present Or Not
        self.active_point_layer = self.iface.mapCanvas().currentLayer()
        if not self.active_point_layer:
            self.iface.messageBar().pushMessage(
                "Active Layer",
                "No Active Layer Found Please Select Point Layer",
                level=Qgis.Warning)
        else:
            self.layer_type = self.active_point_layer.geometryType()
            if self.layer_type == QgsWkbTypes.PointGeometry:
                self.iface.mapCanvas().setMapTool(self.mapTool)
            else:
                self.iface.messageBar().pushMessage(
                    "Active Layer",
                    "Active Layer Is Not Point Type Layer Please Select Point Layer",
                    level=Qgis.Warning)
class ImpEpanet(object):
    def __init__(self, iface):
        # Save a reference to the QGIS iface
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.dlg = ExportEpanetInpFilesDialog()
        self.sections = ['junctions', 'tanks', 'pipes', 'pumps', 'reservoirs', 'valves', 'STATUS', 'PATTERNS', 'CURVES',
                         'CONTROLS', 'RULES', 'ENERGY', 'REACTIONS', 'REACTIONS_I', 'EMITTERS', 'QUALITY', 'SOURCES',
                         'MIXING', 'TIMES', 'REPORT', 'OPTIONS']

    def initGui(self):
        # Create action
        sys.path.append(os.path.dirname(__file__)+'/impcount.py')

        self.action = QAction(QIcon(":/plugins/ImportEpanetInpFiles/impepanet.png"), "Import Epanet Input File",
                              self.iface.mainWindow())
        self.action.setWhatsThis("Import Epanet Input File")
        self.action.triggered.connect(self.run)
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu("&ImportEpanetInpFiles", self.action)

        self.actionexp = QAction(QIcon(":/plugins/ImportEpanetInpFiles/expepanet.png"), "Export Epanet Input File",
                                 self.iface.mainWindow())
        self.actionexp.setWhatsThis("Export Epanet Input File")
        self.actionexp.triggered.connect(self.runexp)
        self.iface.addToolBarIcon(self.actionexp)
        self.iface.addPluginToMenu("&ImportEpanetInpFiles", self.actionexp)

        self.dlg.ok_button.clicked.connect(self.ok)
        self.dlg.cancel_button.clicked.connect(self.cancel)
        self.dlg.toolButtonOut.clicked.connect(self.toolButtonOut)

    def unload(self):
        # Remove the plugin
        self.iface.removePluginMenu("&ImportEpanetInpFiles", self.action)
        self.iface.removeToolBarIcon(self.action)

        self.iface.removePluginMenu("&ImportEpanetInpFiles", self.actionexp)
        self.iface.removeToolBarIcon(self.actionexp)

    def run(self):
        filePath = QFileDialog.getOpenFileName(self.iface.mainWindow(), "Choose EPANET Input file",
                                               os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'),
                                               "Epanet Inp File (*.inp)")
        if filePath[0] == "":
            return
        epa2gis(filePath[0])
        self.iface.messageBar().clearWidgets()
        msgBox = QMessageBox()
        msgBox.setWindowTitle('ImportEpanetInpFiles')
        msgBox.setText('Shapefiles have been created successfully in folder "_shapefiles_".')
        msgBox.exec_()

    def runexp(self):
        self.dlg.out.setText('')
        self.layers = self.canvas.layers()
        self.layer_list = []
        self.layer_list = ['NONE']
        [self.layer_list.append(layer.name()) for layer in self.layers]

        for sect in self.sections:
            eval('self.dlg.sect_' + sect + '.clear()')
            eval('self.dlg.sect_' + sect + '.addItems(self.layer_list)')
            indices = [i for i, s in enumerate(self.layer_list) if sect in s]
            if indices:
                if sect == 'REACTIONS':
                    eval('self.dlg.sect_' + sect + '.setCurrentIndex(indices[1])')
                else:
                    eval('self.dlg.sect_' + sect + '.setCurrentIndex(indices[0])')

        self.dlg.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint)
        self.dlg.show()

    def cancel(self):
        self.layer_list = []
        self.layer_list = ['NONE']
        for sect in self.sections:
            exec ('self.dlg.sect_' + sect + '.clear()')
        self.dlg.close()

    def toolButtonOut(self):
        self.outEpanetName = QFileDialog.getSaveFileName(None, 'Save File',
                                                         os.path.join(os.path.join(os.path.expanduser('~')),
                                                                      'Desktop'), 'Epanet Inp File (*.inp)')
        self.dlg.out.setText(self.outEpanetName[0])

    def selectOutp(self):
        msgBox = QMessageBox()
        msgBox.setIcon(QMessageBox.Warning)
        msgBox.setWindowTitle('Warning')
        msgBox.setText('Please define Epanet Inp File location.')
        msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint)
        msgBox.exec_()
        return True

    def ok(self):
        # Here check if select OK button, get the layer fields
        # Initialize
        # [JUNCTIONS]
        if self.dlg.out.text() == '':
            if self.selectOutp():
                return
        elif os.path.isabs(self.dlg.out.text()) == False:
            if self.selectOutp():
                return

        self.outEpanetName = self.dlg.out.text()

        try:
            f = open(self.outEpanetName, "w")
            f.close()
        except:
            msgBox = QMessageBox()
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setWindowTitle('Warning')
            msgBox.setText('Please define Epanet Inp File location.')
            msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint)
            msgBox.exec_()
            return

        if not self.layers:
            msgBox = QMessageBox()
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setWindowTitle('Warning')
            msgBox.setText('No layers selected.')
            msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint)
            msgBox.exec_()
            return
        xypipes_id = []
        xypipesvert = []
        for sect in self.sections:
            exec('sect' + sect + '=[]') in globals(), locals()
            exec('xy' + sect + '=[]') in globals(), locals()
            if eval('self.dlg.sect_' + sect + '.currentText()') != 'NONE':
                # Get layer field names
                indLayerName = self.layer_list.index(eval('self.dlg.sect_' + sect + '.currentText()')) - 1
                provider = self.layers[indLayerName].dataProvider()
                fields = provider.fields()
                field_names = [field.name() for field in fields]
                for elem in self.layers[indLayerName].getFeatures():
                    eval('sect' + sect + '.append(dict(zip(field_names, elem.attributes())))')
                    if any(sect in s for s in self.sections[0:5]):
                        geom = elem.geometry()
                        if self.layers[indLayerName].geometryType() == 0:
                            eval('xy' + sect + '.append(geom.asPoint())')
                        elif self.layers[indLayerName].geometryType() == 1:
                            eval('xy' + sect + '.append(geom.asPolyline())')
                            if sect == 'pipes':
                                if len(geom.asPolyline()) > 2:
                                    for pp in range(len(geom.asPolyline())-2):
                                        xypipes_id.append(elem.attributes()[0])
                                        xypipesvert.append(geom.asPolyline()[pp])
                    if sect == 'junctions':
                        if 'Elevation' not in locals()['sect' + sect][0].keys():
                            QMessageBox.warning(QWidget(), "Message", "Elevation field is missing.")
        # (myDirectory,nameFile) = os.path.split(self.iface.activeLayer().dataProvider().dataSourceUri())
        my_directory = ''
        f = open(self.outEpanetName, 'wt')
        f.write('[TITLE]\n')
        f.write('Export input file via plugin ExportEpanetInpFiles. \n\n')
        f.write('[JUNCTIONS]\n')
        node_i_ds = []
        for i in range(len(locals()['sectjunctions'])):
            node_i_ds.append(locals()['sectjunctions'][i]['ID'])
            f.write(locals()['sectjunctions'][i]['ID'] + '   ' + str(locals()['sectjunctions'][i]['Elevation']) + '\n')
        f.write('\n[RESERVOIRS]\n')
        for i in range(len(locals()['sectreservoirs'])):
            node_i_ds.append(locals()['sectreservoirs'][i]['ID'])
            f.write(locals()['sectreservoirs'][i]['ID'] + '   ' + str(locals()['sectreservoirs'][i]['Head']) + '\n')
        f.write('\n[TANKS]\n')
        for i in range(len(locals()['secttanks'])):
            node_i_ds.append(locals()['secttanks'][i]['ID'])
            if locals()['secttanks'][i]['VolumeCurv'] == None:
                locals()['secttanks'][i]['VolumeCurv'] = ""
            f.write(locals()['secttanks'][i]['ID'] + '   ' + str(locals()['secttanks'][i]['Elevation']) + '   ' + str(locals()['secttanks'][i]['InitLevel'])
                    + '   ' + str(locals()['secttanks'][i]['MinLevel']) + '   ' + str(locals()['secttanks'][i]['MaxLevel']) + '   ' + str(
                locals()['secttanks'][i]['Diameter'])
                    + '   ' + str(locals()['secttanks'][i]['MinVolume']) + '   ' + str(locals()['secttanks'][i]['VolumeCurv']) + '   ' + '\n')
        f.write('\n[PIPES]\n')
        for i in range(len(locals()['sectpipes'])):
            if (locals()['sectpipes'][i]['NodeFrom'] in node_i_ds) and (locals()['sectpipes'][i]['NodeTo'] in node_i_ds):
                f.write(locals()['sectpipes'][i]['ID'] + '   ' + locals()['sectpipes'][i]['NodeFrom']
                        + '   ' + locals()['sectpipes'][i]['NodeTo'] + '   ' + str(locals()['sectpipes'][i]['Length']) + '   ' + str(
                    locals()['sectpipes'][i]['Diameter'])
                        + '   ' + str(locals()['sectpipes'][i]['Roughness']) + '   ' + str(locals()['sectpipes'][i]['MinorLoss']) + '   ' +
                        locals()['sectpipes'][i]['Status'] + '\n')
        f.write('\n[PUMPS]\n')
        for i in range(len(locals()['sectpumps'])):
            if locals()['sectpumps'][i]['Curve'] != 'NULL':
                try:
                    locals()['sectpumps'][i]['Curve'] = 'HEAD ' + locals()['sectpumps'][i]['Curve']
                except:
                    locals()['sectpumps'][i]['Curve'] = 'HEAD '
            else:
                locals()['sectpumps'][i]['Curve'] = ''
            if locals()['sectpumps'][i]['Pattern'] != 'NULL':
                try:
                    locals()['sectpumps'][i]['Pattern'] = 'PATTERN ' + locals()['sectpumps'][i]['Pattern']
                except:
                    locals()['sectpumps'][i]['Pattern'] = "PATTERN "
            else:
                locals()['sectpumps'][i]['Pattern'] = ''
            if locals()['sectpumps'][i]['Power'] != 'NULL':
                try:
                    locals()['sectpumps'][i]['Power'] = 'POWER ' + locals()['sectpumps'][i]['Power']
                except:
                    locals()['sectpumps'][i]['Power'] = "POWER "
            else:
                locals()['sectpumps'][i]['Power'] = ''

            try:
                f.write(locals()['sectpumps'][i]['ID'] + '   ' + locals()['sectpumps'][i]['NodeFrom']
                        + '   ' + locals()['sectpumps'][i]['NodeTo'] + '   ' + locals()['sectpumps'][i]['Curve']
                        + '   ' + str(locals()['sectpumps'][i]['Pattern']) + '   ' + str(locals()['sectpumps'][i]['Power']) + '\n')
            except:
                f.write(locals()['sectpumps'][i]['ID']  +'\n')

        f.write('\n[VALVES]\n')
        if self.dlg.sect_valves.currentText() != 'NONE':
            for i in range(len(locals()['sectvalves'])):
                try:
                    locals()['sectvalves'][i]['NodeFrom'] = locals()['sectvalves'][i]['NodeFrom'] + ''
                except:
                    locals()['sectvalves'][i]['NodeFrom'] = ""

                try:
                    locals()['sectvalves'][i]['NodeTo'] = locals()['sectvalves'][i]['NodeTo'] + ''
                except:
                    locals()['sectvalves'][i]['NodeTo'] = ""
                f.write("{}   {}   {}   {}    {}    {}    {}\n".format(locals()['sectvalves'][i]['ID'], locals()['sectvalves'][i]['NodeFrom'],
                                                                       locals()['sectvalves'][i]['NodeTo'],
                                                                       str(locals()['sectvalves'][i]['Diameter']),
                                                                       locals()['sectvalves'][i]['Type'],
                                                                       str(locals()['sectvalves'][i]['Setting']),
                                                                       str(locals()['sectvalves'][i]['MinorLoss'])))

        f.write('\n[DEMANDS]\n')
        for i in range(len(locals()['sectjunctions'])):
            for u in range(int((len(locals()['sectjunctions'][i]) - 2) / 2)):
                if locals()['sectjunctions'][i]['Demand' + str(u + 1)] == 0 and str(
                        locals()['sectjunctions'][i]['Pattern' + str(u + 1)]) == 'None':
                    continue
                if str(locals()['sectjunctions'][i]['Pattern' + str(u + 1)]) == 'NULL' or str(
                        locals()['sectjunctions'][i]['Pattern' + str(u + 1)]) == 'None':
                    locals()['sectjunctions'][i]['Pattern' + str(u + 1)] = ''
                f.write(locals()['sectjunctions'][i]['ID'] + '   ' + str(locals()['sectjunctions'][i]['Demand' + str(u + 1)])
                        + '   ' + str(locals()['sectjunctions'][i]['Pattern' + str(u + 1)]) + '\n')

        f.write('\n[STATUS]\n')
        for i in range(len(locals()['sectSTATUS'])):
            f.write("{}   {}\n".format(locals()['sectSTATUS'][i]['Link_ID'], locals()['sectSTATUS'][i]['Status/Set']))

        f.write('\n[PATTERNS]\n')
        for i in range(len(locals()['sectPATTERNS'])):
            f.write("{}   {}\n".format(locals()['sectPATTERNS'][i]['Pattern_ID'], locals()['sectPATTERNS'][i]['Multiplier']))

        f.write('\n[CURVES]\n')
        for i in range(len(locals()['sectCURVES'])):
            f.write(";{}:\n   {}   {}   {}\n".format(locals()['sectCURVES'][i]['Type'], locals()['sectCURVES'][i]['Curve_ID'],
                                                     str(locals()['sectCURVES'][i]['X-Value']),str(locals()['sectCURVES'][i]['Y-Value'])))

        f.write('\n[CONTROLS]\n')
        for i in range(len(locals()['sectCONTROLS'])):
            f.write("{}\n".format(locals()['sectCONTROLS'][i]['Controls']))

        f.write('\n[RULES]\n')
        for i in range(len(locals()['sectRULES'])):
            f.write("RULE {}\n   {}\n".format(locals()['sectRULES'][i]['Rule_ID'], locals()['sectRULES'][i]['Rule']))

        f.write('\n[ENERGY]\n')
        if locals()['sectENERGY']:
            try: f.write('Global Efficiency   ' + str(locals()['sectENERGY'][0]['GlobalEffi']) + '\n')
            except: pass
            try: f.write('Global Price    ' + str(locals()['sectENERGY'][0]['GlobalPric']) + '\n')
            except: pass
            try: f.write('Demand Charge   ' + str(locals()['sectENERGY'][0]['DemCharge']) + '\n')
            except: pass

        f.write('\n[REACTIONS]\n')
        if locals()['sectREACTIONS']:
            try: f.write('Order Bulk   ' + str(locals()['sectREACTIONS'][0]['OrderBulk']) + '\n')
            except: pass
            try: f.write('Order Tank    ' + str(locals()['sectREACTIONS'][0]['OrderTank']) + '\n')
            except: pass
            try: f.write('Order Wall   ' + str(locals()['sectREACTIONS'][0]['OrderWall']) + '\n')
            except: pass
            try: f.write('Global Bulk   ' + str(locals()['sectREACTIONS'][0]['GlobalBulk']) + '\n')
            except: pass
            try: f.write('Global Wall   ' + str(locals()['sectREACTIONS'][0]['GlobalWall']) + '\n')
            except: pass
            try: f.write('Limiting Potential   ' + str(locals()['sectREACTIONS'][0]['LimPotent']) + '\n')
            except: pass
            try: f.write('Roughness Correlation   ' + str(locals()['sectREACTIONS'][0]['RoughCorr']) + '\n')
            except: pass

        f.write('\n[REACTIONS]\n')
        for i in range(len(locals()['sectREACTIONS_I'])):
            f.write('{}    {}    {} \n'.format(locals()['sectREACTIONS_I'][i]['Type'],
                                               locals()['sectREACTIONS_I'][i]['Pipe/Tank'], str(locals()['sectREACTIONS_I'][i]['Coeff.'])))
        f.write('\n[EMITTERS]\n')
        for i in range(len(locals()['sectEMITTERS'])):
            f.write('{}    {}\n'.format(locals()['sectEMITTERS'][i]['Junc_ID'], str(locals()['sectEMITTERS'][i]['Coeff.'])))

        f.write('\n[SOURCES]\n')
        for i in range(len(locals()['sectSOURCES'])):
            try:
                locals()['sectSOURCES'][i]['Pattern'] = locals()['sectSOURCES'][i]['Pattern']  + ''
            except:
                locals()['sectSOURCES'][i]['Pattern'] = ''
            f.write("{}   {}   {}   {}\n".format(locals()['sectSOURCES'][i]['Node_ID'], locals()['sectSOURCES'][i]['Type'],
                                                                   str(locals()['sectSOURCES'][i]['Strength']),
                                                                   locals()['sectSOURCES'][i]['Pattern']))

        f.write('\n[MIXING]\n')
        for i in range(len(locals()['sectMIXING'])):
            f.write('{}    {}    {} \n'.format(locals()['sectMIXING'][i]['Tank_ID'],
                                               locals()['sectMIXING'][i]['Model'], str(locals()['sectMIXING'][i]['Fraction'])))

        f.write('\n[TIMES]\n')
        if locals()['sectTIMES']:
            try: f.write('Duration   ' + str(locals()['sectTIMES'][0]['Duration']) + '\n')
            except: pass
            try: f.write('Hydraulic Timestep    ' + str(locals()['sectTIMES'][0]['HydStep']) + '\n')
            except: pass
            try: f.write('Quality Timestep   ' + str(locals()['sectTIMES'][0]['QualStep']) + '\n')
            except: pass
            try: f.write('Pattern Timestep   ' + str(locals()['sectTIMES'][0]['PatStep']) + '\n')
            except: pass
            try: f.write('Pattern Start   ' + str(locals()['sectTIMES'][0]['PatStart']) + '\n')
            except: pass
            try: f.write('Report Timestep   ' + str(locals()['sectTIMES'][0]['RepStep']) + '\n')
            except: pass
            try: f.write('Report Start   ' + str(locals()['sectTIMES'][0]['RepStart']) + '\n')
            except: pass
            try: f.write('Start ClockTime   ' + str(locals()['sectTIMES'][0]['StartClock']) + '\n')
            except: pass
            try: f.write('Statistic   ' + str(locals()['sectTIMES'][0]['Statistic']) + '\n')
            except: pass

        f.write('\n[REPORT]\n')
        if locals()['sectREPORT']:
            try: f.write('Status   ' + locals()['sectREPORT'][0]['Status'] + '\n')
            except: pass
            try: f.write('Summary    ' + locals()['sectREPORT'][0]['Summary'] + '\n')
            except: pass
            try: f.write('Page   ' + locals()['sectREPORT'][0]['Page'] + '\n')
            except: pass

        f.write('\n[OPTIONS]\n')
        if locals()['sectOPTIONS']:
            try: f.write('Units   ' + str(locals()['sectOPTIONS'][0]['Units']) + '\n');
            except: pass
            try: f.write('Headloss    ' + str(locals()['sectOPTIONS'][0]['Headloss']) + '\n')
            except: pass
            try: f.write('Specific Gravity   ' + str(locals()['sectOPTIONS'][0]['SpecGrav']) + '\n')
            except: pass
            try: f.write('Viscosity   ' + str(locals()['sectOPTIONS'][0]['Viscosity']) + '\n')
            except: pass
            try: f.write('Trials   ' + str(locals()['sectOPTIONS'][0]['Trials']) + '\n')
            except: pass
            try: f.write('Accuracy   ' + str(locals()['sectOPTIONS'][0]['Accuracy']) + '\n')
            except: pass
            try: f.write('CHECKFREQ   ' + str(locals()['sectOPTIONS'][0]['CheckFreq']) + '\n')
            except: pass
            try: f.write('MAXCHECK   ' + str(locals()['sectOPTIONS'][0]['MaxCheck']) + '\n')
            except: pass
            try: f.write('DAMPLIMIT   ' + str(locals()['sectOPTIONS'][0]['DampLimit']) + '\n')
            except: pass
            try: f.write('Unbalanced   ' + str(locals()['sectOPTIONS'][0]['Unbalanced']) + '\n')
            except: pass
            try: f.write('Pattern   ' + str(locals()['sectOPTIONS'][0]['PatID']) + '\n')
            except: pass
            try: f.write('Demand Multiplier   ' + str(locals()['sectOPTIONS'][0]['DemMult']) + '\n')
            except: pass
            try: f.write('Emitter Exponent   ' + str(locals()['sectOPTIONS'][0]['EmitExp']) + '\n')
            except: pass
            try: f.write('Quality   ' + str(locals()['sectOPTIONS'][0]['Quality']) + '\n')
            except: pass
            try: f.write('Diffusivity   ' + str(locals()['sectOPTIONS'][0]['Diffusivit']) + '\n')
            except: pass
            try: f.write('Tolerance   ' + str(locals()['sectOPTIONS'][0]['Tolerance']) + '\n')
            except: pass

        f.write('\n[COORDINATES]\n')
        for i in range(len(locals()['sectjunctions'])):
            f.write(locals()['sectjunctions'][i]['ID'] + '   ' + str(locals()['xyjunctions'][i][0]) + '   ' + str(locals()['xyjunctions'][i][1]) + '\n')
        for i in range(len(locals()['sectreservoirs'])):
            f.write(locals()['sectreservoirs'][i]['ID'] + '   ' + str(locals()['xyreservoirs'][i][0]) + '   ' + str(locals()['xyreservoirs'][i][1]) + '\n')
        for i in range(len(locals()['secttanks'])):
            f.write(locals()['secttanks'][i]['ID'] + '   ' + str(locals()['xytanks'][i][0]) + '   ' + str(locals()['xytanks'][i][1]) + '\n')

        f.write('\n[VERTICES]\n')

        for l in range(len(xypipes_id)):
                f.write(xypipes_id[l] + '   ' + str(xypipesvert[l][0]) + '   ' + str(xypipesvert[l][1]) + '\n')

        f.write('\n[END]\n')

        f.close()

        self.cancel()
        msgBox = QMessageBox()
        msgBox.setWindowTitle('Export Options')
        msgBox.setText('Export Epanet Inp File "' + self.outEpanetName + '" succesful.')
        msgBox.exec_()
Example #12
0
class HffPlugin_s(object):
    HOME = os.environ['HFF_HOME']

    PARAMS_DICT = {
        'SERVER': '',
        'HOST': '',
        'DATABASE': '',
        'PASSWORD': '',
        'PORT': '',
        'USER': '',
        'THUMB_PATH': '',
        'THUMB_RESIZE': '',
        'EXPERIMENTAL': ''
    }

    path_rel = os.path.join(os.sep, HOME, 'HFF_DB_folder', 'config.cfg')
    conf = open(path_rel, "rb+")
    data = conf.read()
    text = (b'THUMB_RESIZE')

    if text in data:
        pass
    else:
        conf.seek(-3, 2)
        conf.read(1)
        conf.write(b"','THUMB_RESIZE' : 'insert path for the image resized'}")

    conf.close()
    PARAMS_DICT = eval(data)

    def __init__(self, iface):
        self.iface = iface
        userPluginPath = os.path.dirname(__file__)
        systemPluginPath = QgsApplication.prefixPath() + "/python/plugins/HFF"

        # overrideLocale = QgsSettings().value("locale/overrideFlag", QVariant)  # .toBool()
        # if not overrideLocale:
        # localeFullName = QLocale.system().name()
        # else:
        # localeFullName = QgsSettings().value("locale/userLocale", QVariant)  # .toString()

        # if QFileInfo(userPluginPath).exists():
        # translationPath = userPluginPath + "/i18n/hff_system__plugin_" + localeFullName + ".qm"
        # else:
        # translationPath = systemPluginPath + "/i18n/hff_system__plugin_" + localeFullName + ".qm"

        # self.localePath = translationPath
        # if QFileInfo(self.localePath).exists():
        # self.translator = QTranslator()
        # self.translator.load(self.localePath)
        # QCoreApplication.installTranslator(self.translator)

    def initGui(self):

        settings = QgsSettings()
        icon_paius = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'hfflogo.png'))
        self.action = QAction(QIcon(icon_paius), "HFF Main Panel",
                              self.iface.mainWindow())
        self.action.triggered.connect(self.showHideDockWidget)

        # dock widget
        self.dockWidget = HffPluginDialog(self.iface)
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockWidget)

        # TOOLBAR
        self.toolBar = self.iface.addToolBar("HFF")
        self.toolBar.setObjectName("HFF")
        self.toolBar.addAction(self.action)

        self.dataToolButton = QToolButton(self.toolBar)
        self.dataToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        ######  Section dedicated to the basic data entry
        # add Actions data
        self.siteToolButton = QToolButton(self.toolBar)
        self.siteToolButton.setPopupMode(QToolButton.MenuButtonPopup)
        icon_site = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconSite.png'))
        self.actionSite = QAction(QIcon(icon_site), "Site",
                                  self.iface.mainWindow())
        self.actionSite.setWhatsThis("Site")
        self.actionSite.triggered.connect(self.runSite)

        icon_eamena = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons', 'eamena.jpg'))
        self.actionEamena = QAction(QIcon(icon_eamena), "Eamena",
                                    self.iface.mainWindow())
        self.actionEamena.setWhatsThis("Eamena")
        self.actionEamena.triggered.connect(self.runEamena)

        self.siteToolButton.addActions([self.actionSite, self.actionEamena])
        self.siteToolButton.setDefaultAction(self.actionSite)

        self.toolBar.addWidget(self.siteToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the UnderWater data entry
        # add Actions data
        icon_UW = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'snorkel.png'))
        self.actionUW = QAction(QIcon(icon_UW), "Divelog Form",
                                self.iface.mainWindow())
        self.actionUW.setWhatsThis("Divelog")
        self.actionUW.triggered.connect(self.runUW)

        icon_ANC = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconANC.png'))
        self.actionANC = QAction(QIcon(icon_ANC), "Anchor",
                                 self.iface.mainWindow())
        self.actionANC.setWhatsThis("Anchor")
        self.actionANC.triggered.connect(self.runANC)

        icon_ART = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons', 'radar.png'))
        self.actionART = QAction(QIcon(icon_ART), "Artefact",
                                 self.iface.mainWindow())
        self.actionART.setWhatsThis("Artefact")
        self.actionART.triggered.connect(self.runART)

        icon_Pottery = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'pottery.png'))
        self.actionPottery = QAction(QIcon(icon_Pottery), "Pottery",
                                     self.iface.mainWindow())
        self.actionPottery.setWhatsThis("Pottery")
        self.actionPottery.triggered.connect(self.runPottery)

        self.dataToolButton.addActions([
            self.actionUW, self.actionART, self.actionANC, self.actionPottery
        ])
        self.dataToolButton.setDefaultAction(self.actionUW)

        self.toolBar.addWidget(self.dataToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the shipwreck
        # add Actions documentation
        self.ShipwreckToolButton = QToolButton(self.toolBar)
        icon_shipwreck = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'Shipwreck.png'))
        self.actionShipwreck = QAction(QIcon(icon_shipwreck), "Shipwreck",
                                       self.iface.mainWindow())
        self.actionShipwreck.setWhatsThis("Shipwreck")
        self.actionShipwreck.triggered.connect(self.runShipwreck)

        self.ShipwreckToolButton.addActions([self.actionShipwreck])
        self.ShipwreckToolButton.setDefaultAction(self.actionShipwreck)

        self.toolBar.addWidget(self.ShipwreckToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the documentation
        # add Actions documentation
        self.docToolButton = QToolButton(self.toolBar)
        self.docToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_imageViewer = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons', 'photo.png'))
        self.actionimageViewer = QAction(QIcon(icon_imageViewer),
                                         "Media manager",
                                         self.iface.mainWindow())
        self.actionimageViewer.setWhatsThis("Media manager")
        self.actionimageViewer.triggered.connect(self.runImageViewer)

        icon_Directory_export = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'directoryExp.png'))
        self.actionImages_Directory_export = QAction(
            QIcon(icon_Directory_export), "Download image",
            self.iface.mainWindow())
        self.actionImages_Directory_export.setWhatsThis("Download image")
        self.actionImages_Directory_export.triggered.connect(
            self.runImages_directory_export)

        icon_excel_exp = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'excel-export.png'))
        self.actionexcelExp = QAction(QIcon(icon_excel_exp), "Download EXCEL",
                                      self.iface.mainWindow())
        self.actionexcelExp.setWhatsThis("Download EXCEL")
        self.actionexcelExp.triggered.connect(self.runPdfexp)

        self.docToolButton.addActions([
            self.actionexcelExp, self.actionimageViewer, self.actionexcelExp,
            self.actionImages_Directory_export
        ])

        self.docToolButton.setDefaultAction(self.actionimageViewer)

        #if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
        self.actionImages_Directory_export.setCheckable(True)
        self.actionexcelExp.setCheckable(True)
        self.actionimageViewer.setCheckable(True)

        self.toolBar.addWidget(self.docToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the plugin management

        self.manageToolButton = QToolButton(self.toolBar)
        self.manageToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_Con = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconConn.png'))
        self.actionConf = QAction(QIcon(icon_Con), "Config plugin",
                                  self.iface.mainWindow())
        self.actionConf.setWhatsThis("Config plugin")
        self.actionConf.triggered.connect(self.runConf)

        icon_Dbmanagment = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons', 'backup.png'))
        self.actionDbmanagment = QAction(QIcon(icon_Dbmanagment),
                                         "Database manager",
                                         self.iface.mainWindow())
        self.actionDbmanagment.setWhatsThis("Database manager")
        self.actionDbmanagment.triggered.connect(self.runDbmanagment)

        icon_Info = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconInfo.png'))
        self.actionInfo = QAction(QIcon(icon_Info), "Plugin info",
                                  self.iface.mainWindow())
        self.actionInfo.setWhatsThis("Plugin info")
        self.actionInfo.triggered.connect(self.runInfo)

        self.manageToolButton.addActions(
            [self.actionConf, self.actionDbmanagment, self.actionInfo])
        self.manageToolButton.setDefaultAction(self.actionConf)

        self.toolBar.addWidget(self.manageToolButton)

        self.toolBar.addSeparator()

        # menu
        self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools",
                                   self.actionUW)
        self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools",
                                   self.actionANC)
        self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools",
                                   self.actionART)
        self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools",
                                   self.actionPottery)

        self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools",
                                   self.actionShipwreck)

        self.iface.addPluginToMenu(
            "HFF - Survey Terrestrial Archaeological GIS Tools",
            self.actionSite)
        self.iface.addPluginToMenu(
            "HFF - Survey Terrestrial Archaeological GIS Tools",
            self.actionEamena)
        self.iface.addPluginToMenu("HFF - Media manager GIS Tools",
                                   self.actionimageViewer)
        self.iface.addPluginToMenu("HFF - Media manager GIS Tools",
                                   self.actionexcelExp)
        self.iface.addPluginToMenu("HFF - Media manager GIS Tools",
                                   self.actionImages_Directory_export)

        self.iface.addPluginToMenu("HFF - Config GIS Tools", self.actionConf)

        self.iface.addPluginToMenu("HFF - Config GIS Tools",
                                   self.actionDbmanagment)
        self.iface.addPluginToMenu("HFF - Info GIS Tools", self.actionInfo)

        # MENU
        self.menu = QMenu("HFF")
        self.menu.addActions([self.actionSite, self.actionEamena])
        self.menu.addSeparator()
        self.menu.addActions([self.actionShipwreck])
        self.menu.addSeparator()
        self.menu.addActions([
            self.actionUW, self.actionART, self.actionANC, self.actionPottery
        ])

        self.menu.addActions([
            self.actionimageViewer, self.actionexcelExp,
            self.actionImages_Directory_export
        ])
        self.menu.addSeparator()

        self.menu.addActions(
            [self.actionConf, self.actionDbmanagment, self.actionInfo])
        menuBar = self.iface.mainWindow().menuBar()
        menuBar.addMenu(self.menu)

    ##
    def runSite(self):
        pluginGui = hff_system__Site(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runEamena(self):
        pluginGui = Eamena(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runUW(self):
        pluginGui = hff_system__UW(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runANC(self):
        pluginGui = hff_system__ANC(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runART(self):
        pluginGui = hff_system__ART(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runPottery(self):
        pluginGui = hff_system__Pottery(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runShipwreck(self):
        pluginGui = hff_system__Shipwreck(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runConf(self):
        pluginConfGui = HFF_systemDialog_Config()
        pluginConfGui.show()
        self.pluginGui = pluginConfGui  # save

    def runInfo(self):
        pluginInfoGui = HFF_systemDialog_Info()
        pluginInfoGui.show()
        self.pluginGui = pluginInfoGui  # save

    def runImageViewer(self):
        pluginImageView = Main()
        pluginImageView.show()
        self.pluginGui = pluginImageView  # save

    def runImages_directory_export(self):
        pluginImage_directory_export = hff_system__Images_directory_export()
        pluginImage_directory_export.show()
        self.pluginGui = pluginImage_directory_export  # save

    def runDbmanagment(self):
        pluginDbmanagment = hff_system__dbmanagment(self.iface)
        pluginDbmanagment.show()
        self.pluginGui = pluginDbmanagment  # save

    def runPdfexp(self):
        pluginPdfexp = hff_system__excel_export(self.iface)
        pluginPdfexp.show()
        self.pluginGui = pluginPdfexp  # save

    def unload(self):
        # Remove the plugin

        self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools",
                                    self.actionUW)
        self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools",
                                    self.actionANC)
        self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools",
                                    self.actionART)
        self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools",
                                    self.actionPottery)

        self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools",
                                    self.actionShipwreck)

        self.iface.removePluginMenu(
            "HFF - Survey Terrestrial Archaeological GIS Tools",
            self.actionSite)
        self.iface.removePluginMenu(
            "HFF - Survey Terrestrial Archaeological GIS Tools",
            self.actionEamena)

        self.iface.removePluginMenu("HFF - Media manager GIS Tools",
                                    self.actionimageViewer)
        self.iface.removePluginMenu("HFF - Media manager GIS Tools",
                                    self.actionImages_Directory_export)
        self.iface.removePluginMenu("HFF - Media manager GIS Tools",
                                    self.actionexcelExp)

        self.iface.removePluginMenu("HFF - Config GIS Tools", self.actionConf)

        self.iface.removePluginMenu("HFF - Info GIS Tools", self.actionInfo)
        self.iface.removePluginMenu("HFF - Config GIS Tools",
                                    self.actionDbmanagment)

        self.iface.removeToolBarIcon(self.actionUW)
        self.iface.removeToolBarIcon(self.actionART)
        self.iface.removeToolBarIcon(self.actionANC)
        self.iface.removeToolBarIcon(self.actionPottery)

        self.iface.removeToolBarIcon(self.actionShipwreck)

        self.iface.removeToolBarIcon(self.actionSite)

        self.iface.removeToolBarIcon(self.actionimageViewer)
        self.iface.removeToolBarIcon(self.actionImages_Directory_export)
        self.iface.removeToolBarIcon(self.actionexcelExp)

        self.iface.removeToolBarIcon(self.actionConf)

        self.iface.removeToolBarIcon(self.actionInfo)
        self.iface.removeToolBarIcon(self.actionDbmanagment)

        self.dockWidget.setVisible(False)
        self.iface.removeDockWidget(self.dockWidget)

        # remove tool bar
        del self.toolBar

    def showHideDockWidget(self):
        if self.dockWidget.isVisible():
            self.dockWidget.hide()
        else:
            self.dockWidget.show()
Example #13
0
class qgsazimuth(object):
    """
    Base class for the qgsAzimuth plugin
    - Provides a means to draw a feature by specifying the angle and distance beetween points.
    - Supports angles in either the conventional 0.0 - 360.0 clockwise from North
        or the surveyor's 'Easting' system with bearings plus or minus 90 deg. from North or South
    - Supports magnetic declination as degrees plus or minus for East or West respectively
    - supports inputs in feet or the current CRS units
    """

    # just a test to see if mods are taking

    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.fPath = (
            ""
        )  # set default working directory, updated from config file & by Import/Export
        self.bands = []

    def initGui(self):
        # create action that will start plugin configuration
        self.action = QAction(
            QIcon(":icons/qgsazimuth.png"),
            "Azimuth and distance",
            self.iface.mainWindow(),
        )
        self.action.setWhatsThis("Azimuth and distance")
        self.action.triggered.connect(self.run)

        self.bandpoint = QgsRubberBand(self.canvas, QgsWkbTypes.PointGeometry)
        self.bandpoint.setIcon(QgsRubberBand.ICON_CROSS)
        self.bandpoint.setColor(QColor.fromRgb(255, 50, 255))
        self.bandpoint.setWidth(3)
        self.bandpoint.setIconSize(20)

        # add toolbar button and menu item
        self.iface.addPluginToMenu("&Topography", self.action)
        self.iface.addToolBarIcon(self.action)

        self.dock = Dock(self.iface.mainWindow())
        self.iface.addDockWidget(Qt.BottomDockWidgetArea, self.dock)
        self.dock.hide()
        self.pluginGui = self.dock.widget()

        self.dock.closed.connect(self.cleanup)
        self.pluginGui.pushButton_vertexAdd.clicked.connect(self.addRow)
        self.pluginGui.pushButton_vertexInsert.clicked.connect(self.insertRow)
        self.pluginGui.pushButton_segListRowDel.clicked.connect(self.delRow)
        self.pluginGui.pushButton_segListLoad.clicked.connect(self.loadList)
        self.pluginGui.pushButton_segListClear.clicked.connect(self.clearList)
        self.pluginGui.pushButton_objectDraw.clicked.connect(self.addgeometry)
        self.pluginGui.pushButton_startCapture.clicked.connect(self.startgetpoint)
        self.pluginGui.pushButton_segListSave.clicked.connect(self.saveList)
        self.pluginGui.pushButton_useLast.clicked.connect(self.use_last_vertex)

        self.pluginGui.pickAngle1_button.clicked.connect(self.select_angle1)
        self.pluginGui.pickAngle2_button.clicked.connect(self.select_angle2)
        self.pluginGui.clearMarkers_button.clicked.connect(self.clear_markers)
        self.pluginGui.copyDiff_button.clicked.connect(self.copy_diff_offset)

        # self.pluginGui.table_segmentList.cellChanged.connect(self.render_temp_band)

        self.pluginGui.table_segmentList.setCurrentCell(0, 0)

        self.tool = GetCoordTool(self.canvas)
        self.tool.finished.connect(self.getpoint)
        self.tool.locationChanged.connect(self.pluginGui.update_startpoint)
        self.tool.locationChanged.connect(self.update_marker_location)

        self.angletool = LineTool(self.canvas)
        self.angletool.geometryComplete.connect(self.update_angle1)
        self.angletool.locationChanged.connect(self.update_marker_location)

        self.angletool2 = LineTool(self.canvas)
        self.angletool2.geometryComplete.connect(self.update_angle2)
        self.angletool2.locationChanged.connect(self.update_marker_location)

        self.pluginGui.azimuth1_edit.textChanged.connect(self.update_angle_calc)
        self.pluginGui.azimuth2_edit.textChanged.connect(self.update_angle_calc)

        self.pluginGui.lineEdit_magNorth.textChanged.connect(self.update_offsetlabel)
        self.pluginGui.radioButton_defaultNorth.toggled.connect(self.update_offsetlabel)

    def update_offsetlabel(self, *args):
        mag = self.mag_dev
        self.pluginGui.offsetLabel.setText(str(mag))

    def copy_diff_offset(self):
        diff = self.pluginGui.azimuthDiff_edit.text()
        self.pluginGui.lineEdit_magNorth.setText(diff)

    def clear_markers(self):
        self.angletool2.reset()
        self.angletool.reset()
        self.pluginGui.azimuth1_edit.setText(str(0))
        self.pluginGui.azimuth2_edit.setText(str(0))

    def update_angle_calc(self):
        a1 = self.pluginGui.azimuth1_edit.text()
        a2 = self.pluginGui.azimuth2_edit.text()
        a1 = utils.dmsToDd(a1)
        a2 = utils.dmsToDd(a2)
        try:
            a1 = float(a1)
            a2 = float(a2)
        except ValueError:
            self.pluginGui.azimuthDiff_edit.setText("")
            return

        diff = a2 - a1
        self.pluginGui.azimuthDiff_edit.setText(str(diff))

    def select_angle1(self):
        self.canvas.setMapTool(self.angletool)

    def update_angle1(self, geometry):
        az = utils.azimuth_from_line(geometry)
        az = str(az)
        self.pluginGui.azimuth1_edit.setText(az)

    def update_angle2(self, geometry):
        az = utils.azimuth_from_line(geometry)
        az = str(az)
        self.pluginGui.azimuth2_edit.setText(az)

    def select_angle2(self):
        self.canvas.setMapTool(self.angletool2)

    def update_marker_location(self, point):
        self.bandpoint.setToGeometry(QgsGeometry.fromPointXY(point), None)

    def unload(self):
        # remove the plugin menu item and icon
        self.saveConf()
        self.iface.removeDockWidget(self.dock)
        self.iface.removePluginMenu("&Topography", self.action)
        self.iface.removeToolBarIcon(self.action)
        self.bandpoint.reset()
        self.tool.cleanup()
        self.clear_markers()
        del self.angletool2
        del self.angletool
        del self.tool
        del self.bandpoint

    def run(self):
        # misc init
        self.loadConf()  # get config data
        self.clearList()
        self.setStartAt("0;0;90")  # remove previous StartAt point

        self.pluginGui.lineEdit_crs.setText(
            self.iface.mapCanvas().mapSettings().destinationCrs().description()
        )

        if self.iface.activeLayer():
            self.updatelayertext(self.iface.activeLayer())
            self.pluginGui.radioButton_useActiveLayer.setChecked(True)
        else:
            self.pluginGui.radioButton_useActiveLayer.setEnabled(False)
            self.pluginGui.radioButton_useMemoryLayer.setChecked(True)
        self.iface.currentLayerChanged.connect(self.updatelayertext)
        if not self.dock.isVisible():
            self.dock.show()

        # for debugging convenience
        self.notes = self.pluginGui.plainTextEdit_note

    def cleanup(self):
        self.tool.cleanup()
        self.clear_bands()
        self.saveConf()

    def updatelayertext(self, layer):
        if not layer:
            self.pluginGui.radioButton_useActiveLayer.setEnabled(False)
        else:
            self.pluginGui.radioButton_useActiveLayer.setEnabled(True)
            self.pluginGui.radioButton_useActiveLayer.setText(
                "Active Layer ({0})".format(layer.name())
            )

    @property
    def useactivelayer(self):
        return self.pluginGui.radioButton_useActiveLayer.isChecked()

    def render_temp_band(self, *args):
        """
        Render a temp rubber band for showing the user the results
        """

        self.clear_bands()

        featurelist, vectorlayer = self.create_feature()
        if not featurelist or not vectorlayer:
            return

        for feature in featurelist:
            band = QgsRubberBand(self.iface.mapCanvas())
            if hasattr(band, "setLineStyle"):
                band.setLineStyle(Qt.DotLine)
            band.setWidth(4)
            band.setColor(Qt.darkMagenta)
            band.setToGeometry(feature.geometry(), vectorlayer)
            band.show()
            self.bands.append(band)
        pass

    @property
    def should_open_form(self):
        return self.pluginGui.checkBox_openForm.isChecked()

    @should_open_form.setter
    def should_open_form(self, value):
        return self.pluginGui.checkBox_openForm.setChecked(value)

    def addgeometry(self):
        featurelist, vectorlayer = self.create_feature()
        if not featurelist or not vectorlayer:
            return

        if not self.useactivelayer:
            QgsProject.instance().addMapLayer(vectorlayer)

        vectorlayer.startEditing()
        for feature in featurelist:
            if self.should_open_form:
                form = self.iface.getFeatureForm(vectorlayer, feature)
                form.setMode(QgsAttributeEditorContext.AddFeatureMode)
                if not form.exec_():
                    continue
            else:
                print(feature.isValid())
                print(feature.geometry().asWkt())
                error = vectorlayer.addFeature(feature)
                print(error, feature)
                if error:
                    log("Error in adding feature")

        self.iface.mapCanvas().refresh()
        self.clear_bands()

    def clear_bands(self):
        for band in self.bands:
            band.reset()
        self.bands = []

    def update_draw_button_state(self):
        x, y, z = self.starting_point()
        enabled = True
        if (x == 0 and y == 0 and z == 90) or (
            self.pluginGui.table_segmentList.rowCount() == 0
        ):
            enabled = False
        self.pluginGui.pushButton_objectDraw.setEnabled(enabled)

    def starting_point(self):
        # Get starting point coordinates
        X = float(str(self.pluginGui.lineEdit_vertexX0.text()))
        Y = float(str(self.pluginGui.lineEdit_vertexY0.text()))
        Z = float(str(self.pluginGui.lineEdit_vertexZ0.text()))
        return X, Y, Z

    @property
    def angletype(self):
        if self.pluginGui.radioButton_azimuthAngle.isChecked():
            return "azimuth"
        elif self.pluginGui.radioButton_bearingAngle.isChecked():
            return "bearing"
        elif self.pluginGui.radioButton_polarCoordAngle.isChecked():
            return "polor"

    @angletype.setter
    def angletype(self, value):
        if value == "azimuth":
            self.pluginGui.radioButton_azimuthAngle.setChecked(True)
        elif value == "bearing":
            self.pluginGui.radioButton_bearingAngle.setChecked(True)
        elif value == "polor":
            self.pluginGui.radioButton_polarCoordAngle.setChecked(True)
        else:
            self.pluginGui.radioButton_azimuthAngle.setChecked(True)

    @property
    def distanceunits(self):
        if self.pluginGui.radioButton_defaultUnits.isChecked():
            return "default"
        elif self.pluginGui.radioButton_englishUnits.isChecked():
            return "feet"

    @distanceunits.setter
    def distanceunits(self, value):
        if value == "default":
            self.pluginGui.radioButton_defaultUnits.setChecked(True)
        elif value == "feet":
            self.pluginGui.radioButton_englishUnits.setChecked(True)
        else:
            self.pluginGui.radioButton_defaultUnits.setChecked(True)

    @property
    def angleunit(self):
        if self.pluginGui.radioButton_degreeUnit.isChecked():
            return "degree"
        elif self.pluginGui.radioButton_gradianUnit.isChecked():
            return "gradian"

    @angleunit.setter
    def angleunit(self, value):
        if value == "degree":
            self.pluginGui.radioButton_degreeUnit.setChecked(True)
        elif value == "gradian":
            self.pluginGui.radioButton_gradianUnit.setChecked(True)
        else:
            self.pluginGui.radioButton_degreeUnit.setChecked(True)

    @property
    def northtype(self):
        if self.pluginGui.radioButton_magNorth.isChecked():
            return "magnetic"
        else:
            return "default"

    @northtype.setter
    def northtype(self, value):
        if value == "magnetic":
            self.pluginGui.radioButton_magNorth.setChecked(True)
        else:
            self.pluginGui.radioButton_defaultNorth.setChecked(True)

    @property
    def mag_dev(self):
        if self.pluginGui.radioButton_magNorth.isChecked():
            value = str(self.pluginGui.lineEdit_magNorth.text())
            try:
                return float(value)
            except ValueError:
                try:
                    if self.pluginGui.radioButton_gradianUnit.isChecked():
                        value = utils.gradianToDd(value)
                    return float(utils.dmsToDd(value))
                except IndexError:
                    return 0.0
        elif self.pluginGui.radioButton_defaultNorth.isChecked():
            return 0.0
        else:
            return 0.0

    @mag_dev.setter
    def mag_dev(self, value):
        self.pluginGui.lineEdit_magNorth.setText(str(value))

    @property
    def surveytype(self):
        if self.pluginGui.radioButton_radialSurvey.isChecked():
            surveytype = "radial"
        elif self.pluginGui.radioButton_boundarySurvey.isChecked():
            surveytype = "polygonal"
        return surveytype

    @surveytype.setter
    def surveytype(self, value):
        if value == "radial":
            self.pluginGui.radioButton_radialSurvey.setChecked(True)
        elif value == "polygonal":
            self.pluginGui.radioButton_boundarySurvey.setChecked(True)
        else:
            self.pluginGui.radioButton_boundarySurvey.setChecked(True)

    def use_last_vertex(self):
        # Get the last point from the last band
        x, y, z = 0, 0, 90
        arcpoint_count = self.arc_count
        points = self.get_points(self.surveytype, arcpoint_count)
        try:
            point = points[-1]
            x, y, z = point.x, point.y, point.z
        except IndexError:
            # Don't do anything if there is no last point
            return

        point = QgsPointXY(x, y)
        self.pluginGui.update_startpoint(point, z)
        self.update_marker_location(point)
        self.clearList()

    def table_entries(self):
        """
        Return the entries for each row in the table
        """
        rows = self.pluginGui.table_segmentList.rowCount()
        for row in range(rows):
            az = self.pluginGui.table_segmentList.item(row, 0).text()
            dis = float(str(self.pluginGui.table_segmentList.item(row, 1).text()))
            zen = self.pluginGui.table_segmentList.item(row, 2).text()
            direction = self.pluginGui.table_segmentList.item(row, 4).text()
            direction = utils.Direction.resolve(direction)

            try:
                radius = float(self.pluginGui.table_segmentList.item(row, 3).text())
            except ValueError:
                radius = None

            yield az, dis, zen, direction, radius

    def get_points(self, surveytype, arcpoint_count):
        """
        Return a list of calculated points for the full run.
        :param surveytype:
        :return:
        """
        X, Y, Z = self.starting_point()

        if (X == 0 and Y == 0 and Z == 90) or (
            self.pluginGui.table_segmentList.rowCount() == 0
        ):
            return []

        vlist = []
        vlist.append(utils.Point(X, Y, Z))
        # convert segment list to set of vertice
        for az, dis, zen, direction, radius in self.table_entries():
            if self.pluginGui.radioButton_englishUnits.isChecked():
                # adjust for input in feet, not meters
                dis = float(dis) * 0.3048

            # checking degree input
            if self.pluginGui.radioButton_azimuthAngle.isChecked():
                if self.pluginGui.radioButton_gradianUnit.isChecked():
                    az = utils.gradianToDd(az)
                    zen = utils.gradianToDd(zen)
                else:
                    az = float(utils.dmsToDd(az))
                    zen = float(utils.dmsToDd(zen))
            elif self.pluginGui.radioButton_bearingAngle.isChecked():
                az = float(self.bearingToDd(az))
                zen = float(self.bearingToDd(zen))

            # correct for magnetic compass headings if necessary
            self.magDev = self.mag_dev

            az = float(az) + float(self.magDev)

            # correct for angles outside of 0.0-360.0
            while az > 360.0:
                az = az - 360.0

            while az < 0.0:
                az = az + 360.0

            # checking survey type
            if surveytype == "radial":
                reference_point = vlist[0]  # reference first vertex

            if surveytype == "polygonal":
                reference_point = vlist[-1]  # reference previous vertex

            nextpoint = utils.nextvertex(reference_point, dis, az, zen)

            if radius:
                # If there is a radius then we are drawing a arc.
                if self.pluginGui.radioButton_englishUnits.isChecked():
                    # adjust for input in feet, not meters
                    radius = float(radius) * 0.3048

                # Calculate the arc points.
                points = list(
                    utils.arc_points(
                        reference_point,
                        nextpoint,
                        dis,
                        radius,
                        point_count=arcpoint_count,
                        direction=direction,
                        zenith_angle=zen,
                    )
                )

                if direction == utils.Direction.ANTICLOCKWISE:
                    points = reversed(points)

                # Append them to the final points list.
                vlist.extend(points)

            vlist.append(nextpoint)

        return vlist

    @property
    def drawing_layer(self):
        if self.useactivelayer:
            vectorlayer = self.iface.activeLayer()
        else:
            code = self.iface.mapCanvas().mapSettings().destinationCrs().authid()
            vectorlayer = QgsVectorLayer(
                "LineString?crs={}".format(code), "tmp_plot", "memory"
            )
        return vectorlayer

    @property
    def arc_count(self):
        """
        The number of points to use when drawing arcs
        """
        return self.pluginGui.spin_arclines.value()

    @arc_count.setter
    def arc_count(self, value):
        """
        The number of points to use when drawing arcs
        """
        self.pluginGui.spin_arclines.setValue(value)

    def create_feature(self):
        vectorlayer = self.drawing_layer

        # reprojecting to projects SRS
        arcpoint_count = self.arc_count
        points = self.get_points(self.surveytype, arcpoint_count)

        if not points:
            return None, None

        vlist = self.reproject(points, vectorlayer)

        as_segments = self.pluginGui.checkBox_asSegments.isChecked()

        featurelist = []
        geometrytype = vectorlayer.geometryType()
        if geometrytype == QgsWkbTypes.PointGeometry:
            points = utils.to_qgspoints(vlist)
            features = utils.createpoints(points)
            featurelist.extend(features)
        elif geometrytype == QgsWkbTypes.LineGeometry:
            if as_segments:
                # If the line is to be draw as segments then we loop the pairs and create a line for each one.
                points_to_join = []
                in_arc = False
                for pair in utils.pairs(
                    vlist, matchtail=self.surveytype == "polygonal"
                ):
                    start, end = pair[0], pair[1]
                    # If we are not drawing the arc then just add the pair to get a single line
                    if not start.arc_point and not end.arc_point:
                        points_to_join = pair
                    else:
                        # If we are in a arc we need to handle drawing it as one line
                        # which means grabbing each pair until we are finished the arc
                        if not start.arc_point and end.arc_point:
                            points_to_join = []
                            in_arc = True

                        if start.arc_point and not end.arc_point:
                            points_to_join.append(start)
                            points_to_join.append(end)
                            in_arc = False

                        if in_arc:
                            points_to_join.append(start)
                            points_to_join.append(end)
                            continue
                    pointlist = utils.to_qgspoints(
                        points_to_join, repeatfirst=self.surveytype == "radial"
                    )
                    feature = utils.createline(pointlist)
                    featurelist.append(feature)
            else:
                pointlist = utils.to_qgspoints(
                    vlist, repeatfirst=self.surveytype == "radial"
                )
                feature = utils.createline(pointlist)
                featurelist.append(feature)
        elif geometrytype == QgsWkbTypes.PolygonGeometry:
            polygon = utils.to_qgspoints(vlist)
            feature = utils.createpolygon([polygon])
            if feature:
                featurelist.append(feature)

        # Add the fields for the current layer
        for feature in featurelist:
            feature.setFields(vectorlayer.fields())

        return featurelist, vectorlayer

    def bearingToDd(self, dms):
        # allow survey bearings in form:  - N 25d 34' 40" E
        # where minus ('-') sign allows handling bearings given in reverse direction
        dms = dms.strip()
        if dms[0] == "-":
            rev = True
            dms = dms[1:].strip()
        else:
            rev = False

        baseDir = dms[0].upper()
        if baseDir in ["N", "S"]:
            adjDir = dms[-1].upper()
            bearing = True
            if baseDir == "N":
                if adjDir == "E":
                    base = 0.0
                    adj = "add"
                elif adjDir == "W":
                    base = 360.0
                    adj = "sub"
                else:
                    return 0
            elif baseDir == "S":
                base = 180.0
                if adjDir == "E":
                    adj = "sub"
                elif adjDir == "W":
                    adj = "add"
                else:
                    return 0
        else:
            bearing = False

        if self.pluginGui.radioButton_gradianUnit.isChecked():
            dd = utils.gradianToDd(dms)
        else:
            dd = utils.dmsToDd(dms)

        if rev:
            dd = float(dd) + 180.0

        if bearing == True:
            if adj == "add":
                dd = float(base) + float(dd)
            elif adj == "sub":
                dd = float(base) - float(dd)

        return dd

    def clearList(self):
        self.pluginGui.table_segmentList.clearContents()
        self.pluginGui.table_segmentList.setSortingEnabled(False)
        self.pluginGui.table_segmentList.setRowCount(0)
        self.pluginGui.table_segmentList.setCurrentCell(
            0, 0
        )  # substitute for missing setCurrentRow()
        self.render_temp_band()
        # retranslateUi

    def newVertex(self):
        # adds a vertex from the gui
        self.addrow(
            self.pluginGui.lineEdit_nextAzimuth.text(),
            self.pluginGui.lineEdit_nextDistance.value(),
            self.pluginGui.lineEdit_nextVertical.text(),
            self.pluginGui.spin_radius.value(),
        )

    def addRow(self):
        # this and following must be split to handle both GUI & FILE inputs
        az = self.pluginGui.lineEdit_nextAzimuth.text()
        dist = self.pluginGui.lineEdit_nextDistance.value()
        zen = self.pluginGui.lineEdit_nextVertical.text()
        radius = self.pluginGui.spin_radius.value()
        if radius == 0:
            radius = None
            direction = None
        else:
            if self.pluginGui.radio_anticlockwise.isChecked():
                direction = "anticlockwise"
            else:
                direction = "clockwise"
        self.addrow(az, dist, zen, radius, direction)

    def addrow(self, az=0, dist=0, zen=90, radius=None, direction=None):
        # add the vertex to the end of the table
        row = self.pluginGui.table_segmentList.rowCount()
        self.pluginGui.table_segmentList.insertRow(row)
        self.pluginGui.table_segmentList.setItem(
            row, 0, QTableWidgetItem(str(az).upper())
        )
        self.pluginGui.table_segmentList.setItem(row, 1, QTableWidgetItem(str(dist)))
        self.pluginGui.table_segmentList.setItem(row, 2, QTableWidgetItem(str(zen)))
        self.pluginGui.table_segmentList.setItem(row, 3, QTableWidgetItem(str(radius)))
        self.pluginGui.table_segmentList.setItem(
            row, 4, QTableWidgetItem(str(direction))
        )
        self.render_temp_band()

    def insertRow(self):
        az = self.pluginGui.lineEdit_nextAzimuth.text()
        dist = self.pluginGui.lineEdit_nextDistance.value()
        zen = self.pluginGui.lineEdit_nextVertical.text()
        radius = self.pluginGui.spin_radius.value()

        if radius == 0:
            radius = None
            direction = None
        else:
            if self.pluginGui.radio_anticlockwise.isChecked():
                direction = "anticlockwise"
            else:
                direction = "clockwise"

        # insert the vertext into the table at the current position
        row = self.pluginGui.table_segmentList.currentRow()
        self.pluginGui.table_segmentList.insertRow(row)
        self.pluginGui.table_segmentList.setItem(
            row, 0, QTableWidgetItem(str(az).upper())
        )
        self.pluginGui.table_segmentList.setItem(row, 1, QTableWidgetItem(str(dist)))
        self.pluginGui.table_segmentList.setItem(row, 2, QTableWidgetItem(str(zen)))
        self.pluginGui.table_segmentList.setItem(row, 3, QTableWidgetItem(str(radius)))
        self.pluginGui.table_segmentList.setItem(
            row, 4, QTableWidgetItem(str(direction))
        )
        self.render_temp_band()

    def delRow(self):
        self.pluginGui.table_segmentList.removeRow(
            self.pluginGui.table_segmentList.currentRow()
        )
        self.render_temp_band()

    def moveup(self):
        self.render_temp_band()
        pass

    def movedown(self):
        self.render_temp_band()
        pass

    def startgetpoint(self):
        # point capture tool
        self.saveTool = self.canvas.mapTool()
        self.canvas.setMapTool(self.tool)

    def getpoint(self, pt):
        self.clear_markers()
        self.pluginGui.update_startpoint(pt)
        self.canvas.setMapTool(self.saveTool)

    def reproject(self, vlist, vectorlayer):
        renderer = self.canvas.mapSettings()
        for row, point in enumerate(vlist):
            new_point = renderer.layerToMapCoordinates(
                vectorlayer, QgsPointXY(point[0], point[1])
            )
            # Translate it into our new point with arc_point info
            new_point = utils.Point(
                new_point.x(), new_point.y(), arc_point=point.arc_point
            )
            vlist[row] = new_point
        return vlist

    def setAngle(self, s):
        # self.say('processing angleType='+s)
        if s == "azimuth":
            self.pluginGui.radioButton_azimuthAngle.setChecked(True)
        elif s == "bearing":
            self.pluginGui.radioButton_bearingAngle.setChecked(True)
        elif s == "polar":
            self.pluginGui.radioButton_polorCoordAngle.setChecked(True)
        else:
            self.say("invalid angle type: " + s)

    def setHeading(self, s):
        # self.say('processing headingType='+s)
        if s == "coordinate_system":
            self.pluginGui.radioButton_defaultNorth.setChecked(True)
        elif s == "magnetic":
            self.pluginGui.radioButton_magNorth.setChecked(True)
        else:
            self.say("invalid heading type: " + s)

    def setDeclination(self, s):
        # self.say('processing declination='+s)
        self.pluginGui.lineEdit_magNorth.setText(s)
        self.magDev = float(s)

    def setDistanceUnits(self, s):
        # self.say('processing distance units='+s)
        if s == "feet":
            self.pluginGui.radioButton_englishUnits.setChecked(True)
        else:
            self.pluginGui.radioButton_defaultUnits.setChecked(True)

    def setAngleUnit(self, s):
        if s == "gradian":
            self.pluginGui.radioButton_gradianUnit.setChecked(True)
        else:
            self.pluginGui.radioButton_degreeUnit.setChecked(True)

    def setStartAt(self, s):
        # self.say('processing startAt='+s)
        coords = [float(v) for v in s.split(";")]
        point = QgsPointXY(coords[0], coords[1])
        self.pluginGui.update_startpoint(point, coords[2])

    def setSurvey(self, s):
        # self.say('processing surveyType='+s)
        if s == "polygonal":
            self.pluginGui.radioButton_boundarySurvey.setChecked(True)
        elif s == "radial":
            self.pluginGui.radioButton_irrSurvey.setChecked(True)
        else:
            self.say("invalid survey type: " + s)

    def say(self, txt):
        # present a message box on screen
        warn = QgsMessageViewer()
        warn.setMessageAsPlainText(txt)
        warn.showMessage()

    def tell(self, txt):
        # write to bottom of Note area at top of screen
        self.notes.appendPlainText(txt)

    # ---------------------------------------------------------------------------------------------------------------------------------
    #               File handling
    # This section deals with saving the user data to disk, and loading it
    #
    # format:
    #   line 1: angle=Azimuth|Bearing|Polar
    #   line 2: heading=Coordinate System|Magnetic
    #   line 3: declination=[- ]x.xxd[ xx.x'] [E|W]
    #   line 4: distunits=Default|Feet
    #   line 5: startAt=xxxxx.xxxxx, xxxxxx.xxxxx
    #   line 6: survey=Polygonal|Radial
    #   line 7: [data]
    #   line 8 through end: Azimuth; dist; zen
    #
    #       note: lines 1 through 5 are optional if hand entered, but will always be generated when 'saved'
    # ---------------------------------------------------------------------------------------------------------------------------------
    def loadList(self):
        self.fileName, _ = QFileDialog.getOpenFileName(
            None, "Load data separated by ';'", self.fPath, ""
        )
        if not os.path.exists(self.fileName):
            return 0
        # update selected file's folder
        fInfo = QFileInfo(self.fileName)
        self.fPath = fInfo.absolutePath()
        self.saveConf()

        self.render_temp_band()
        # get saved data
        try:
            f = open(self.fileName)
            lines = f.readlines()
            f.close()
            self.clearList()
            for line in lines:
                # remove trailing 'new lines', etc and break into parts
                parts = ((line.strip()).lower()).split("=")
                if len(parts) > 1:
                    # self.say("line="+line+'\nparts[0]='+parts[0]+'\nparts[1]='+parts[1])
                    if parts[0].lower() == "angle":
                        self.setAngle(parts[1].lower())
                    elif parts[0].lower() == "heading":
                        self.setHeading(parts[1].lower())
                    elif parts[0].lower() == "declination":
                        self.setDeclination(parts[1].lower())
                    elif parts[0].lower() == "dist_units":
                        self.setDistanceUnits(parts[1].lower())
                    elif parts[0].lower() == "angle_unit":
                        self.setAngleUnit(parts[1].lower())
                    elif parts[0].lower() == "startat":
                        self.setStartAt(parts[1].lower())
                    elif parts[0].lower() == "survey":
                        self.setSurvey(parts[1].lower())
                else:
                    coords = tuple((line.strip()).split(";"))
                    if coords[0].lower() == "[data]":
                        pass
                    else:
                        self.addrow(*coords)
        except:
            self.say("Invalid input")

    def saveList(self):
        file, _ = QFileDialog.getSaveFileName(
            None, "Save segment list to file.", self.fileName, ""
        )
        if file == "":
            return
        f = open(file, "w")
        # update selected file's folder
        fInfo = QFileInfo(file)
        self.fPath = fInfo.absolutePath()
        self.saveConf()

        if self.pluginGui.radioButton_azimuthAngle.isChecked():
            s = "Azimuth"
        elif self.pluginGui.radioButton_bearingAngle.isChecked():
            s = "Bearing"
        f.write("angle=" + s + "\n")

        if self.pluginGui.radioButton_defaultNorth.isChecked():
            s = "Coordinate_System"
        elif self.pluginGui.radioButton_magNorth.isChecked():
            s = "Magnetic"
        f.write("heading=" + s + "\n")

        if hasattr(self, "magDev") and self.magDev != 0.0:
            f.write("declination=" + str(self.magDev) + "\n")

        if self.pluginGui.radioButton_defaultUnits.isChecked():
            s = "Default"
        elif self.pluginGui.radioButton_englishUnits.isChecked():
            s = "Feet"
        f.write("dist_units=" + s + "\n")

        if self.pluginGui.radioButton_degreeUnit.isChecked():
            s = "degree"
        elif self.pluginGui.radioButton_gradianUnit.isChecked():
            s = "gradian"
        f.write("angle_unit=" + s + "\n")

        f.write(
            "startAt="
            + str(self.pluginGui.lineEdit_vertexX0.text())
            + ";"
            + str(self.pluginGui.lineEdit_vertexY0.text())
            + ";"
            + str(self.pluginGui.lineEdit_vertexZ0.text())
            + "\n"
        )

        if self.pluginGui.radioButton_boundarySurvey.isChecked():
            s = "Polygonal"
        elif self.pluginGui.radioButton_radialSurvey.isChecked():
            s = "Radial"
        f.write("survey=" + s + "\n")

        f.write("[data]\n")
        for row in range(self.pluginGui.table_segmentList.rowCount()):
            line = (
                str(self.pluginGui.table_segmentList.item(row, 0).text())
                + ";"
                + str(self.pluginGui.table_segmentList.item(row, 1).text())
                + ";"
                + str(self.pluginGui.table_segmentList.item(row, 2).text())
                + ";"
                + str(self.pluginGui.table_segmentList.item(row, 3).text())
                + ";"
                + str(self.pluginGui.table_segmentList.item(row, 4).text())
            )
            f.write(line + "\n")

        f.close()

    # ------------------------
    def loadConf(self):
        settings = QSettings()
        size = settings.value("/Plugin-qgsAzimuth/size", QSize(800, 600), type=QSize)
        position = settings.value(
            "/Plugin-qgsAzimuth/position", QPoint(0, 0), type=QPoint
        )
        self.fPath = settings.value("/Plugin-qgsAzimuth/inp_exp_dir", "", type=str)
        self.angletype = settings.value("/Plugin-qgsAzimuth/angletype", "", type=str)

        self.should_open_form = settings.value(
            "/Plugin-qgsAzimuth/open_form", True, type=bool
        )
        self.surverytype = settings.value("/Plugin-qgsAzimuth/type", "", type=str)
        self.northtype = settings.value("/Plugin-qgsAzimuth/northtype", "", type=str)
        self.mag_dev = settings.value(
            "/Plugin-qgsAzimuth/northtype_value", 0.0, type=float
        )
        self.distanceunits = settings.value(
            "/Plugin-qgsAzimuth/distanceunits", "", type=str
        )
        self.angleunit = settings.value("/Plugin-qgsAzimuth/angleunit", "", type=str)
        if self.angleunit == "gradian":
            self.pluginGui.lineEdit_nextVertical.setText("100")
        self.angletype = settings.value("/Plugin-qgsAzimuth/angletype", "", type=str)
        self.arc_count = settings.value("/Plugin-qgsAzimuth/arcpoints", 6, type=int)

        self.pluginGui.resize(size)
        self.pluginGui.move(position)
        self.fileName = self.fPath
        # settings.restoreGeometry(settings.value("Geometry"), QByteArray(), type=QByteArray)

    def saveConf(self):
        settings = QSettings()
        # settings.setValue("Geometry", self.saveGeometry())
        settings.setValue("/Plugin-qgsAzimuth/size", self.pluginGui.size())
        settings.setValue("/Plugin-qgsAzimuth/position", self.pluginGui.pos())
        settings.setValue("/Plugin-qgsAzimuth/inp_exp_dir", self.fPath)
        settings.setValue("/Plugin-qgsAzimuth/open_form", self.should_open_form)
        settings.setValue("/Plugin-qgsAzimuth/type", self.surveytype)
        settings.setValue("/Plugin-qgsAzimuth/northtype", self.northtype)
        settings.setValue("/Plugin-qgsAzimuth/northtype_value", self.mag_dev)
        settings.setValue("/Plugin-qgsAzimuth/distanceunits", self.distanceunits)
        settings.setValue("/Plugin-qgsAzimuth/angleunit", self.angleunit)
        settings.setValue("/Plugin-qgsAzimuth/angletype", self.angletype)
        settings.setValue("/Plugin-qgsAzimuth/arcpoints", self.arc_count)

    def sortedDict(self, adict):
        keys = list(adict.keys())
        keys.sort()
        return list(map(adict.get, keys))
Example #14
0
class MainPlugin(object):
    def __init__(self, iface):
        self.name = "groupLayers"
        self.iface = iface
        self.project = QgsProject.instance()
        self.treeBeforeSave = None

    def initGui(self):
        self.action = QAction(
            QIcon(os.path.dirname(os.path.realpath(__file__)) + "/icon.png"),
            u"Group Layers by similar type (keep visibility)",
            self.iface.mainWindow()
        )
        self.action.setObjectName("groupAction")
        self.action.setWhatsThis("Group/ungroup layers by type")
        self.action.setStatusTip("Group/ungroup layers by type")
        self.action.setCheckable(True)
        self.action.triggered.connect(self.run)

        self.resetAction = QAction("Group and make all layers visible")
        self.resetAction.triggered.connect(self.run_reset_visibility)

        # the icon pressed status could be used, but it is already
        # changed when run method is called, so this is ambiguous
        # therefore a dedicated boolean status is used
        self.grouped = False
        self.groupAdditionalTypes = False
        self.defSelection = groupHierarchies.keys().__iter__().__next__()
        self.hierarchyDefinition = groupHierarchies[self.defSelection]

        # add toolbar button and menu item
        layersDock = self.iface.mainWindow().findChild(QDockWidget, "Layers")
        self.layersToolBar = layersDock.widget().layout().itemAt(0).widget()
        assert isinstance(self.layersToolBar, QToolBar)
        self.layersToolBar.addAction(self.action)
        self.menuButton = [btn for btn in self.layersToolBar.children()
                           if isinstance(btn, QToolButton)
                           if self.action in btn.actions()][0]
        self.buttonMenu = QMenu()
        self.menuButton.setMenu(self.buttonMenu)
        self.menuButton.setPopupMode(QToolButton.MenuButtonPopup)
        self.buttonMenu.addAction(self.action)
        self.buttonMenu.addAction(self.resetAction)
        # self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu("&Group Layers", self.action)

        self.defSelector = QAction(
            u"Select hierarchy definitions",
            self.iface.mainWindow()
        )
        self.defSelector.setObjectName("defSelector")
        self.defSelector.triggered.connect(self.selectDefs)
        self.iface.addPluginToMenu("&Group Layers", self.defSelector)
        # connect hook to reset the plugin state
        # when a new or existing project is opened
        self.project.cleared.connect(self.reset_state)
        self.project.writeProject.connect(self.write)
        self.project.projectSaved.connect(self.saved)

    def unload(self):
        # remove the plugin menu item and icon
        self.iface.removePluginMenu("&Group Layers", self.action)
        self.iface.removePluginMenu("&Group Layers", self.defSelector)
        self.layersToolBar.removeAction(self.action)
        self.project.cleared.disconnect(self.reset_state)
        self.project.writeProject.disconnect(self.write)
        self.project.projectSaved.disconnect(self.saved)
        try:
            self.project.layerWasAdded.disconnect(self.add_layer_sync)
        except Exception:
            print('could not disconnect add_layer_sync in unload')
        try:
            self.project.layerRemoved.disconnect(self.remove_layer_sync)
        except Exception:
            print('could not disconnect remove_layer_sync in unload')
        # self.iface.removeToolBarIcon(self.action)

    def selectDefs(self):
        dialog = DefSelectDialog(self.defSelection, self.groupAdditionalTypes)
        if dialog.exec_():
            self.defSelection = dialog.comboBox.currentText()
            self.hierarchyDefinition = groupHierarchies[self.defSelection]
            self.groupAdditionalTypes = dialog.checkBox.isChecked()

    def run(self, checked=False, reset=False):
        try:
            if self.grouped:
                try:
                    self.project.layerWasAdded.disconnect(self.add_layer_sync)
                except Exception:
                    print('could not disconnect add_layer_sync')
                try:
                    self.project.layerRemoved.disconnect(self.remove_layer_sync)
                except Exception:
                    print('could not disconnect remove_layer_sync')
                self.groupToTree(reset_initial_visibility=reset)
                self.resetAction.setText("Group and make all layers visible")
            else:
                self.treeToGroup(all_visible=reset)
                self.resetAction.setText("Ungroup and restore initial (ungrouped) visibility")
                self.project.layerWasAdded.connect(self.add_layer_sync)
                self.project.layerRemoved.connect(self.remove_layer_sync)
        except Exception as e:
            raise(e)
        finally:
            # synchronize plugin state with button state in case of exceptions
            self.grouped = checked

    def run_reset_visibility(self):
        self.action.toggle()
        self.run(checked=self.action.isChecked(), reset=True)

    def reset_state(self):
        self.action.setChecked(False)
        self.grouped = False

    def write(self):
        if self.grouped:
            answer = QMessageBox.question(self.iface.mainWindow(),
                                          "Save ungrouped state",
                                          "The layers are currently grouped by the "
                                          "groupLayers plugin\n\n"
                                          "Would you like to save the initial (ungrouped) state?\n"
                                          "(save current (grouped) layer tree if answer = NO)",
                                          QMessageBox.Yes|QMessageBox.No)
            if answer == QMessageBox.Yes:
                self.treeBeforeSave = self.iface.layerTreeCanvasBridge().rootGroup().clone()
                self.groupToTree(reset_initial_visibility=True)
                self.iface.messageBar().pushMessage(
                    'CAUTION: The layer tree has been saved in its original format, '
                    'check options if you want to change this behavior.', Qgis.Info
                )

    def saved(self):
        if self.treeBeforeSave is not None:
            tempOldTree = self.oldTree
            self.oldTree = self.treeBeforeSave
            self.groupToTree(reset_initial_visibility=True)
            self.oldTree = tempOldTree
        self.treeBeforeSave = None

    def add_layer_sync(self, addedLayer):
        self.oldTree.addLayer(addedLayer)

    def remove_layer_sync(self, removedLayerId):
        removedLayer = self.oldTree.findLayer(removedLayerId)
        self.recursiveRemoveFromGroup(self.oldTree, removedLayer)

    def recursiveRemoveFromGroup(self, group, layer):
        group.removeChildNode(layer)
        for subGroup in group.findGroups():
            self.recursiveRemoveFromGroup(subGroup, layer)

    def initTreeRec(self, hierarchyDefinition, tree):
        for (k, v) in hierarchyDefinition.items():
            if "groupCriteria" in v:
                tree[k] = {}
                self.initTreeRec(v["values"], tree[k])
            else:
                tree[k] = []

    def treeToGroup(self, all_visible=True):
        self.layerDict = {}
        self.treeRoot = self.project.layerTreeRoot()
        self.initTreeRec(self.hierarchyDefinition['values'], self.layerDict)
        layerTree = self.iface.layerTreeCanvasBridge().rootGroup()
        self.oldTree = layerTree.clone()
        self.parseTreeRec(layerTree)  # into self.layerDict
        self.layerDict = self.cleanTree(self.layerDict)
        oldLen = len(layerTree.children())
        self.layerDictToTree(self.layerDict, layerTree, all_visible)

        # caution: commented instruction below removes all layers !!
        # iface.layerTreeCanvasBridge().rootGroup().clear()
        layerTree.removeChildren(0, oldLen)

    def groupToTree(self, reset_initial_visibility=True):
        self.treeRoot = self.project.layerTreeRoot()
        layerTree = self.iface.layerTreeCanvasBridge().rootGroup()
        oldLen = len(layerTree.children())
        self.insertInto(self.oldTree, layerTree, reset_initial_visibility)
        layerTree.removeChildren(0, oldLen)

    def layerDictToTree(self, layerDict, destinationGroup, all_visible):
        if isinstance(layerDict, dict):
            for (layerType, layers) in layerDict.items():
                grp = destinationGroup.addGroup(layerType)
                self.layerDictToTree(layers, grp, all_visible)
        elif isinstance(layerDict, list):
            for l in layerDict:
                isVisible = self.treeRoot.findLayer(l).isVisible()
                node = destinationGroup.addLayer(l)
                if not all_visible:
                    node.setItemVisibilityChecked(isVisible)

        else:
            raise Exception("Tree dictionary has been initialized incorrectly.")

    def insertInto(self, origin, destination, reset_initial_visibility):
        for el in origin.children():
            if QgsLayerTree.isLayer(el):
                node = destination.addLayer(el.layer())
                node.setItemVisibilityChecked(
                    self.treeRoot.findLayer(el.layer()).isVisible()
                )
            elif QgsLayerTree.isGroup(el):
                node = destination.addGroup(el.name())
                self.insertInto(el, node, reset_initial_visibility)
            if reset_initial_visibility:
                # overwrite visibility with previously saved visibility
                node.setItemVisibilityChecked(el.itemVisibilityChecked())

    def parseTreeRec(self, treeLeaf):
        for el in treeLeaf.children():
            if QgsLayerTree.isLayer(el):
                l = el.layer()
                self.sortInto(l, self.layerDict, self.hierarchyDefinition)
            elif QgsLayerTree.isGroup(el):
                self.parseTreeRec(el)

    def sortInto(self, layer, destination, definitions):
        if "groupCriteria" in definitions:
            groupValue = layer.__getattribute__(definitions["groupCriteria"])()
            itemFound = False
            for (label, criteria) in definitions["values"].items():
                if groupValue == criteria["value"]:
                    itemFound = True
                    self.sortInto(layer, destination[label], criteria)
            if not itemFound:
                if self.groupAdditionalTypes:
                    groupName = "others"
                else:
                    groupName = str(groupValue)
                try:
                    destination[groupName].append(layer)
                except KeyError:
                    destination[groupName] = [layer]
        else:
            destination.append(layer)

    def cleanTree(self, sourceTree):
        # remove all branches without end leaves
        if isinstance(sourceTree, dict):
            groupContents = {}
            for (layerType, layers) in sourceTree.items():
                groupLayers = self.cleanTree(layers)
                if groupLayers:
                    groupContents[layerType] = groupLayers
            return groupContents
        elif isinstance(sourceTree, list):
            return sourceTree
        else:
            raise Exception("Tree dictionary has been initialized incorrectly.")
Example #15
0
class SeilaplanPlugin(object):
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        # 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]
        localePath = os.path.join(self.plugin_dir, 'i18n',
                                  'SeilaplanPlugin_{}.qm'.format(locale))

        if os.path.exists(localePath):
            self.translator = QTranslator()
            self.translator.load(localePath)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        self.action = None
        self.progressDialog = None
        self.dlg = None
        
        # try:
        #     import pydevd
        #     pydevd.settrace('localhost', port=53100,
        #                 stdoutToServer=True, stderrToServer=True)
        # except ConnectionRefusedError:
        #     pass
        # except ImportError:
        #     pass


    def initGui(self):
        # Create action that will start plugin configuration
        self.action = QAction(
            QIcon(":/plugins/SeilaplanPlugin/icons/icon_app.png"),
            "SEILAPLAN", self.iface.mainWindow())
        self.action.setWhatsThis("SEILAPLAN")
        # Connect the action to the run method
        self.action.triggered.connect(self.run)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu("&SEILAPLAN", self.action)


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        self.iface.removePluginMenu('&SEILAPLAN', self.action)
        self.iface.removeToolBarIcon(self.action)

    def run(self):
        """Run method that performs all the real work"""

        # Control variables for possible rerun of algorithm
        reRun = True
        reRunProj = None

        while reRun:
    
            
            
            # Create seperate threa for calculations so that QGIS stays
            # responsive
            workerThread = ProcessingTask()
            
            # Initialize dialog window
            self.dlg = SeilaplanPluginDialog(self.iface, workerThread)
            # Get available raster from table of content in QGIS
            self.dlg.updateRasterList()
            # Load initial values of dialog
            self.dlg.loadInitialVals()

            # If this is a rerun of the algorithm the previous user values are
            #   loaded into the GUI
            if reRunProj:
                self.dlg.loadProj(reRunProj)

            self.dlg.show()
            # Start event loop
            self.dlg.exec_()

            reRun = False
            reRunProj = None

            
            # The algorithm is executed in a separate thread. To see progress,
            # a new gui shows a progress bar.
            
            # If all needed data has been input in the gui and the user has
            # clicked 'ok'
            if workerThread.state is True:
                # Initialize gui to show progress
                self.progressDialog = ProgressDialog(self.iface)
                self.progressDialog.setThread(workerThread)

                # Add task to taskmanager of QGIS and start the calculations
                QgsApplication.taskManager().addTask(workerThread)

                # Show progress bar
                self.progressDialog.run()

                # After calculations have finished and progress gui has been
                # closed: Check if user wants a rerun
                if self.progressDialog.reRun:
                    reRun = True
                    reRunProj = workerThread.projInfo['projFile']

                del self.progressDialog
            
            del workerThread
            del self.dlg

        return

    def reject(self):
        self.dlg.Reject()

    def cleanUp(self):
        pass
Example #16
0
class MetaSearchPlugin(object):

    """base plugin"""

    def __init__(self, iface):
        """init"""

        self.iface = iface
        self.context = StaticContext()
        self.action_run = None
        self.action_help = None
        self.dialog = None
        self.web_menu = '&MetaSearch'

    def initGui(self):
        """startup"""

        # run
        run_icon = QIcon('%s/%s' % (self.context.ppath,
                                    'images/MetaSearch.png'))
        self.action_run = QAction(run_icon, 'MetaSearch',
                                  self.iface.mainWindow())
        self.action_run.setWhatsThis(QCoreApplication.translate('MetaSearch',
                                                                'MetaSearch plugin'))
        self.action_run.setStatusTip(QCoreApplication.translate('MetaSearch',
                                                                'Search Metadata Catalogues'))

        self.action_run.triggered.connect(self.run)

        self.iface.addWebToolBarIcon(self.action_run)
        self.iface.addPluginToWebMenu(self.web_menu, self.action_run)

        # help
        help_icon = QgsApplication.getThemeIcon('/mActionHelpContents.svg')
        self.action_help = QAction(help_icon, 'Help', self.iface.mainWindow())
        self.action_help.setWhatsThis(QCoreApplication.translate('MetaSearch',
                                                                 'MetaSearch plugin help'))
        self.action_help.setStatusTip(QCoreApplication.translate('MetaSearch',
                                                                 'Get Help on MetaSearch'))
        self.action_help.triggered.connect(self.help)

        self.iface.addPluginToWebMenu(self.web_menu, self.action_help)

        # prefab the dialog but not open it yet
        self.dialog = MetaSearchDialog(self.iface)

    def unload(self):
        """teardown"""

        # remove the plugin menu item and icon
        self.iface.removePluginWebMenu(self.web_menu, self.action_run)
        self.iface.removePluginWebMenu(self.web_menu, self.action_help)
        self.iface.removeWebToolBarIcon(self.action_run)

    def run(self):
        """open MetaSearch"""

        self.dialog.exec_()

    def help(self):
        """open help in user's default web browser"""

        open_url(get_help_url())
class VoGISProfilToolMainDialog(QDialog):
    def __init__(self, interface, settings):
        QDialog.__init__(self, interface.mainWindow())

        # Set up the user interface from Designer.
        self.ui = Ui_VoGISProfilToolMain()
        self.ui.setupUi(self)
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setText(QApplication.translate("code", "Profil erstellen"))
        self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(QApplication.translate("code", "Schließen"))

        self.ui.grpCadastre.toggled.connect(self._toggleCadastreLayer)
        self.ui.cmbCadastreLayer.currentIndexChanged.connect(self._updateCadastreLayer)

        self.settings = settings
        self.iface = interface
        self.selectingVisibleRasters = False
        self.thread = None

        if self.settings.onlyHektoMode is True:
            self.ui.IDC_widRaster.hide()
            self.adjustSize()

        self.ui.IDC_dblspinDistance.setValue(self.settings.equiDistance)
        self.ui.IDC_dblspinVertexCnt.setValue(self.settings.vertexCnt)

        validator = QIntValidator(-32768, 32768, self)
        self.ui.IDC_tbNoDataExport.setValidator(validator)

        self.ui.IDC_tbFromX.setText("-30000")
        self.ui.IDC_tbFromY.setText("240000")
        self.ui.IDC_tbToX.setText("-20000")
        self.ui.IDC_tbToY.setText("230000")

        self.__addRastersToGui()
        self.__addPolygonsToGui()

        for line_lyr in self.settings.mapData.lines.lines():
            self.ui.IDC_cbLineLayers.addItem(line_lyr.name, line_lyr)

        if self.settings.mapData.lines.count() < 1:
            self.ui.IDC_rbDigi.setChecked(True)
            self.ui.IDC_rbShapeLine.setEnabled(False)

        #Einstellungen fuer Linie zeichen
        self.action = QAction(
            QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"),
            "VoGIS-Profiltool",
            self.iface.mainWindow())
        self.action.setWhatsThis("VoGIS-Profiltool")

        self.canvas = self.iface.mapCanvas()
        self.tool = ProfiletoolMapTool(self.canvas, self.action)
        self.savedTool = self.canvas.mapTool()
        self.polygon = False

        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        self.rubberband.setLineStyle(Qt.SolidLine)
        self.rubberband.setWidth(4.0)
        self.rubberband.setColor(QColor(0, 255, 0))
        #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab

        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None

    def accept(self):
        try:
            nodata = self.ui.IDC_tbNoDataExport.text()
            self.settings.nodata_value = int(nodata) if nodata != "" else None
            QgsMessageLog.logMessage("Maindlg: nodata: {0}".format(self.settings.nodata_value), "VoGis", Qgis.Info)

            if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count() > 0:
                self.settings.onlyHektoMode = False

            if self.settings.onlyHektoMode is False:
                if self.settings.mapData.rasters.count() < 1:
                   retVal = QMessageBox.warning(self.iface.mainWindow(),
                                                "VoGIS-Profiltool",
                                                QApplication.translate("code", "Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?"),
                                                QMessageBox.Yes | QMessageBox.No,
                                                QMessageBox.Yes)
                   if retVal == QMessageBox.No:
                       return
                   else:
                       self.settings.onlyHektoMode = True
                       self.settings.createHekto = True

            if self.__getSettingsFromGui() is False:
                return

            if self.settings.onlyHektoMode is False:
                if len(self.settings.mapData.rasters.selectedRasters()) < 1:
                    QMessageBox.warning(self.iface.mainWindow(),
                                        "VoGIS-Profiltool",
                                        QApplication.translate("code", "Kein Raster selektiert!"))
                    return

            QgsMessageLog.logMessage("modeLine!=line: {0}".format(self.settings.modeLine != enumModeLine.line), "VoGis", Qgis.Info)
            QgsMessageLog.logMessage("customLine is None: {0}".format(self.settings.mapData.customLine is None), "VoGis", Qgis.Info)

            if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None:
                QMessageBox.warning(self.iface.mainWindow(),
                                    "VoGIS-Profiltool",
                                    QApplication.translate("code", "Keine Profillinie vorhanden!"))
                return

            if len(self.settings.mapData.polygons.selected_polygons()) > 0 and len(self.settings.mapData.rasters.selectedRasters()) > 1:
                raster_names = list(raster.name for raster in self.settings.mapData.rasters.selectedRasters())
                sel_raster, ok_clicked = QInputDialog.getItem(
                                                self.iface.mainWindow(),
                                                "DHM?",
                                                "Welches DHM soll zur Flächenverschneidung verwendet werden?",
                                                raster_names,
                                                0,
                                                False
                                                )
                if ok_clicked is False:
                    return

                self.settings.intersection_dhm_idx = raster_names.index(sel_raster)

            QApplication.setOverrideCursor(Qt.WaitCursor)

            create_profile = CreateProfile(self.iface, self.settings)
            thread = QThread(self)
            create_profile.moveToThread(thread)
            create_profile.finished.connect(self.profiles_finished)
            create_profile.error.connect(self.profiles_error)
            create_profile.progress.connect(self.profiles_progress)
            thread.started.connect(create_profile.create)
            thread.start(QThread.LowestPriority)
            self.thread = thread
            self.create_profile = create_profile
            self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
        except:
            QApplication.restoreOverrideCursor()
            ex = "{0}".format(traceback.format_exc())
            msg = "Unexpected ERROR:\n\n{0}".format(ex[:2000])
            QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", msg)

    def profiles_finished(self, profiles, intersections, cadastre):
        QApplication.restoreOverrideCursor()
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
        self.thread.quit()
        self.thread.wait()

        #QGIS 2.0 http://gis.stackexchange.com/a/58754 http://gis.stackexchange.com/a/57090
        self.iface.mainWindow().statusBar().showMessage("VoGIS-Profiltool, {0} Profile".format(len(profiles)))
        QgsMessageLog.logMessage("Profile Count: {0}".format(len(profiles)), "VoGis", Qgis.Info)

        if len(profiles) < 1:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self.iface.mainWindow(),
                                "VoGIS-Profiltool",
                                QApplication.translate("code", "Es konnten keine Profile erstellt werden."))
            return

        dlg = VoGISProfilToolPlotDialog(self.iface, self.settings, profiles, intersections, cadastre)
        dlg.show()
        dlg.exec_()

    def profiles_error(self, exception_string):
        QApplication.restoreOverrideCursor()
        QgsMessageLog.logMessage("Error during profile creation: {0}".format(exception_string), "VoGis", Qgis.Critical)
        QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool", exception_string)

    def profiles_progress(self, msg):
        self.iface.mainWindow().statusBar().showMessage(msg)
        self.ui.IDC_lblCreateStatus.setText(msg)
        QApplication.processEvents()

    def reject(self):
        if not self.thread is None:
            if self.thread.isRunning():
                self.create_profile.abort()
                return

        self.rubberband.reset(self.polygon)
        QDialog.reject(self)

    def selectVisibleRasters(self):
        self.refreshRasterList()
        self.selectingVisibleRasters = True
        extCanvas = self.iface.mapCanvas().extent()
        #alle raster in den einstellunge deselektieren
        for r in self.settings.mapData.rasters.rasters():
            r.selected = False
        #alle raster in der ListView deselektieren
        for idx in range(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            item.setCheckState(Qt.Unchecked)
        #Raster im Extent selektieren
        canvasCrs = self.iface.mapCanvas().mapSettings().destinationCrs()
        for idx in range(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            raster = item.data(Qt.UserRole)
            for r in self.settings.mapData.rasters.rasters():
                layerCrs = r.grid.crs()
                ct = QgsCoordinateTransform(layerCrs, canvasCrs, QgsProject.instance())
                extent = ct.transform(r.grid.extent())
                if extCanvas.intersects(extent):
                    if r.id == raster.id:
                        r.selected = True
                        item.setCheckState(Qt.Checked)
        self.selectingVisibleRasters = False

    def lineLayerChanged(self, idx):
        if self.ui.IDC_rbShapeLine.isChecked() is False:
            self.ui.IDC_rbShapeLine.setChecked(True)
        lineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()))

        lyr = lineLyr.line
        if hasattr(lyr, "selectedFeatureCount"):
            if(lyr.selectedFeatureCount() < 1):
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(False)
            else:
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(True)

    def valueChangedEquiDistance(self, val):
        if self.ui.IDC_rbEquiDistance.isChecked() is False:
            self.ui.IDC_rbEquiDistance.setChecked(True)

    def valueChangedVertexCount(self, val):
        if self.ui.IDC_rbVertexCount.isChecked() is False:
            self.ui.IDC_rbVertexCount.setChecked(True)

    def lvRasterItemChanged(self, item):
        if self.selectingVisibleRasters is True:
            return
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        raster_lyr = item_data
        self.settings.mapData.rasters.getById(raster_lyr.id).selected = selected

    def lvPolygonItemChanged(self, item):
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        poly_lyr = item_data
        self.settings.mapData.polygons.getById(poly_lyr.id).selected = selected

    def refreshRasterList(self):
        root = QgsProject.instance().layerTreeRoot()
        avail_lyrs = root.findLayers()

        raster_coll = RasterCollection()

        for lyr in avail_lyrs:
            if lyr.isVisible():
                mapLayer = lyr.layer()
                lyr_type = mapLayer.type()
                lyr_name = mapLayer.name()
                if lyr_type == QgsMapLayer.RasterLayer:
                    if mapLayer.bandCount() < 2:
                        new_raster = Raster(mapLayer.id(), lyr_name, mapLayer)
                        raster_coll.addRaster(new_raster)

        self.settings.mapData.rasters = raster_coll
        self.__addRastersToGui()

    def __addRastersToGui(self):
        self.ui.IDC_listRasters.clear()
        check = Qt.Unchecked
        if self.settings.mapData.rasters.count() == 1:
            check = Qt.Checked
            self.settings.mapData.rasters.rasters()[0].selected = True

        for raster_lyr in self.settings.mapData.rasters.rasters():
            item = QListWidgetItem(raster_lyr.name)
            item.setData(Qt.UserRole, raster_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listRasters.addItem(item)

    def __addPolygonsToGui(self):
        self.ui.IDC_listPolygons.clear()
        self.ui.cmbCadastreLayer.clear()
        check = Qt.Unchecked
        for poly_lyr in self.settings.mapData.polygons.polygons():
            item = QListWidgetItem(poly_lyr.name)
            item.setData(Qt.UserRole, poly_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listPolygons.addItem(item)
            self.ui.cmbCadastreLayer.addItem(poly_lyr.name, poly_lyr.id)

    def drawLine(self):
        if self.ui.IDC_rbDigi.isChecked() is False:
            self.ui.IDC_rbDigi.setChecked(True)
        self.dblckltemp = None
        self.rubberband.reset(self.polygon)
        self.__cleanDigi()
        self.__activateDigiTool()
        self.canvas.setMapTool(self.tool)

    def __createDigiFeature(self, pnts):
        u = Util(self.iface)
        f = u.createQgLineFeature(pnts)
        self.settings.mapData.customLine = f

    def __lineFinished(self, position):
        self.showNormal()
        self.raise_()
        self.activateWindow()

        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
        newPoint = QgsPointXY(mapPos.x(), mapPos.y())
        self.pointsToDraw.append(newPoint)
        #launch analyses
        self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw))
        if len(self.pointsToDraw) < 2:
            self.__cleanDigi()
            self.pointsToDraw = []
            self.dblclktemp = newPoint
            self.drawnLine = None
            QMessageBox.warning(self,
                                "VoGIS-Profiltool",
                                QApplication.translate("code", "Profillinie digitalisieren abgebrochen!"))
        self.drawnLine = self.__createDigiFeature(self.pointsToDraw)
        self.__cleanDigi()

        self.pointsToDraw = []
        self.dblclktemp = newPoint

    def __cleanDigi(self):
        self.pointsToDraw = []
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.savedTool)

    def __activateDigiTool(self):
        self.tool.moved.connect(self.__moved)
        self.tool.rightClicked.connect(self.__rightClicked)
        self.tool.leftClicked.connect(self.__leftClicked)
        self.tool.doubleClicked.connect(self.__doubleClicked)
        self.tool.deactivated.connect(self.__deactivateDigiTool)

    def __deactivateDigiTool(self):
        # TODO: how to check if not connected???
        try:
            self.tool.moved.disconnect(self.__moved)
        except:
            pass
        try:
            self.tool.leftClicked.disconnect(self.__leftClicked)
        except:
            pass
        try:
            self.tool.rightClicked.disconnect(self.__rightClicked)
        except:
            pass
        try:
            self.tool.doubleClicked.disconnect(self.__doubleClicked)
        except:
            pass
        try:
            self.iface.mainWindow().statusBar().showMessage("")
        except:
            pass

    def __moved(self, position):
        if len(self.pointsToDraw) > 0:
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
            self.rubberband.reset(self.polygon)
            newPnt = QgsPointXY(mapPos.x(), mapPos.y())
            pnts = self.pointsToDraw + [newPnt]
            self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(pnts), None)

    def __rightClicked(self, position):
        self.__lineFinished(position)

    def __leftClicked(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(position["x"], position["y"])
        newPoint = QgsPointXY(mapPos.x(), mapPos.y())
        if newPoint == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset(self.polygon)
            self.pointsToDraw.append(newPoint)

    def __doubleClicked(self, position):
        pass

    #not in use right now
    def __lineCancel(self):
        pass

    def __getSettingsFromGui(self):
        self.settings.linesExplode = (self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked)
        self.settings.linesMerge = (self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked)
        self.settings.onlySelectedFeatures = (self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked)
        self.settings.equiDistance = self.ui.IDC_dblspinDistance.value()
        self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value()
        #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked)
        self.settings.nodesAndVertices = (self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked)

        self.settings.mapData.selectedLineLyr = (self.ui.IDC_cbLineLayers.itemData(self.ui.IDC_cbLineLayers.currentIndex()))

        if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount() < 1:
            QMessageBox.warning(self.iface.mainWindow(),
                                "VoGIS-Profiltool",
                                QApplication.translate("code", u"Der gewählte Layer hat keine selektierten Elemente."))
            return False

        if self.ui.IDC_rbDigi.isChecked():
            self.settings.modeLine = enumModeLine.customLine
        elif self.ui.IDC_rbShapeLine.isChecked():
            self.settings.modeLine = enumModeLine.line
        else:
            #self.ui.IDC_rbStraigthLine
            self.settings.modeLine = enumModeLine.straightLine

        if self.ui.IDC_rbEquiDistance.isChecked():
            self.settings.modeVertices = enumModeVertices.equiDistant
        else:
            self.settings.modeVertices = enumModeVertices.vertexCnt

        if self.ui.IDC_rbStraigthLine.isChecked():
            ut = Util(self.iface)
            if ut.isFloat(self.ui.IDC_tbFromX.text(), QApplication.translate("code", "Rechtswert von")) is False:
                return False
            else:
                fromX = float(self.ui.IDC_tbFromX.text())
            if ut.isFloat(self.ui.IDC_tbFromY.text(), QApplication.translate("code", "Hochwert von")) is False:
                return False
            else:
                fromY = float(self.ui.IDC_tbFromY.text())
            if ut.isFloat(self.ui.IDC_tbToX.text(), QApplication.translate("code", "Rechtswert nach")) is False:
                return False
            else:
                toX = float(self.ui.IDC_tbToX.text())
            if ut.isFloat(self.ui.IDC_tbToY.text(), QApplication.translate("code", "Hochwert nach")) is False:
                return False
            else:
                toY = float(self.ui.IDC_tbToY.text())

            fromPnt = QgsPointXY(fromX, fromY)
            toPnt = QgsPointXY(toX, toY)

            self.settings.mapData.customLine = ut.createQgLineFeature([fromPnt, toPnt])

        return True

    def _toggleCadastreLayer(self, toggled):
        if toggled:
            layerId = self.ui.cmbCadastreLayer.itemData(self.ui.cmbCadastreLayer.currentIndex())
            self.settings.mapData.cadastre = layerId
        else:
            self.settings.mapData.cadastre = None

    def _updateCadastreLayer(self, index):
        if self.ui.grpCadastre.isChecked():
            layerId = self.ui.cmbCadastreLayer.itemData(index)
            self.settings.mapData.cadastre = layerId
class PostNAS_Search:

    def __init__(self, iface):
        # 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','PostNAS_Search_{}.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 = PostNAS_SearchDialog(iface=self.iface)
        self.conf = PostNAS_ConfDialog(iface=self.iface)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&PostNAS_Search')

        self.searchDockWidget = None
        self.searchDockWidgetArea = Qt.LeftDockWidgetArea

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('PostNAS_Search', message)

    def initGui(self):
        # Create Conf-Action and Menuentry
        self.confAction = QAction("Einstellungen", self.iface.mainWindow())
        self.confAction.setWhatsThis("Konfiguration der PostNAS-Suche")
        self.confAction.setStatusTip("Konfiguration der PostNAS-Suche")
        self.confAction.triggered.connect(self.showConf)

        if hasattr(self.iface, "addPluginToDatabaseMenu"):
            self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.confAction)
        else:
            self.iface.addPluginToMenu("&PostNAS-Suche", self.confAction)

        self.toggleSearchAction = QAction(u"Flurstücksuche", self.iface.mainWindow())
        self.toggleSearchAction.setWhatsThis(u"Starten/Schliessen der Flurstücksuche")
        self.toggleSearchAction.setStatusTip(u"Starten/Schliessen der Flurstücksuche")
        self.toggleSearchAction.triggered.connect(self.toggleWidget)

        if hasattr(self.iface, "addPluginToDatabaseMenu"):
            self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.toggleSearchAction)
        else:
            self.iface.addPluginToMenu("&PostNAS-Suche", self.toggleSearchAction)

        self.fulltextindex = QAction(u"Volltextindex erstellen", self.iface.mainWindow())
        self.fulltextindex.setWhatsThis(u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen")
        self.fulltextindex.setStatusTip(u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen")
        self.fulltextindex.triggered.connect(self.createFulltextindex)

        if hasattr(self.iface, "addPluginToDatabaseMenu"):
            self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.fulltextindex)
        else:
            self.iface.addPluginToMenu("&PostNAS-Suche", self.fulltextindex)

        # Create action that will start plugin configuration
        self.action = QAction(QIcon(":/plugins/PostNAS_Search/search_24x24.png"),u"Flurstücksuche", self.iface.mainWindow())
        self.action.setCheckable(True)
        # connect the action to the run method
        self.action.triggered.connect(self.toggleWidget)

        # Add toolbar button and menu item
        self.iface.addToolBarIcon(self.action)

    def toggleWidget(self, event):
        if self.searchDockWidget == None:
            self.searchDockWidget = QDockWidget(self.iface.mainWindow())
            self.searchDockWidget.setWindowTitle(self.tr(u'Suche'))
            self.searchDockWidget.setWidget(self.dlg)
            self.searchDockWidget.closeEvent = self.toggleWidget
            self.iface.addDockWidget(self.searchDockWidgetArea, self.searchDockWidget)
            self.action.setChecked(True)
        else:
            self.searchDockWidgetArea = self.iface.mainWindow().dockWidgetArea(self.searchDockWidget)
            self.iface.removeDockWidget(self.searchDockWidget)
            self.searchDockWidget = None
            self.action.setChecked(False)

    def showConf(self):
        dlg = PostNAS_ConfDialog(self)
        dlg.exec_()

    def createFulltextindex(self):
        dlg = PostNAS_CreateFulltextindex(self)
        dlg.exec_()

    def unload(self):
        # Remove the Toolbar Icon
        self.iface.removeToolBarIcon(self.action)
        # Remove DockWidget
        if self.searchDockWidget != None:
            self.iface.removeDockWidget(self.searchDockWidget)

        if hasattr(self.iface, "removePluginDatabaseMenu"):
            self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.confAction)
            self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.toggleSearchAction)
            self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.fulltextindex)
        else:
            self.iface.removePluginMenu("&PostNAS-Suche", self.confAction)
            self.iface.removePluginMenu("&PostNAS-Suche", self.toggleSearchAction)
            self.iface.removePluginMenu("&PostNAS-Suche", self.fulltextindex)

        if self.confAction:
            self.confAction.deleteLater()
            self.confAction = None

        if self.toggleSearchAction:
            self.toggleSearchAction.deleteLater()
            self.toggleSearchAction = None

        if self.fulltextindex:
            self.fulltextindex.deleteLater()
            self.fulltextindex = None
class BoundlessConnectPlugin(object):
    def __init__(self, iface):
        self.iface = iface

        try:
            from boundlessconnect.tests import testerplugin
            from qgistester.tests import addTestModule
            addTestModule(testerplugin, 'Boundless Connect')
        except Exception as e:
            pass

        self.dockWidget = None
        readSettings()

        self.iface.initializationCompleted.connect(self.checkFirstRun)

    def initGui(self):
        self.dockWidget = getConnectDockWidget()
        self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget)
        self.dockWidget.hide()

        utils.setRepositoryUrl()

        self.actionRunWizard = self.dockWidget.toggleViewAction()
        self.actionRunWizard.setText('Boundless Connect')
        self.actionRunWizard.setIcon(
            QIcon(os.path.join(pluginPath, 'icons', 'connect.svg')))
        self.actionRunWizard.setWhatsThis('Boundless Connect')
        self.actionRunWizard.setObjectName('actionRunWizard')

        # If Boundless repository is a directory, add menu entry
        # to start modified Plugin Manager which works with local repositories
        if utils.isRepositoryInDirectory():
            self.actionPluginManager = QAction(
                'Manage plugins (local folder)', self.iface.mainWindow())
            self.actionPluginManager.setIcon(
                QIcon(os.path.join(pluginPath, 'icons', 'plugin.svg')))
            self.actionPluginManager.setWhatsThis(
                'Manage and install plugins from local repository')
            self.actionPluginManager.setObjectName('actionPluginManager')

            self.iface.addPluginToMenu(
                'Boundless Connect', self.actionPluginManager)

            self.actionPluginManager.triggered.connect(self.pluginManagerLocal)

        actions = self.iface.mainWindow().menuBar().actions()
        for action in actions:
            if action.menu().objectName() == 'mPluginMenu':
                menuPlugin = action.menu()
                separator = menuPlugin.actions()[1]
                menuPlugin.insertAction(separator, self.actionRunWizard)
                if utils.isRepositoryInDirectory():
                    menuPlugin.insertAction(separator, self.actionPluginManager)

        addSettingsMenu('Boundless Connect')
        addHelpMenu('Boundless Connect')
        addAboutMenu('Boundless Connect')

        # Enable check for updates if it is not enabled
        utils.addCheckForUpdates()

        try:
            from lessons import addLessonsFolder, addGroup
            folder = os.path.join(os.path.dirname(__file__), "_lessons")
            addLessonsFolder(folder, "boundlessconnect")
            group_description = os.path.join(folder, "group.md")
            addGroup("Boundless Connect plugin", group_description)
        except:
            pass

    def unload(self):
        actions = self.iface.mainWindow().menuBar().actions()
        for action in actions:
            if action.menu().objectName() == 'mPluginMenu':
                menuPlugin = action.menu()
                menuPlugin.removeAction(self.actionRunWizard)
                if utils.isRepositoryInDirectory():
                    menuPlugin.removeAction(self.actionPluginManager)

        removeSettingsMenu('Boundless Connect')
        removeHelpMenu('Boundless Connect')
        removeAboutMenu('Boundless Connect')

        self.dockWidget.hide()

        try:
            from boundlessconnect.tests import testerplugin
            from qgistester.tests import removeTestModule
            removeTestModule(testerplugin, 'Boundless Connect')
        except Exception as e:
            pass

        try:
            from lessons import removeLessonsFolder
            folder = os.path.join(pluginPath, '_lessons')
            removeLessonsFolder(folder)
        except:
            pass

    def checkFirstRun(self):
        settings = QSettings()
        firstRun = settings.value('boundlessconnect/firstRun', True, bool)
        settings.setValue('boundlessconnect/firstRun', False)

        if self.dockWidget is None:
            self.dockWidget = getConnectDockWidget()

        if firstRun:
            self.dockWidget.show()
            utils.installFromStandardPath()

    def installPlugin(self):
        fileName = askForFiles(self.iface.mainWindow(),
                               'Open file',
                               exts='zip')

        if fileName is None:
            return

        result = utils.installFromZipFile(fileName)
        if result is None:
            self._showMessage('Plugin installed successfully',
                              QgsMessageBar.SUCCESS)
        else:
            self._showMessage(result, QgsMessageBar.WARNING)

        settings.setValue('lastPluginDirectory',
            QFileInfo(fileName).absoluteDir().absolutePath())

    def pluginManagerLocal(self):
        utils.showPluginManager(False)

    def _showMessage(self, message, level=QgsMessageBar.INFO):
        self.iface.messageBar().pushMessage(
            message, level, self.iface.messageTimeout())
Example #20
0
class XYZHubConnector(object):
    """base plugin"""
    def __init__(self, iface):
        """init"""
        import sys
        print(sys.version)
        self.iface = iface
        self.web_menu = "&XYZ Hub Connector"
        self.init_modules()
        self.obj = self

    def initGui(self):
        """startup"""

        parent = self.iface.mainWindow()

        ######## action, button

        icon = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/xyz.png"))
        icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/bbox.svg"))
        self.action_connect = QAction(icon, "New XYZ Hub Connection", parent)
        self.action_connect.setWhatsThis(
            QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message"))
        self.action_connect.setStatusTip(
            QCoreApplication.translate(PLUGIN_NAME, "status tip message"))

        self.action_clear_cache = QAction("Clear cache", parent)
        self.action_upload = QAction("Upload to New XYZ Geospace", parent)
        self.action_basemap = QAction("Add HERE Map Tile", parent)

        self.action_magic_sync = QAction("Magic Sync (EXPERIMENTAL)", parent)
        self.action_manage = QAction("Manage XYZ Geospace (EXPERIMENTAL)",
                                     parent)
        self.action_edit = QAction("Edit/Delete XYZ Geospace (EXPERIMENTAL)",
                                   parent)

        if self.iface.activeLayer() is None:
            # self.action_upload.setEnabled(False)
            self.action_edit.setEnabled(False)
            self.action_magic_sync.setEnabled(False)

        # self.action_magic_sync.setVisible(False) # disable magic sync

        ######## CONNECT action, button

        self.action_connect.triggered.connect(self.open_connection_dialog)
        self.action_manage.triggered.connect(self.open_manage_dialog)
        self.action_edit.triggered.connect(self.open_edit_dialog)
        self.action_upload.triggered.connect(self.open_upload_dialog)
        self.action_magic_sync.triggered.connect(self.open_magic_sync_dialog)
        self.action_clear_cache.triggered.connect(self.open_clear_cache_dialog)
        self.action_basemap.triggered.connect(self.open_basemap_dialog)

        ######## Add the toolbar + button
        self.toolbar = self.iface.addToolBar(PLUGIN_NAME)
        self.toolbar.setObjectName("XYZ Hub Connector")

        tool_btn = QToolButton(self.toolbar)

        self.actions = [
            self.action_connect, self.action_upload, self.action_basemap,
            self.action_clear_cache
        ]  # , self.action_magic_sync, self.action_manage, self.action_edit
        for a in self.actions:
            tool_btn.addAction(a)
            self.iface.addPluginToWebMenu(self.web_menu, a)

        tool_btn.setDefaultAction(self.action_connect)
        tool_btn.setPopupMode(tool_btn.MenuButtonPopup)

        self.xyz_widget_action = self.toolbar.addWidget(tool_btn)

        self.action_help = None

        self.action_reload = QAction(icon_bbox, "Reload BBox", parent)
        self.action_reload.triggered.connect(self.layer_reload_bbox)
        self.action_reload.setVisible(False)  # disable
        self.toolbar.addAction(self.action_reload)

        progress = QProgressBar()
        progress.setMinimum(0)
        progress.setMaximum(0)
        progress.reset()
        progress.hide()
        # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis
        self.iface.statusBarIface().addPermanentWidget(progress)
        self.pb = progress

    def init_modules(self):
        # util.init_module()

        # parent = self.iface.mainWindow()
        parent = QgsProject.instance()

        ######## Init xyz modules
        self.map_basemap_meta = basemap.load_default_xml()
        self.auth_manager = AuthManager(config.PLUGIN_DIR + "/auth.ini")

        self.token_model = GroupTokenModel(parent)
        # self.layer = LayerManager(parent, self.iface)

        self.network = NetManager(parent)

        self.con_man = ControllerManager()
        self.layer_man = LayerManager()

        ######## data flow
        self.conn_info = SpaceConnectionInfo()

        ######## token
        print(config.PLUGIN_DIR)
        self.token_model.load_ini(config.PLUGIN_DIR + "/token.ini")

        ######## CALLBACK
        # self.iface.mapCanvas().extentsChanged.connect( self.debug_reload)
        # self.con_man.connect_ux( self.iface) # canvas ux
        # self.con_man.signal.canvas_span.connect( self.loader_reload_bbox)

        self.con_man.ld_pool.signal.progress.connect(
            self.cb_progress_busy)  #, Qt.QueuedConnection
        self.con_man.ld_pool.signal.finished.connect(self.cb_progress_done)

        QgsProject.instance().layersWillBeRemoved["QStringList"].connect(
            self.layer_man.remove)
        QgsProject.instance().layersWillBeRemoved["QStringList"].connect(
            self.con_man.remove)

        # self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT

        if DEBUG:
            QgsApplication.messageLog().messageReceived.connect(print_qgis)

    def unload_modules(self):
        # self.con_man.disconnect_ux( self.iface)
        QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect(
            self.layer_man.remove)
        QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect(
            self.con_man.remove)

        # utils.disconnect_silent(self.iface.currentLayerChanged)

        # self.con_man.unload()
        # del self.con_man

        # self.iface.mapCanvas().extentsChanged.disconnect( self.debug_reload)

        close_print_qgis()
        pass

    def unload(self):
        """teardown"""
        self.unload_modules()
        # remove the plugin menu item and icon
        self.iface.removePluginWebMenu(self.web_menu, self.action_help)

        self.toolbar.clear(
        )  # remove action from custom toolbar (toolbar still exist)
        self.toolbar.deleteLater()

        for a in self.actions:
            self.iface.removePluginWebMenu(self.web_menu, a)

    ###############
    # Callback
    ###############
    def cb_layer_selected(self, qlayer):
        flag_xyz = True if qlayer is not None and self.layer.is_xyz_supported_layer(
            qlayer) else False
        # disable magic sync
        # self.action_magic_sync.setEnabled(flag_xyz)
        flag_layer = True
        self.action_upload.setEnabled(flag_layer)
        self.action_edit.setEnabled(flag_layer)

    ###############
    # Callback of action (main function)
    ###############
    def cb_success_msg(self, msg, info=""):
        self.iface.messageBar().pushMessage(msg, info, Qgis.Success, 1)

    def make_cb_success(self, msg, info=""):
        def _cb_success_msg():
            txt = info
            self.cb_success_msg(msg, txt)

        return _cb_success_msg

    def cb_handle_error_msg(self, e):
        err = parse_exception_obj(e)
        if isinstance(err, ChainInterrupt):
            e0, idx = err.args[0:2]
            if isinstance(e0, net_handler.NetworkError):
                ok = self.show_net_err_dialog(e0)
                if ok: return
            elif isinstance(e0, loader.EmptyXYZSpaceError):
                ret = exec_warning_dialog(
                    "Warning", "Requested query returns no features")
        self.show_err_msgbar(err)

    def show_net_err_dialog(self, err):
        assert isinstance(err, net_handler.NetworkError)
        reply_tag, status, reason, body = err.args[:4]
        if reply_tag in ["count"]:  # too many error
            return 0

        msg = ("%s: %s\n" % (status, reason) +
               "There was a problem connecting to the server")
        if status == 403:
            msg += "\n\n" + "Please make sure that the token has WRITE permission"
        ret = exec_warning_dialog("Network Error", msg, body)
        return 1

    def show_err_msgbar(self, err):
        self.iface.messageBar().pushMessage(TAG_PLUGIN, repr(err),
                                            Qgis.Warning, 5)
        msg = format_traceback(err)
        QgsMessageLog.logMessage(msg, TAG_PLUGIN, Qgis.Warning)

    def cb_progress_busy(self, n_active):
        if n_active > 1: return
        self.flag_pb_show = True
        self.cb_progress_refresh()

    def cb_progress_done(self):
        self.flag_pb_show = False
        self.cb_progress_refresh()

    def cb_progress_refresh(self):
        if not hasattr(self, "flag_pb_show"): return

        pb = self.pb
        if self.flag_pb_show:
            pb.show()
            print_qgis("show", pb)
        else:
            pb.hide()
            print_qgis("hide")

    ###############
    # Action (main function)
    ###############
    def load_bbox(self, con, args):
        bbox = bbox_utils.extend_to_bbox(
            bbox_utils.get_bounding_box(self.iface))
        a, kw = parse_qt_args(args)
        kw["bbox"] = bbox
        kw["limit"] = 1000
        con.start(*a, **kw)

    def layer_reload_bbox(self):
        con_bbox_reload = ReloadLayerController_bbox(self.network)
        self.con_man.add(con_bbox_reload)
        # con_bbox_reload.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_bbox_reload.signal.finished.connect(
            self.make_cb_success("Bounding box loading finish"))
        con_bbox_reload.signal.error.connect(self.cb_handle_error_msg)

        # TODO: set/get params from vlayer
        layer_id = self.iface.activeLayer().id()
        layer = self.layer_man.get(layer_id)
        self.load_bbox(con_bbox_reload, make_qt_args(layer))

    # UNUSED
    def debug_reload(self):
        print("debug_reload")

    def refresh_canvas(self):
        self.iface.mapCanvas().refresh()
        # assert False # debug unload module

    def previous_canvas_extent(self):
        self.iface.mapCanvas().zoomToPreviousExtent()

    def open_clear_cache_dialog(self):
        parent = self.iface.mainWindow()
        dialog = ConfirmDialog(
            parent, "Delete cache will make loaded layer unusable !!")
        ret = dialog.exec_()
        if ret != dialog.Ok: return

        utils.clear_cache()

    def open_connection_dialog(self):
        parent = self.iface.mainWindow()
        dialog = ConnectManageSpaceDialog(parent)
        dialog.config(self.token_model, self.conn_info)

        ############ edit btn

        con = EditSpaceController(self.network)
        self.con_man.add(con)
        con.signal.finished.connect(dialog.btn_use.clicked.emit)
        con.signal.error.connect(self.cb_handle_error_msg)
        dialog.signal_edit_space.connect(con.start_args)

        ############ delete btn

        con = DeleteSpaceController(self.network)
        self.con_man.add(con)
        con.signal.results.connect(dialog.btn_use.clicked.emit)
        con.signal.error.connect(self.cb_handle_error_msg)
        dialog.signal_del_space.connect(con.start_args)

        ############ Use Token btn

        con = LoadSpaceController(self.network)
        self.con_man.add(con)
        con.signal.results.connect(make_fun_args(dialog.cb_display_spaces))
        con.signal.error.connect(self.cb_handle_error_msg)
        con.signal.error.connect(lambda e: dialog.cb_enable_token_ui())
        con.signal.finished.connect(dialog.cb_enable_token_ui)
        dialog.signal_use_token.connect(con.start_args)

        ############ get statisitics
        con = StatSpaceController(self.network)
        self.con_man.add(con)
        con.signal.results.connect(make_fun_args(
            dialog.cb_display_space_count))
        con.signal.error.connect(self.cb_handle_error_msg)
        dialog.signal_space_count.connect(con.start_args)

        ############ TODO: bbox btn

        ############ connect btn
        con_load = loader.ReloadLayerController(self.network, n_parallel=2)
        self.con_man.add(con_load)
        # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_load.signal.finished.connect(
            self.make_cb_success("Loading finish"))
        con_load.signal.error.connect(self.cb_handle_error_msg)

        dialog.signal_space_connect.connect(con_load.start_args)

        # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT

        dialog.exec_()
        # self.startTime = time.time()

    def open_manage_dialog(self):
        pass

    def open_edit_dialog(self):
        pass

    def open_upload_dialog(self):
        vlayer = self.iface.activeLayer()
        parent = self.iface.mainWindow()
        dialog = UploadNewSpaceDialog(parent)
        dialog.config(self.token_model, self.network, vlayer)

        ############ Use Token btn
        con = LoadSpaceController(self.network)
        self.con_man.add(con)
        con.signal.results.connect(make_fun_args(
            dialog.cb_set_valid_token))  # finished signal !?
        con.signal.error.connect(self.cb_handle_error_msg)
        con.signal.finished.connect(dialog.cb_enable_token_ui)
        dialog.signal_use_token.connect(con.start_args)

        con_upload = UploadLayerController(self.network, n_parallel=2)
        self.con_man.add(con_upload)
        con_upload.signal.finished.connect(
            self.make_cb_success("Uploading finish"))
        con_upload.signal.error.connect(self.cb_handle_error_msg)

        con = InitUploadLayerController(self.network)
        self.con_man.add(con)

        dialog.signal_upload_new_space.connect(con.start_args)
        con.signal.results.connect(con_upload.start_args)
        con.signal.error.connect(self.cb_handle_error_msg)

        dialog.exec_()

    def open_magic_sync_dialog(self):
        pass

    def open_basemap_dialog(self):
        parent = self.iface.mainWindow()
        auth = self.auth_manager.get_auth()
        dialog = BaseMapDialog(parent)
        dialog.config(self.map_basemap_meta, auth)
        dialog.signal_add_basemap.connect(self.add_basemap_layer)

        dialog.exec_()

    def add_basemap_layer(self, args):
        a, kw = parse_qt_args(args)
        meta, app_id, app_code = a
        self.auth_manager.save(app_id, app_code)
        basemap.add_basemap_layer(meta, app_id, app_code)
class PdokServicesPlugin(object):

    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface

        # docked or dialog, defaults to dialog
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if isinstance(QSettings().value("/pdokservicesplugin/docked"), QVariant):
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False))
        # else:
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", False)
        #
        # # Create the dialog and keep reference
        # if "True" == self.docked or "true" == self.docked or True is self.docked:
        #     self.dlg = PdokServicesPluginDockWidget()
        #     self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        # else:
        #     self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())

        self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() + "/python/plugins/pdokservicesplugin"
        # initialize locale
        localePath = ""
        if isinstance(QSettings().value("locale/userLocale"), QVariant):
            locale = QSettings().value("locale/userLocale").value()[0:2]
        else:
            locale = QSettings().value("locale/userLocale")[0:2]

        if QFileInfo(self.plugin_dir).exists():
            localePath = self.plugin_dir + "/i18n/pdokservicesplugin_" + locale + ".qm"

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        self.currentLayer = None
        self.SETTINGS_SECTION = '/pdokservicesplugin/'
        self.pointer = None
        self.pdokgeocoder = PDOKGeoLocator(self.iface)
        self.geocoderSourceModel = None

    def getSettingsValue(self, key, default=''):
        if QSettings().contains(self.SETTINGS_SECTION + key):
            key = self.SETTINGS_SECTION + key
            if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8
                return str(QSettings().value(key).toString())
            else:
                return str(QSettings().value(key))
        else:
            return default

    def setSettingsValue(self, key, value):
        key = self.SETTINGS_SECTION + key
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue(key, QVariant(value))
        else:
            QSettings().setValue(key, value)

    def initGui(self):
        # Create action that will start plugin configuration
        self.run_action = QAction(QIcon(":/plugins/pdokservicesplugin/icon.png"), \
            u"Pdok Services Plugin", self.iface.mainWindow())

        self.servicesLoaded = False
        # connect the action to the run method
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if "True" == self.docked or "true" == self.docked or  True == self.docked:
        #     self.run_action.triggered.connect(self.showAndRaise)
        #     self.dlg.radioDocked.setChecked(True)
        #     # docked the dialog is immidiately visible, so should run NOW
        # else:
        #     self.run_action.triggered.connect(self.run)
        #     self.dlg.radioDocked.setChecked(False)
        #     self.setupfq()
        self.run_action.triggered.connect(self.run)
        #self.dlg.radioDocked.setChecked(False)
        self.setupfq()

        # Add toolbar button and menu item
        #self.iface.addToolBarIcon(self.action)

        self.toolbar = self.iface.addToolBar("PDOK services plugin")
        self.toolbar.setObjectName("PDOK services plugin")
        self.toolbar.addAction(self.run_action)
        self.toolbarSearch = QLineEdit()
        self.toolbarSearch.setMaximumWidth(200)
        self.toolbarSearch.setAlignment(Qt.AlignLeft)
        self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek")
        self.toolbar.addWidget(self.toolbarSearch)
        self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar)
        # address/point cleanup
        self.clean_action = QAction(QIcon(":/plugins/pdokservicesplugin/eraser.png"), \
            u"Cleanup", self.eraseAddress())
        self.toolbar.addAction(self.clean_action)
        self.clean_action.triggered.connect(self.eraseAddress)

        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/help.png"), \
                            "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("Pdok Services Plugin About")
        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction)

        self.aboutAction.triggered.connect(self.about)
        self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService)

        self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress)

        self.dlg.geocoderSearch.textEdited.connect(self.searchAddress)
        self.dlg.geocoderSearch.setPlaceholderText("PDOK Locatieserver zoek, bv postcode of postcode huisnummer")

        self.dlg.geocoderResultSearch.textChanged.connect(self.filterGeocoderResult)
        self.dlg.geocoderResultSearch.setPlaceholderText("een of meer zoekwoorden uit resultaat")

        #self.dlg.radioDocked.toggled.connect(self.set_docked)

        self.dlg.btnCheckPdokJson.clicked.connect(self.checkPdokJson)
        #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged)

        ui = self.dlg.ui
        cbxs = [ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr, ui.cbx_pcl, ui.cbx_hmp]
        # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search
        for cbx in cbxs:
            cbx.stateChanged.connect(self.searchAddress)

        self.run(True)

    # for now hiding the pointer as soon as the extent changes
    #def extentsChanged(self):
    #    self.removePointer()

    def checkPdokJson(self):
        myversion = self.getSettingsValue('pdokversion', '1')
        msgtxt = ''
        msglvl = 0  # QgsMessageBar.INFO
        try:
            response = urllib.request.urlopen('http://www.qgis.nl/pdok.version')
            str_response = response.read().decode('utf-8')
            pdokversion = json.loads(str_response)
            if pdokversion > int(myversion):
                response = urllib.request.urlopen('http://www.qgis.nl/pdok.json')
                str_response = response.read().decode('utf-8')
                pdokjson = json.loads(str_response)
                with open(self.plugin_dir +'/pdok.json', 'w') as outfile:
                    json.dump(pdokjson, outfile)
                msgtxt = "De laatste versie is opgehaald en zal worden gebruikt " + \
                    str(pdokversion) + ' (was ' + myversion +')'
                self.servicesLoaded = False # reset reading of json
                self.run()
                self.setSettingsValue('pdokversion', pdokversion)
            else:
                msgtxt = "Geen nieuwere versie beschikbaar dan " + str(pdokversion)
        except Exception as e:
            #print e
            msgtxt = "Fout bij ophalen van service info. Netwerk probleem?"
            msglvl = 2 # QgsMessageBar.CRITICAL
        # msg
        if hasattr(self.iface, 'messageBar'):
            self.iface.messageBar().pushMessage("PDOK services update", msgtxt, level=msglvl, duration=10)
        else: # 1.8
            QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin", msgtxt)

    # def set_docked(self, foo):
    #     self.setSettingsValue('docked', self.dlg.radioDocked.isChecked())
    #     #if Qgis.QGIS_VERSION_INT < 10900:
    #     #    # qgis <= 1.8
    #     #    QSettings().setValue("/pdokservicesplugin/docked", QVariant(self.dlg.radioDocked.isChecked()))
    #     #else:
    #     #    QSettings().setValue("/pdokservicesplugin/docked", self.dlg.radioDocked.isChecked())

    def showAndRaise(self):
        self.dlg.show()
        self.dlg.raise_()
        # also remove the pointer
        self.removePointer()

    def about(self):
        infoString =  "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
        infoString += "Company - Zuidt - http://www.zuidt.nl\n"
        infoString += "Source: https://github.com/rduivenvoorde/pdokservicesplugin"
        QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin About", infoString)

    def unload(self):
        self.removePointer()
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(u"&Pdok Services Plugin",self.run_action)
        del self.toolbarSearch

    def showService(self, selectedIndexes):
        if len(selectedIndexes)==0:
            self.currentLayer = None
            self.dlg.ui.layerInfo.setHtml('')
            self.dlg.ui.comboSelectProj.clear()
            return
        # needed to scroll To the selected row incase of using the keyboard / arrows
        self.dlg.servicesView.scrollTo(self.dlg.servicesView.selectedIndexes()[0])
        # itemType holds the data (== column 1)
        self.currentLayer = self.dlg.servicesView.selectedIndexes()[1].data(Qt.UserRole)
        if isinstance(self.currentLayer, QVariant):
            self.currentLayer = self.currentLayer.toMap()
            # QGIS 1.8: QVariants
            currentLayer = {}
            for key in list(self.currentLayer.keys()):
                val = self.currentLayer[key]
                currentLayer[str(key)]=str(val.toString())
            self.currentLayer = currentLayer
        url = self.currentLayer['url']
        title = self.currentLayer['title']
        style = ''
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        servicetitle = self.currentLayer['servicetitle']
        layername = self.currentLayer['layers']
        abstract = self.currentLayer['abstract']
        stype = self.currentLayer['type'].upper()
        minscale =''
        if 'minscale' in self.currentLayer and self.currentLayer['minscale'] != None and self.currentLayer['minscale'] != '':
            minscale = "min. schaal 1:"+self.currentLayer['minscale']
        maxscale = ''
        if 'maxscale' in self.currentLayer and self.currentLayer['maxscale'] != None and self.currentLayer['maxscale'] != '':
            maxscale = "max. schaal 1:"+self.currentLayer['maxscale']
        self.dlg.ui.layerInfo.setText('')
        self.dlg.ui.btnLoadLayer.setEnabled(True)
        self.dlg.ui.layerInfo.setHtml('<h4>%s</h4><h3>%s</h3><lu><li>%s</li><li>&nbsp;</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li></lu>' % (servicetitle, title, abstract, stype, url, layername, style, minscale, maxscale))
        self.dlg.ui.comboSelectProj.clear()
        if stype=="WMS":
            try:
                crs = self.currentLayer['crs']
            except KeyError:
                crs = 'EPSG:28992'
            crs = crs.split(',')
            self.dlg.ui.comboSelectProj.addItems(crs)
            for i in range(len(crs)):
                if crs[i] == 'EPSG:28992':
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)
        if stype=="WMTS":
            tilematrixsets = self.currentLayer['tilematrixsets'].split(',')
            self.dlg.ui.comboSelectProj.addItems(tilematrixsets)
            for i in range(len(tilematrixsets)):
                if tilematrixsets[i].startswith('EPSG:28992'):
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)

    def loadService(self):
        if self.currentLayer == None:
            return
        servicetype = self.currentLayer['type']
        url = self.currentLayer['url']
        # some services have an url with query parameters in it, we have to urlencode those:
        location,query = urllib.parse.splitquery(url)
        url = location
        if query != None and query != '':
            url +=('?'+urllib.parse.quote_plus(query))
        title = self.currentLayer['title']
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        else:
            style = '' # == default for this service
        layers = self.currentLayer['layers']
        # mmm, tricky: we take the first one while we can actually want png/gif or jpeg
        if servicetype == "wms":
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                crs = 'EPSG:28992'
            else:
                crs = self.dlg.ui.comboSelectProj.currentText()
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                uri = url
                self.iface.addRasterLayer(
                    uri, # service uri
                    title, # name for layer (as seen in QGIS)
                    "wms", # dataprovider key
                    [layers], # array of layername(s) for provider (id's)
                    [""], # array of stylename(s)  NOTE: ignoring styles here!!!
                    imgformat, # image format searchstring
                    crs) # crs code searchstring
            else:
                # qgis > 1.8
                uri = "crs="+crs+"&layers="+layers+"&styles="+style+"&format="+imgformat+"&url="+url;
                self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wmts":
            if Qgis.QGIS_VERSION_INT < 10900:
                QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen in deze versie van QGIS.\nMisschien kunt u QGIS 2.0 installeren (die kan het WEL)?\nOf is de laag niet ook beschikbaar als wms of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
                return
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                tilematrixset = 'EPSG:28992'
            else:
                tilematrixset = self.dlg.ui.comboSelectProj.currentText()
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            # special case for luchtfoto
            #if layers=="luchtfoto":
            #    # tileMatrixSet=nltilingschema&crs=EPSG:28992&layers=luchtfoto&styles=&format=image/jpeg&url=http://geodata1.nationaalgeoregister.nl/luchtfoto/wmts/1.0.0/WMTSCapabilities.xml
            #    # {u'layers': u'luchtfoto', u'imgformats': u'image/jpeg', u'title': u'PDOK-achtergrond luchtfoto', u'url': u'http://geodata1.nationaalgeoregister.nl/luchtfoto/wms', u'abstract': u'', u'tilematrixsets': u'nltilingschema', u'type': u'wmts'}
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url
            #else:
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url;
            #uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            if tilematrixset.startswith('EPSG:'):
                crs=tilematrixset
                i = crs.find(':', 5)
                if i > -1:
                    crs=crs[:i]
            elif tilematrixset.startswith('OGC:1.0'):
                crs='EPSG:3857'
            uri = "tileMatrixSet="+tilematrixset+"&crs="+crs+"&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            #print "############ PDOK URI #################"
            #print uri
            self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wfs":
            location, query = urllib.parse.splitquery(url)
            #uri = location+"?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME="+layers+"&SRSNAME=EPSG:28992"
            #uri = location + "?SERVICE=WFS&REQUEST=GetFeature&TYPENAME=" + layers + "&SRSNAME=EPSG:28992"
            # adding a bbox paramater forces QGIS to NOT cache features but retrieve new features all the time
            # QGIS will update the BBOX to the right value
            #uri += "&BBOX=-10000,310000,290000,650000"
            uri = " pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:28992' typename='"+layers+"' url='"+url+"' version='2.0.0' "
            self.iface.addVectorLayer(uri, title, "WFS")
        elif servicetype == "wcs":
            # cache=AlwaysCache&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            uri = ''
            # cache=AlwaysCache
            # cache=PreferNetwork 
            # cache=AlwaysNetwork
            # cache=AlwaysNetwork&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.1&identifier="+layers+"&url="+url
            # working for ahn1 ahn2 and ahn3: GEOTIFF_FLOAT32
            format = 'GEOTIFF_FLOAT32'
            # working for ahn25m is only image/tiff
            if layers=='ahn25m':
                format = 'image/tiff'
            # we handcrated some wcs layers with 2 different image formats: tiff (RGB) and tiff (float32):
            if 'imgformats' in self.currentLayer:
                format = self.currentLayer['imgformats'].split(',')[0]
            uri = "cache=AlwaysNetwork&crs=EPSG:28992&format="+format+"&version=1.1.2&identifier=" + layers + "&url=" + url

            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.2&identifier=" + layers + "&url=" + url
            self.iface.addRasterLayer(uri, title, "wcs")
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen door de plugin of door QGIS.\nIs het niet beschikbaar als wms, wmts of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
            return

    def filterGeocoderResult(self, string):
        #print "filtering geocoder results: %s" % string
        self.dlg.geocoderResultView.selectRow(0)
        self.geocoderProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.geocoderProxyModel.setFilterFixedString(string)

    def searchAddressFromToolbar(self):
        self.removePointer()
        self.geocoderSourceModel.clear()
        self.geocode()

    def searchAddress(self):
        self.removePointer()
        #print "search geocoder for: %s" % self.dlg.geocoderSearch.text()
        self.geocoderSourceModel.clear()
        #self.geocode(self.dlg.geocoderSearch.text())
        self.suggest()


    def eraseAddress(self):
        """
        clean the input and remove the pointer
        """
        self.removePointer()
        if self.geocoderSourceModel is not None:
            self.geocoderSourceModel.clear()
        if self.dlg.geocoderSearch is not None:
            self.dlg.geocoderSearch.clear()
        if self.toolbarSearch is not None:
            self.toolbarSearch.clear()

    def filterLayers(self, string):
        # remove selection if one row is selected
        self.dlg.servicesView.selectRow(0)
        #self.currentLayer = None
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxyModel.setFilterFixedString(string)

    #def addSourceRow(self, service, layer):
    def addSourceRow(self, serviceLayer):
        # you can attache different "data's" to to an QStandarditem
        # default one is the visible one:
        itemType = QStandardItem("%s" % (serviceLayer["type"].upper()) )
        # userrole is a free form one:
        # only attach the data to the first item
        # service layer = a dict/object with all props of the layer
        itemType.setData( serviceLayer, Qt.UserRole )
        itemType.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        # only wms services have styles (sometimes)
        layername = serviceLayer["title"]
        if 'style' in serviceLayer:
            itemLayername = QStandardItem("%s [%s]" % (serviceLayer["title"], serviceLayer["style"]) )
            layername = "%s [%s]" % (serviceLayer["title"], serviceLayer["style"])
        else:
            itemLayername = QStandardItem("%s" % (serviceLayer["title"]))
        itemLayername.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["servicetitle"] ))
        # itemFilter is the item used to search filter in. That is why layername is a combi of layername + filter here
        itemFilter = QStandardItem("%s %s %s %s" % (serviceLayer["type"], layername, serviceLayer["servicetitle"], serviceLayer["abstract"]) )
        itemServicetitle = QStandardItem("%s" % (serviceLayer["servicetitle"]))
        itemServicetitle.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        self.sourceModel.appendRow( [ itemLayername, itemType, itemServicetitle, itemFilter ] )

    # run method that performs all the real work
    def run(self, hiddenDialog=False):

        # enable possible remote pycharm debugging
        #import pydevd
        #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)

        # last viewed/selected tab
        if QSettings().contains("/pdokservicesplugin/currenttab"):
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                self.dlg.tabs.widget(QSettings().value("/pdokservicesplugin/currenttab").toInt()[0])
            else:
                self.dlg.tabs.widget(int(QSettings().value("/pdokservicesplugin/currenttab")))

        if self.servicesLoaded == False:
            pdokjson = os.path.join(os.path.dirname(__file__), ".", "pdok.json")
            f = open(pdokjson, 'r', encoding='utf-8')
            self.pdok = json.load(f)
            f.close()

            self.proxyModel = QSortFilterProxyModel()
            self.sourceModel = QStandardItemModel()
            self.proxyModel.setSourceModel(self.sourceModel)
            # filter == search on itemFilter column:
            self.proxyModel.setFilterKeyColumn(3)
            self.dlg.servicesView.setModel(self.proxyModel)
            self.dlg.servicesView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            self.geocoderProxyModel = QSortFilterProxyModel()
            self.geocoderSourceModel = QStandardItemModel()

            self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel)
            self.geocoderProxyModel.setFilterKeyColumn(0)
            self.dlg.geocoderResultView.setModel(self.geocoderProxyModel)
            self.dlg.geocoderResultView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            #{"services":[
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"},
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}
            # ]}
            # 
            for service in self.pdok["services"]:
                # service[layer] was an array
                if isinstance(service["layers"], str) or isinstance(service["layers"], str):
                    self.addSourceRow(service)

            self.dlg.layerSearch.textChanged.connect(self.filterLayers)
            self.dlg.layerSearch.setPlaceholderText("woord uit laagnaam, type of service ")
            self.dlg.servicesView.selectionModel().selectionChanged.connect(self.showService)
            self.dlg.servicesView.doubleClicked.connect(self.loadService)
            # actually I want to load a service when doubleclicked on header
            # but as I cannot get this to work, let's disable clicking it then
            self.dlg.servicesView.verticalHeader().setSectionsClickable(False)
            self.dlg.servicesView.horizontalHeader().setSectionsClickable(False)

            #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress)
            self.dlg.geocoderResultView.selectionModel().selectionChanged.connect(self.zoomToAddress)

            # hide itemFilter column:
            self.dlg.servicesView.hideColumn(3)
            self.servicesLoaded = True;

        self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service")
        self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]")
        self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        #self.dlg.servicesView.verticalHeader().hide()
        #self.dlg.servicesView.resizeColumnsToContents()
        self.dlg.servicesView.setColumnWidth(0, 300)  # set name to 300px (there are some huge layernames)
        self.dlg.servicesView.horizontalHeader().setStretchLastSection(True)
        # show the dialog ?
        if not hiddenDialog:
            self.dlg.show()
        # Run the dialog event loop
        #result = self.dlg.exec_()
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue("/pdokservicesplugin/currenttab", QVariant(self.dlg.tabs.currentIndex()))
        else:
            QSettings().setValue("/pdokservicesplugin/currenttab", self.dlg.tabs.currentIndex())
        self.removePointer()

    def setupfq(self):
        """
        Setup the fq checkboxes in the gui, by looking into the settings for the
        'pdokservicesplugin/checkedfqs' key, which contains a list of type strings
        like ['weg','adres']
        """
        checked_fqs = self.getSettingsValue('checkedfqs', [])
        #self.info('setup fq: {}'.format(checked_fqs))
        if len(checked_fqs) > 0:  # else there is not saved state... take gui defaults
            self.dlg.ui.cbx_gem.setChecked('gemeente' in checked_fqs)
            self.dlg.ui.cbx_wpl.setChecked('woonplaats' in checked_fqs)
            self.dlg.ui.cbx_weg.setChecked('weg' in checked_fqs)
            self.dlg.ui.cbx_pcd.setChecked('postcode' in checked_fqs)
            self.dlg.ui.cbx_adr.setChecked('adres' in checked_fqs)
            self.dlg.ui.cbx_pcl.setChecked('perceel' in checked_fqs)
            self.dlg.ui.cbx_hmp.setChecked('hectometerpaal' in checked_fqs)

    def createfq(self):
        """
        This creates a fq-string (Filter Query, see https://github.com/PDOK/locatieserver/wiki/Zoekvoorbeelden-Locatieserver)
        Based on the checkboxes in the dialog.
        Defaults to ''
        Example: 'fq=+type:adres+type:gemeente'  (only gemeente AND addresses)
        :return:
        """
        fqlist = []
        if self.dlg.ui.cbx_gem.isChecked():
            fqlist.append('gemeente')
        if self.dlg.ui.cbx_wpl.isChecked():
            fqlist.append('woonplaats')
        if self.dlg.ui.cbx_weg.isChecked():
            fqlist.append('weg')
        if self.dlg.ui.cbx_pcd.isChecked():
            fqlist.append('postcode')
        if self.dlg.ui.cbx_adr.isChecked():
            fqlist.append('adres')
        if self.dlg.ui.cbx_pcl.isChecked():
            fqlist.append('perceel')
        if self.dlg.ui.cbx_hmp.isChecked():
            fqlist.append('hectometerpaal')
        self.setSettingsValue('checkedfqs', fqlist)
        #self.info(self.getSettingsValue('checkedfqs', ['leeg?']))
        fq = ''
        if len(fqlist) > 0:
            fq = '&fq=+type:' + '+type:'.join(fqlist)
        return fq

    def suggest(self):
        self.dlg.ui.lookupinfo.setHtml('')
        search_text = self.dlg.geocoderSearch.text()
        if len(search_text) <= 1:
            # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
            #     "meer input aub: {}".format(search_text)
            #     ), QMessageBox.Ok, QMessageBox.Ok)
            return
        # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
        #     "zoeken: {}".format(search_text)
        # ), QMessageBox.Ok, QMessageBox.Ok)
        results = self.pdokgeocoder.suggest(search_text, self.createfq())
        if len(results) == 0:
            # ignore, as we are suggesting, maybe more characters will reveal something...
            return
        for result in results:
            #print address
            adrestekst = QStandardItem("%s" % (result["adrestekst"]))
            adrestekst.setData(result, Qt.UserRole)
            type = QStandardItem("%s" % (result["type"]))
            id = QStandardItem("%s" % (result["id"]))
            score = QStandardItem("%s" % (result["score"]))
            adrestekst.setData(result, Qt.UserRole)
            self.geocoderSourceModel.appendRow([adrestekst, type])
        self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
        self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        self.dlg.geocoderResultView.resizeColumnsToContents()
        self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def geocode(self):
        self.dlg.geocoderSearch.setText(self.toolbarSearch.text())
        self.suggest()
        if self.dlg.geocoderResultView.model().rowCount()>0:
            self.dlg.geocoderResultView.selectRow(0)
            self.zoomToAddress()
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
                "Niets gevonden.\nProbeer een andere spelling, of alleen postcode/huisnummer?\n\nSelecteer meer (Locatieserver) 'typen' in de PdokServicesPlugin dialoog.\n\nOf gebruik de 'PDOK geocoder'-tab in de PdokServicesPlugin dialoog."
                ), QMessageBox.Ok, QMessageBox.Ok)

    # def geocode(self):
    #     self.dlg.ui.lookupinfo.setHtml('')
    #     search_text = self.toolbarSearch.text()
    #     addresses = self.pdokgeocoder.search(search_text)
    #     if len(addresses) == 0:
    #         QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
    #             "Niets gevonden. Probeer een andere spelling of alleen postcode/huisnummer."
    #             ), QMessageBox.Ok, QMessageBox.Ok)
    #         return
    #     for address in addresses:
    #         #print address
    #         adrestekst = QStandardItem("%s" % (address["adrestekst"]))
    #         adrestekst.setData(address, Qt.UserRole)
    #         straat = QStandardItem("%s" % (address["straat"]))
    #         nummer = QStandardItem("%s" % (address["nummer"]))
    #         postcode = QStandardItem("%s" % (address["postcode"]))
    #         plaats = QStandardItem("%s" % (address["plaats"]))
    #         gemeente = QStandardItem("%s" % (address["gemeente"]))
    #         provincie = QStandardItem("%s" % (address["provincie"]))
    #         self.geocoderSourceModel.appendRow([adrestekst, straat, nummer, postcode, plaats, gemeente, provincie])
    #
    #     self.dlg.geocoderResultView.selectRow(0)
    #     self.zoomToAddress()
    #
    #     self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
    #     self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Straat")
    #     self.geocoderSourceModel.setHeaderData(2, Qt.Horizontal, "Nr")
    #     self.geocoderSourceModel.setHeaderData(3, Qt.Horizontal, "Postcode")
    #     self.geocoderSourceModel.setHeaderData(4, Qt.Horizontal, "Plaats")
    #     self.geocoderSourceModel.setHeaderData(5, Qt.Horizontal, "Gemeente")
    #     self.geocoderSourceModel.setHeaderData(6, Qt.Horizontal, "Provincie")
    #
    #     self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(3).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(4).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(5).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(6).setTextAlignment(Qt.AlignLeft)
    #
    #     self.dlg.geocoderResultView.resizeColumnsToContents()
    #     self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def zoomToAddress(self):
        # get x,y from data of record
        self.removePointer()

        data = self.dlg.geocoderResultView.selectedIndexes()[0].data(Qt.UserRole)

        if 'centroide_rd' in data: # free OR lookup service
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
        else:
            # no centroid yet, probably only object id, retrieve it via lookup service
            id = data['id']
            data = self.pdokgeocoder.lookup(id)
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
            lookup_data= data['data']
            lis = ''
            for key in lookup_data.keys():
                lis = lis + '<li>{}: {}</li>'.format(key, lookup_data[key])
            self.dlg.ui.lookupinfo.setHtml(
                '<h4>{}</h4><lu>{}</lu>'.format(adrestekst, lis))

        # just always transform from 28992 to mapcanvas crs
        crs = self.iface.mapCanvas().mapSettings().destinationCrs()
        crs28992 = QgsCoordinateReferenceSystem()
        crs28992.createFromId(28992)
        crsTransform = QgsCoordinateTransform(crs28992, crs, QgsProject.instance())
        z = 1587
        if adrestekst.lower().startswith('adres'):
            z = 794
        elif adrestekst.lower().startswith('perceel'):
            z = 794
        elif adrestekst.lower().startswith('hectometer'):
            z = 1587
        elif adrestekst.lower().startswith('straat'):
            z = 3175
        elif adrestekst.lower().startswith('postcode'):
            z = 6350
        elif adrestekst.lower().startswith('woonplaats'):
            z = 25398
        elif adrestekst.lower().startswith('gemeente'):
            z = 50797
        elif adrestekst.lower().startswith('provincie'):
            z = 812750
        geom.transform(crsTransform)
        center = geom.asPoint()
        self.setPointer(center)
        # zoom to with center is actually setting a point rectangle and then zoom
        rect = QgsRectangle(center, center)
        self.iface.mapCanvas().setExtent(rect)
        self.iface.mapCanvas().zoomScale(z)
        self.iface.mapCanvas().refresh()

    def setPointer(self, point):
        self.removePointer()
        self.pointer = QgsVertexMarker(self.iface.mapCanvas())
        self.pointer.setColor(QColor(255, 255, 0))
        self.pointer.setIconSize(10)
        self.pointer.setPenWidth(5)
        self.pointer.setCenter(point)

    def removePointer(self):
        if self.pointer is not None:
            self.iface.mapCanvas().scene().removeItem(self.pointer)

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin', Qgis.Info)
Example #22
0
class Plugin():
    """The QGIS interface implementation for the InaSAFE plugin.

    This class acts as the 'glue' between QGIS and our custom logic.
    It creates a toolbar and menu bar entry and launches the InaSAFE user
    interface if these are activated.
    """
    def __init__(self, iface):
        """Class constructor.

        On instantiation, the plugin instance will be assigned a copy
        of the QGIS iface object which will allow this plugin to access and
        manipulate the running QGIS instance that spawned it.

        :param iface:Quantum GIS iface instance. This instance is
            automatically passed to the plugin by QGIS when it loads the
            plugin.
        :type iface: QgisAppInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        self.dock_widget = None

        # Actions
        self.action_add_layers = None
        self.action_add_osm_layer = None
        self.action_add_petabencana_layer = None
        self.action_batch_runner = None
        self.action_dock = None
        self.action_extent_selector = None
        self.action_field_mapping = None
        self.action_multi_exposure = None
        self.action_function_centric_wizard = None
        self.action_import_dialog = None
        self.action_keywords_wizard = None
        self.action_minimum_needs = None
        self.action_minimum_needs_config = None
        self.action_multi_buffer = None
        self.action_options = None
        self.action_run_tests = None
        self.action_save_scenario = None
        self.action_shake_converter = None
        self.action_show_definitions = None
        self.action_toggle_rubberbands = None
        self.action_metadata_converter = None

        self.translator = None
        self.toolbar = None
        self.wizard = None
        self.actions = []  # list of all QActions we create for InaSAFE

        self.message_bar_item = None
        # Flag indicating if toolbar should show only common icons or not
        self.full_toolbar = False
        # print self.tr('InaSAFE')
        # For enable/disable the keyword editor icon
        self.iface.currentLayerChanged.connect(self.layer_changed)

        developer_mode = setting('developer_mode', False, expected_type=bool)
        self.hide_developer_buttons = (inasafe_release_status == 'final'
                                       and not developer_mode)

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

    def add_action(self, action, add_to_toolbar=True, add_to_legend=False):
        """Add a toolbar icon to the InaSAFE toolbar.

        :param action: The action that should be added to the toolbar.
        :type action: QAction

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

        :param add_to_legend: Flag indicating whether the action should also
            be added to the layer legend menu. Default to False.
        :type add_to_legend: bool
        """
        # store in the class list of actions for easy plugin unloading
        self.actions.append(action)
        self.iface.addPluginToMenu(self.tr('InaSAFE'), action)
        if add_to_toolbar:
            self.toolbar.addAction(action)
        if add_to_legend:
            # The id is the action name without spaces, tabs ...
            self.iface.addCustomActionForLayerType(action, self.tr('InaSAFE'),
                                                   QgsMapLayer.VectorLayer,
                                                   True)
            self.iface.addCustomActionForLayerType(action, self.tr('InaSAFE'),
                                                   QgsMapLayer.RasterLayer,
                                                   True)

    def _create_dock_toggle_action(self):
        """Create action for plugin dockable window (show/hide)."""
        # pylint: disable=W0201
        icon = resources_path('img', 'icons', 'icon.svg')
        self.action_dock = QAction(QIcon(icon), self.tr('Toggle InaSAFE Dock'),
                                   self.iface.mainWindow())
        self.action_dock.setObjectName('InaSAFEDockToggle')
        self.action_dock.setStatusTip(self.tr('Show/hide InaSAFE dock widget'))
        self.action_dock.setWhatsThis(self.tr('Show/hide InaSAFE dock widget'))
        self.action_dock.setCheckable(True)
        self.action_dock.setChecked(True)
        self.action_dock.triggered.connect(self.toggle_dock_visibility)
        self.add_action(self.action_dock)

        # --------------------------------------
        # Create action for keywords creation wizard
        # -------------------------------------

    def _create_keywords_wizard_action(self):
        """Create action for keywords creation wizard."""
        icon = resources_path('img', 'icons', 'show-keyword-wizard.svg')
        self.action_keywords_wizard = QAction(
            QIcon(icon), self.tr('Keywords Creation Wizard'),
            self.iface.mainWindow())
        self.action_keywords_wizard.setStatusTip(
            self.tr('Open InaSAFE keywords creation wizard'))
        self.action_keywords_wizard.setWhatsThis(
            self.tr('Open InaSAFE keywords creation wizard'))
        self.action_keywords_wizard.setEnabled(False)
        self.action_keywords_wizard.triggered.connect(
            self.show_keywords_wizard)
        self.add_action(self.action_keywords_wizard, add_to_legend=True)

    def _create_analysis_wizard_action(self):
        """Create action for IF-centric wizard."""
        icon = resources_path('img', 'icons', 'show-wizard.svg')
        self.action_function_centric_wizard = QAction(
            QIcon(icon), self.tr('Impact Function Centric Wizard'),
            self.iface.mainWindow())
        self.action_function_centric_wizard.setStatusTip(
            self.tr('Open InaSAFE impact function centric wizard'))
        self.action_function_centric_wizard.setWhatsThis(
            self.tr('Open InaSAFE impact function centric wizard'))
        self.action_function_centric_wizard.setEnabled(True)
        self.action_function_centric_wizard.triggered.connect(
            self.show_function_centric_wizard)
        self.add_action(self.action_function_centric_wizard)

    def _create_options_dialog_action(self):
        """Create action for options dialog."""
        icon = resources_path('img', 'icons', 'configure-inasafe.svg')
        self.action_options = QAction(QIcon(icon), self.tr('Options'),
                                      self.iface.mainWindow())
        self.action_options.setStatusTip(
            self.tr('Open InaSAFE options dialog'))
        self.action_options.setWhatsThis(
            self.tr('Open InaSAFE options dialog'))
        self.action_options.triggered.connect(self.show_options)
        self.add_action(self.action_options, add_to_toolbar=self.full_toolbar)

    def _create_minimum_needs_action(self):
        """Create action for minimum needs dialog."""
        icon = resources_path('img', 'icons', 'show-minimum-needs.svg')
        self.action_minimum_needs = QAction(
            QIcon(icon), self.tr('Minimum Needs Calculator'),
            self.iface.mainWindow())
        self.action_minimum_needs.setStatusTip(
            self.tr('Open InaSAFE minimum needs calculator'))
        self.action_minimum_needs.setWhatsThis(
            self.tr('Open InaSAFE minimum needs calculator'))
        self.action_minimum_needs.triggered.connect(self.show_minimum_needs)
        self.add_action(self.action_minimum_needs,
                        add_to_toolbar=self.full_toolbar)

    def _create_multi_buffer_action(self):
        """Create action for multi buffer dialog."""
        icon = resources_path('img', 'icons', 'show-multi-buffer.svg')
        self.action_multi_buffer = QAction(QIcon(icon),
                                           self.tr('Multi Buffer'),
                                           self.iface.mainWindow())
        self.action_multi_buffer.setStatusTip(
            self.tr('Open InaSAFE multi buffer'))
        self.action_multi_buffer.setWhatsThis(
            self.tr('Open InaSAFE multi buffer'))
        self.action_multi_buffer.triggered.connect(self.show_multi_buffer)
        self.add_action(self.action_multi_buffer,
                        add_to_toolbar=self.full_toolbar)

    def _create_minimum_needs_options_action(self):
        """Create action for global minimum needs dialog."""
        icon = resources_path('img', 'icons', 'show-global-minimum-needs.svg')
        self.action_minimum_needs_config = QAction(
            QIcon(icon), self.tr('Minimum Needs Configuration'),
            self.iface.mainWindow())
        self.action_minimum_needs_config.setStatusTip(
            self.tr('Open InaSAFE minimum needs configuration'))
        self.action_minimum_needs_config.setWhatsThis(
            self.tr('Open InaSAFE minimum needs configuration'))
        self.action_minimum_needs_config.triggered.connect(
            self.show_minimum_needs_configuration)
        self.add_action(self.action_minimum_needs_config,
                        add_to_toolbar=self.full_toolbar)

    def _create_shakemap_converter_action(self):
        """Create action for converter dialog."""
        icon = resources_path('img', 'icons', 'show-converter-tool.svg')
        self.action_shake_converter = QAction(QIcon(icon),
                                              self.tr('Shakemap Converter'),
                                              self.iface.mainWindow())
        self.action_shake_converter.setStatusTip(
            self.tr('Open InaSAFE Converter'))
        self.action_shake_converter.setWhatsThis(
            self.tr('Open InaSAFE Converter'))
        self.action_shake_converter.triggered.connect(
            self.show_shakemap_importer)
        self.add_action(self.action_shake_converter,
                        add_to_toolbar=self.full_toolbar)

    def _create_batch_runner_action(self):
        """Create action for batch runner dialog."""
        icon = resources_path('img', 'icons', 'show-batch-runner.svg')
        self.action_batch_runner = QAction(QIcon(icon),
                                           self.tr('Batch Runner'),
                                           self.iface.mainWindow())
        self.action_batch_runner.setStatusTip(self.tr('Open Batch Runner'))
        self.action_batch_runner.setWhatsThis(self.tr('Open Batch Runner'))
        self.action_batch_runner.triggered.connect(self.show_batch_runner)
        self.add_action(self.action_batch_runner,
                        add_to_toolbar=self.full_toolbar)

    def _create_save_scenario_action(self):
        """Create action for save scenario dialog."""
        icon = resources_path('img', 'icons', 'save-as-scenario.svg')
        self.action_save_scenario = QAction(QIcon(icon),
                                            self.tr('Save Current Scenario'),
                                            self.iface.mainWindow())
        message = self.tr('Save current scenario to text file')
        self.action_save_scenario.setStatusTip(message)
        self.action_save_scenario.setWhatsThis(message)
        # noinspection PyUnresolvedReferences
        self.action_save_scenario.triggered.connect(self.save_scenario)
        self.add_action(self.action_save_scenario,
                        add_to_toolbar=self.full_toolbar)

    def _create_osm_downloader_action(self):
        """Create action for import OSM Dialog."""
        icon = resources_path('img', 'icons', 'show-osm-download.svg')
        self.action_import_dialog = QAction(
            QIcon(icon), self.tr('OpenStreetMap Downloader'),
            self.iface.mainWindow())
        self.action_import_dialog.setStatusTip(
            self.tr('OpenStreetMap Downloader'))
        self.action_import_dialog.setWhatsThis(
            self.tr('OpenStreetMap Downloader'))
        self.action_import_dialog.triggered.connect(self.show_osm_downloader)
        self.add_action(self.action_import_dialog, add_to_toolbar=True)

    def _create_geonode_uploader_action(self):
        """Create action for Geonode uploader dialog."""
        icon = resources_path('img', 'icons', 'geonode.png')
        label = tr('Geonode Uploader')
        self.action_geonode = QAction(QIcon(icon), label,
                                      self.iface.mainWindow())
        self.action_geonode.setStatusTip(label)
        self.action_geonode.setWhatsThis(label)
        self.action_geonode.triggered.connect(self.show_geonode_uploader)
        self.add_action(self.action_geonode, add_to_toolbar=False)

    def _create_add_osm_layer_action(self):
        """Create action for import OSM Dialog."""
        icon = resources_path('img', 'icons', 'add-osm-tiles-layer.svg')
        self.action_add_osm_layer = QAction(
            QIcon(icon), self.tr('Add OpenStreetMap Tile Layer'),
            self.iface.mainWindow())
        self.action_add_osm_layer.setStatusTip(
            self.tr('Add OpenStreetMap Tile Layer'))
        self.action_add_osm_layer.setWhatsThis(
            self.tr('Use this to add an OSM layer to your map. '
                    'It needs internet access to function.'))
        self.action_add_osm_layer.triggered.connect(self.add_osm_layer)
        self.add_action(self.action_add_osm_layer, add_to_toolbar=True)

    def _create_show_definitions_action(self):
        """Create action for showing definitions / help."""
        icon = resources_path('img', 'icons', 'show-inasafe-help.svg')
        self.action_show_definitions = QAction(QIcon(icon),
                                               self.tr('InaSAFE Help'),
                                               self.iface.mainWindow())
        self.action_show_definitions.setStatusTip(self.tr('Show InaSAFE Help'))
        self.action_show_definitions.setWhatsThis(
            self.
            tr('Use this to show a document describing all InaSAFE concepts.'))
        self.action_show_definitions.triggered.connect(self.show_definitions)
        self.add_action(self.action_show_definitions, add_to_toolbar=True)

    def _create_metadata_converter_action(self):
        """Create action for showing metadata converter dialog."""
        icon = resources_path('img', 'icons', 'show-metadata-converter.svg')
        self.action_metadata_converter = QAction(
            QIcon(icon), self.tr('InaSAFE Metadata Converter'),
            self.iface.mainWindow())
        self.action_metadata_converter.setStatusTip(
            self.tr('Convert metadata from version 4.3 to version 3.5.'))
        self.action_metadata_converter.setWhatsThis(
            self.tr('Use this tool to convert metadata 4.3 to version 3.5'))
        self.action_metadata_converter.triggered.connect(
            self.show_metadata_converter)
        self.add_action(self.action_metadata_converter,
                        add_to_toolbar=self.full_toolbar)

    def _create_field_mapping_action(self):
        """Create action for showing field mapping dialog."""
        icon = resources_path('img', 'icons', 'show-mapping-tool.svg')
        self.action_field_mapping = QAction(
            QIcon(icon), self.tr('InaSAFE Field Mapping Tool'),
            self.iface.mainWindow())
        self.action_field_mapping.setStatusTip(
            self.tr('Assign field mapping to layer.'))
        self.action_field_mapping.setWhatsThis(
            self.tr('Use this tool to assign field mapping in layer.'))
        self.action_field_mapping.setEnabled(False)
        self.action_field_mapping.triggered.connect(self.show_field_mapping)
        self.add_action(self.action_field_mapping,
                        add_to_toolbar=self.full_toolbar)

    def _create_multi_exposure_action(self):
        """Create action for showing the multi exposure tool."""
        self.action_multi_exposure = QAction(
            QIcon(resources_path('img', 'icons', 'show-multi-exposure.svg')),
            self.tr('InaSAFE Multi Exposure Tool'), self.iface.mainWindow())
        self.action_multi_exposure.setStatusTip(
            self.tr('Open the multi exposure tool.'))
        self.action_multi_exposure.setWhatsThis(
            self.tr('Open the multi exposure tool.'))
        self.action_multi_exposure.setEnabled(True)
        self.action_multi_exposure.triggered.connect(self.show_multi_exposure)
        self.add_action(self.action_multi_exposure,
                        add_to_toolbar=self.full_toolbar)

    def _create_add_petabencana_layer_action(self):
        """Create action for import OSM Dialog."""
        icon = resources_path('img', 'icons', 'add-petabencana-layer.svg')
        self.action_add_petabencana_layer = QAction(
            QIcon(icon), self.tr('Add PetaBencana Flood Layer'),
            self.iface.mainWindow())
        self.action_add_petabencana_layer.setStatusTip(
            self.tr('Add PetaBencana Flood Layer'))
        self.action_add_petabencana_layer.setWhatsThis(
            self.tr('Use this to add a PetaBencana layer to your map. '
                    'It needs internet access to function.'))
        self.action_add_petabencana_layer.triggered.connect(
            self.add_petabencana_layer)
        self.add_action(self.action_add_petabencana_layer,
                        add_to_toolbar=self.full_toolbar)

    def _create_rubber_bands_action(self):
        """Create action for toggling rubber bands."""
        icon = resources_path('img', 'icons', 'toggle-rubber-bands.svg')
        self.action_toggle_rubberbands = QAction(
            QIcon(icon), self.tr('Toggle Scenario Outlines'),
            self.iface.mainWindow())
        message = self.tr('Toggle rubber bands showing scenario extents.')
        self.action_toggle_rubberbands.setStatusTip(message)
        self.action_toggle_rubberbands.setWhatsThis(message)
        # Set initial state
        self.action_toggle_rubberbands.setCheckable(True)
        flag = setting('showRubberBands', False, expected_type=bool)
        self.action_toggle_rubberbands.setChecked(flag)
        # noinspection PyUnresolvedReferences
        self.action_toggle_rubberbands.triggered.connect(
            self.dock_widget.toggle_rubber_bands)
        self.add_action(self.action_toggle_rubberbands)

    def _create_analysis_extent_action(self):
        """Create action for analysis extent dialog."""
        icon = resources_path('img', 'icons', 'set-extents-tool.svg')
        self.action_extent_selector = QAction(QIcon(icon),
                                              self.tr('Set Analysis Area'),
                                              self.iface.mainWindow())
        self.action_extent_selector.setStatusTip(
            self.tr('Set the analysis area for InaSAFE'))
        self.action_extent_selector.setWhatsThis(
            self.tr('Set the analysis area for InaSAFE'))
        self.action_extent_selector.triggered.connect(
            self.show_extent_selector)
        self.add_action(self.action_extent_selector)

    def _create_test_layers_action(self):
        """Create action for adding layers (developer mode, non final only)."""
        if self.hide_developer_buttons:
            return

        icon = resources_path('img', 'icons', 'add-test-layers.svg')
        self.action_add_layers = QAction(QIcon(icon),
                                         self.tr('Add Test Layers'),
                                         self.iface.mainWindow())
        self.action_add_layers.setStatusTip(self.tr('Add test layers'))
        self.action_add_layers.setWhatsThis(self.tr('Add test layers'))
        self.action_add_layers.triggered.connect(self.add_test_layers)

        self.add_action(self.action_add_layers)

    def _create_run_test_action(self):
        """Create action for running tests (developer mode, non final only)."""
        if self.hide_developer_buttons:
            return

        default_package = str(setting('testPackage', 'safe',
                                      expected_type=str))
        msg = self.tr('Run tests in %s' % default_package)

        self.test_button = QToolButton()
        self.test_button.setMenu(QMenu())
        self.test_button.setPopupMode(QToolButton.MenuButtonPopup)

        icon = resources_path('img', 'icons', 'run-tests.svg')
        self.action_run_tests = QAction(QIcon(icon), msg,
                                        self.iface.mainWindow())

        self.action_run_tests.setStatusTip(msg)
        self.action_run_tests.setWhatsThis(msg)
        self.action_run_tests.triggered.connect(self.run_tests)

        self.test_button.menu().addAction(self.action_run_tests)
        self.test_button.setDefaultAction(self.action_run_tests)

        self.action_select_package = QAction(QIcon(icon),
                                             self.tr('Select package'),
                                             self.iface.mainWindow())

        self.action_select_package.setStatusTip(self.tr('Select Test Package'))
        self.action_select_package.setWhatsThis(self.tr('Select Test Package'))
        self.action_select_package.triggered.connect(self.select_test_package)
        self.test_button.menu().addAction(self.action_select_package)
        self.toolbar.addWidget(self.test_button)

        self.add_action(self.action_run_tests, add_to_toolbar=False)
        self.add_action(self.action_select_package, add_to_toolbar=False)

    def _create_dock(self):
        """Create dockwidget and tabify it with the legend."""
        # Import dock here as it needs to be imported AFTER i18n is set up
        from safe.gui.widgets.dock import Dock
        self.dock_widget = Dock(self.iface)
        self.dock_widget.setObjectName('InaSAFE-Dock')
        self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget)
        legend_tab = self.iface.mainWindow().findChild(QApplication, 'Legend')
        if legend_tab:
            self.iface.mainWindow().tabifyDockWidget(legend_tab,
                                                     self.dock_widget)
            self.dock_widget.raise_()

    # noinspection PyPep8Naming
    def initGui(self):
        """Gui initialisation procedure (for QGIS plugin api).

        .. note:: Don't change the name of this method from initGui!

        This method is called by QGIS and should be used to set up
        any graphical user interface elements that should appear in QGIS by
        default (i.e. before the user performs any explicit action with the
        plugin).
        """
        self.toolbar = self.iface.addToolBar('InaSAFE')
        self.toolbar.setObjectName('InaSAFEToolBar')
        self.dock_widget = None
        # Now create the actual dock
        self._create_dock()
        # And all the menu actions
        # Configuration Group
        self._create_dock_toggle_action()
        self._create_options_dialog_action()
        self._create_minimum_needs_options_action()
        self._create_analysis_extent_action()
        self._create_rubber_bands_action()
        self._add_spacer_to_menu()
        self._create_keywords_wizard_action()
        self._create_analysis_wizard_action()
        self._add_spacer_to_menu()
        self._create_field_mapping_action()
        self._create_multi_exposure_action()
        self._create_metadata_converter_action()
        # TODO: temporarily disabled this until we have a fix
        # issue: https://github.com/inasafe/inasafe/issues/5109
        # self._create_osm_downloader_action()
        self._create_add_osm_layer_action()
        self._create_add_petabencana_layer_action()
        self._create_geonode_uploader_action()
        self._create_shakemap_converter_action()
        self._create_minimum_needs_action()
        self._create_multi_buffer_action()
        self._create_test_layers_action()
        self._create_run_test_action()
        self._add_spacer_to_menu()
        self._create_batch_runner_action()
        self._create_save_scenario_action()
        self._add_spacer_to_menu()
        self._create_show_definitions_action()

        # Hook up a slot for when the dock is hidden using its close button
        # or  view-panels
        #
        self.dock_widget.visibilityChanged.connect(self.toggle_inasafe_action)
        # Also deal with the fact that on start of QGIS dock may already be
        # hidden.
        self.action_dock.setChecked(self.dock_widget.isVisible())

        self.iface.initializationCompleted.connect(
            partial(self.show_welcome_message))

    def _add_spacer_to_menu(self):
        """Create a spacer to the menu to separate action groups."""
        separator = QAction(self.iface.mainWindow())
        separator.setSeparator(True)
        self.iface.addPluginToMenu(self.tr('InaSAFE'), separator)

    @staticmethod
    def clear_modules():
        """Unload inasafe functions and try to return QGIS to before InaSAFE.

        .. todo:: I think this function can be removed. TS.
        """
        # next lets force remove any inasafe related modules
        modules = []
        for module in sys.modules:
            if 'inasafe' in module:
                # Check if it is really one of our modules i.e. exists in the
                # plugin directory
                tokens = module.split('.')
                path = ''
                for myToken in tokens:
                    path += os.path.sep + myToken
                parent = os.path.abspath(
                    os.path.join(__file__, os.path.pardir, os.path.pardir))
                full_path = os.path.join(parent, path + '.py')
                if os.path.exists(os.path.abspath(full_path)):
                    LOGGER.debug('Removing: %s' % module)
                    modules.append(module)
        for module in modules:
            del (sys.modules[module])
        for module in sys.modules:
            if 'inasafe' in module:
                print(module)

        # Lets also clean up all the path additions that were made
        package_path = os.path.abspath(
            os.path.join(os.path.dirname(__file__), os.path.pardir))
        LOGGER.debug('Path to remove: %s' % package_path)
        # We use a list comprehension to ensure duplicate entries are removed
        LOGGER.debug(sys.path)
        sys.path = [y for y in sys.path if package_path not in y]
        LOGGER.debug(sys.path)

    def unload(self):
        """GUI breakdown procedure (for QGIS plugin api).

        .. note:: Don't change the name of this method from unload!

        This method is called by QGIS and should be used to *remove*
        any graphical user interface elements that should appear in QGIS.
        """
        # Remove the plugin menu item and icon
        if self.wizard:
            self.wizard.deleteLater()
        for myAction in self.actions:
            self.iface.removePluginMenu(self.tr('InaSAFE'), myAction)
            self.iface.removeToolBarIcon(myAction)
            self.iface.removeCustomActionForLayerType(myAction)
        self.iface.mainWindow().removeDockWidget(self.dock_widget)
        self.iface.mainWindow().removeToolBar(self.toolbar)
        self.dock_widget.setVisible(False)
        self.dock_widget.destroy()
        self.iface.currentLayerChanged.disconnect(self.layer_changed)

        # Unload QGIS expressions loaded by the plugin.
        for qgis_expression in list(qgis_expressions().keys()):
            QgsExpression.unregisterFunction(qgis_expression)

    def toggle_inasafe_action(self, checked):
        """Check or un-check the toggle inaSAFE toolbar button.

        This slot is called when the user hides the inaSAFE panel using its
        close button or using view->panels.

        :param checked: True if the dock should be shown, otherwise False.
        :type checked: bool
        """
        self.action_dock.setChecked(checked)

    # Run method that performs all the real work
    def toggle_dock_visibility(self):
        """Show or hide the dock widget."""
        if self.dock_widget.isVisible():
            self.dock_widget.setVisible(False)
        else:
            self.dock_widget.setVisible(True)
            self.dock_widget.raise_()

    def add_test_layers(self):
        """Add standard test layers."""
        from safe.test.utilities import load_standard_layers
        load_standard_layers()
        rect = QgsRectangle(106.806, -6.195, 106.837, -6.167)
        self.iface.mapCanvas().setExtent(rect)

    def select_test_package(self):
        """Select the test package."""
        default_package = 'safe'
        user_package = str(
            setting('testPackage', default_package, expected_type=str))

        test_package, _ = QInputDialog.getText(
            self.iface.mainWindow(), self.tr('Select the python test package'),
            self.tr('Select the python test package'), QLineEdit.Normal,
            user_package)

        if test_package == '':
            test_package = default_package

        set_setting('testPackage', test_package)
        msg = self.tr('Run tests in %s' % test_package)
        self.action_run_tests.setWhatsThis(msg)
        self.action_run_tests.setText(msg)

    def run_tests(self):
        """Run unit tests in the python console."""
        from qgis.PyQt.QtWidgets import QDockWidget
        main_window = self.iface.mainWindow()
        action = main_window.findChild(QAction, 'mActionShowPythonDialog')
        action.trigger()
        package = str(setting('testPackage', 'safe', expected_type=str))
        for child in main_window.findChildren(QDockWidget, 'PythonConsole'):
            if child.objectName() == 'PythonConsole':
                child.show()
                for widget in child.children():
                    if 'PythonConsoleWidget' in str(widget.__class__):
                        # print "Console widget found"
                        shell = widget.shell
                        shell.runCommand(
                            'from inasafe.test_suite import test_package')
                        shell.runCommand('test_package(\'%s\')' % package)
                        break

    def show_extent_selector(self):
        """Show the extent selector widget for defining analysis extents."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.extent_selector_dialog import ExtentSelectorDialog
        widget = ExtentSelectorDialog(
            self.iface,
            self.iface.mainWindow(),
            extent=self.dock_widget.extent.user_extent,
            crs=self.dock_widget.extent.crs)
        widget.clear_extent.connect(
            self.dock_widget.extent.clear_user_analysis_extent)
        widget.extent_defined.connect(
            self.dock_widget.define_user_analysis_extent)
        # This ensures that run button state is updated on dialog close
        widget.extent_selector_closed.connect(
            self.dock_widget.validate_impact_function)
        # Needs to be non modal to support hide -> interact with map -> show
        widget.show()  # non modal

    def show_minimum_needs(self):
        """Show the minimum needs dialog."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.minimum_needs.needs_calculator_dialog import (
            NeedsCalculatorDialog)

        dialog = NeedsCalculatorDialog(self.iface.mainWindow())
        dialog.exec_()

    def show_minimum_needs_configuration(self):
        """Show the minimum needs dialog."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.minimum_needs.needs_manager_dialog import (
            NeedsManagerDialog)

        dialog = NeedsManagerDialog(parent=self.iface.mainWindow(),
                                    dock=self.dock_widget)
        dialog.exec_()  # modal

    def show_options(self):
        """Show the options dialog."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.options_dialog import OptionsDialog

        dialog = OptionsDialog(iface=self.iface,
                               parent=self.iface.mainWindow())
        dialog.show_option_dialog()
        if dialog.exec_():  # modal
            self.dock_widget.read_settings()
            from safe.gui.widgets.message import getting_started_message
            send_static_message(self.dock_widget, getting_started_message())
            # Issue #4734, make sure to update the combobox after update the
            # InaSAFE option
            self.dock_widget.get_layers()

    def show_welcome_message(self):
        """Show the welcome message."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.options_dialog import OptionsDialog

        # Do not show by default
        show_message = False

        previous_version = StrictVersion(setting('previous_version'))
        current_version = StrictVersion(inasafe_version)

        # Set previous_version to the current inasafe_version
        set_setting('previous_version', inasafe_version)

        if setting('always_show_welcome_message', expected_type=bool):
            # Show if it the setting said so
            show_message = True
        elif previous_version < current_version:
            # Always show if the user installed new version
            show_message = True

        # Allow to disable welcome message when running automated tests
        if os.environ.get('INASAFE_DISABLE_WELCOME_MESSAGE', False):
            show_message = False

        if show_message:
            dialog = OptionsDialog(iface=self.iface,
                                   parent=self.iface.mainWindow())
            dialog.show_welcome_dialog()
            if dialog.exec_():  # modal
                self.dock_widget.read_settings()

    def show_keywords_wizard(self):
        """Show the keywords creation wizard."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.wizard.wizard_dialog import WizardDialog

        if self.iface.activeLayer() is None:
            return

        # Don't break an existing wizard session if accidentally clicked
        if self.wizard and self.wizard.isVisible():
            return

        # Prevent spawning multiple copies since the IFCW is non modal
        if not self.wizard:
            self.wizard = WizardDialog(self.iface.mainWindow(), self.iface,
                                       self.dock_widget)
        self.wizard.set_keywords_creation_mode()
        self.wizard.exec_()  # modal

    def show_function_centric_wizard(self):
        """Show the function centric wizard."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.wizard.wizard_dialog import WizardDialog

        # Don't break an existing wizard session if accidentally clicked
        if self.wizard and self.wizard.isVisible():
            return

        # Prevent spawning multiple copies since it is non modal
        if not self.wizard:
            self.wizard = WizardDialog(self.iface.mainWindow(), self.iface,
                                       self.dock_widget)
        self.wizard.set_function_centric_mode()
        # non-modal in order to hide for selecting user extent
        self.wizard.show()

    def show_shakemap_importer(self):
        """Show the converter dialog."""
        # import here only so that it is AFTER i18n set up
        from safe.gui.tools.shake_grid.shakemap_converter_dialog import (
            ShakemapConverterDialog)

        dialog = ShakemapConverterDialog(self.iface.mainWindow(), self.iface,
                                         self.dock_widget)
        dialog.exec_()  # modal

    def show_multi_buffer(self):
        """Show the multi buffer tool."""
        from safe.gui.tools.multi_buffer_dialog import (MultiBufferDialog)

        dialog = MultiBufferDialog(self.iface.mainWindow(), self.iface,
                                   self.dock_widget)
        dialog.exec_()  # modal

    def show_osm_downloader(self):
        """Show the OSM buildings downloader dialog."""
        from safe.gui.tools.osm_downloader_dialog import OsmDownloaderDialog

        dialog = OsmDownloaderDialog(self.iface.mainWindow(), self.iface)
        # otherwise dialog is never deleted
        dialog.setAttribute(Qt.WA_DeleteOnClose, True)
        dialog.show()  # non modal

    def show_geonode_uploader(self):
        """Show the Geonode uploader dialog."""
        from safe.gui.tools.geonode_uploader import GeonodeUploaderDialog

        dialog = GeonodeUploaderDialog(self.iface.mainWindow())
        dialog.show()  # non modal

    def add_osm_layer(self):
        """Add OSM tile layer to the map.

        This uses a gdal wrapper around the OSM tile service - see the
        WorldOSM.gdal file for how it is constructed.
        """
        path = resources_path('osm', 'WorldOSM.gdal')
        layer = QgsRasterLayer(path, self.tr('OpenStreetMap'))
        project = QgsProject.instance()

        # Try to add it as the last layer in the list
        # False flag prevents layer being added to legend
        project.addMapLayer(layer, False)
        root = QgsProject.instance().layerTreeRoot()
        index = len(root.findLayers()) + 1
        # LOGGER.info('Inserting layer %s at position %s' % (
        #    layer.source(), index))
        root.insertLayer(index, layer)
        project.addMapLayer(layer)

    def show_definitions(self):
        """Show InaSAFE Definitions (a report showing all key metadata)."""
        from safe.utilities.help import show_help
        from safe.gui.tools.help import definitions_help
        show_help(definitions_help.definitions_help())

    def show_field_mapping(self):
        """Show InaSAFE Field Mapping."""
        from safe.gui.tools.field_mapping_dialog import FieldMappingDialog
        dialog = FieldMappingDialog(
            parent=self.iface.mainWindow(),
            iface=self.iface,
        )
        if dialog.exec_():  # modal
            LOGGER.debug('Show field mapping accepted')
            self.dock_widget.layer_changed(self.iface.activeLayer())
        else:
            LOGGER.debug('Show field mapping not accepted')

    def show_metadata_converter(self):
        """Show InaSAFE Metadata Converter."""
        from safe.gui.tools.metadata_converter_dialog import (
            MetadataConverterDialog)
        dialog = MetadataConverterDialog(
            parent=self.iface.mainWindow(),
            iface=self.iface,
        )
        dialog.exec_()

    def show_multi_exposure(self):
        """Show InaSAFE Multi Exposure."""
        from safe.gui.tools.multi_exposure_dialog import MultiExposureDialog
        dialog = MultiExposureDialog(self.iface.mainWindow(), self.iface)
        dialog.exec_()  # modal

    def add_petabencana_layer(self):
        """Add petabencana layer to the map.

        This uses the PetaBencana API to fetch the latest floods in JK. See
        https://data.petabencana.id/floods
        """
        from safe.gui.tools.peta_bencana_dialog import PetaBencanaDialog
        dialog = PetaBencanaDialog(self.iface.mainWindow(), self.iface)
        dialog.show()  # non modal

    def show_batch_runner(self):
        """Show the batch runner dialog."""
        from safe.gui.tools.batch.batch_dialog import BatchDialog

        dialog = BatchDialog(parent=self.iface.mainWindow(),
                             iface=self.iface,
                             dock=self.dock_widget)
        dialog.exec_()  # modal

    def save_scenario(self):
        """Save current scenario to text file."""
        from safe.gui.tools.save_scenario import SaveScenarioDialog

        dialog = SaveScenarioDialog(iface=self.iface, dock=self.dock_widget)
        dialog.save_scenario()

    def layer_changed(self, layer):
        """Enable or disable keywords editor icon when active layer changes.

        :param layer: The layer that is now active.
        :type layer: QgsMapLayer
        """
        if not layer:
            enable_keyword_wizard = False
        elif not hasattr(layer, 'providerType'):
            enable_keyword_wizard = False
        elif layer.providerType() == 'wms':
            enable_keyword_wizard = False
        else:
            enable_keyword_wizard = True

        try:
            if layer:
                if is_raster_layer(layer):
                    enable_field_mapping_tool = False
                else:
                    keywords = KeywordIO().read_keywords(layer)
                    keywords_version = keywords.get('keyword_version')
                    if not keywords_version:
                        supported = False
                    else:
                        supported = (
                            is_keyword_version_supported(keywords_version))
                    if not supported:
                        enable_field_mapping_tool = False
                    else:
                        layer_purpose = keywords.get('layer_purpose')

                        if not layer_purpose:
                            enable_field_mapping_tool = False
                        else:
                            if layer_purpose == layer_purpose_exposure['key']:
                                layer_subcategory = keywords.get('exposure')
                            elif layer_purpose == layer_purpose_hazard['key']:
                                layer_subcategory = keywords.get('hazard')
                            else:
                                layer_subcategory = None
                            field_groups = get_field_groups(
                                layer_purpose, layer_subcategory)
                            if len(field_groups) == 0:
                                # No field group, disable field mapping tool.
                                enable_field_mapping_tool = False
                            else:
                                enable_field_mapping_tool = True
            else:
                enable_field_mapping_tool = False
        except (KeywordNotFoundError, NoKeywordsFoundError, MetadataReadError):
            # No keywords, disable field mapping tool.
            enable_field_mapping_tool = False

        self.action_keywords_wizard.setEnabled(enable_keyword_wizard)
        self.action_field_mapping.setEnabled(enable_field_mapping_tool)

    def shortcut_f7(self):
        """Executed when user press F7 - will show the shakemap importer."""
        self.show_shakemap_importer()
class midv_tolkn:
    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(QFile.decodeName(__file__))
        self.db = None
        
    def initGui(self):
        # Create actions
        icon = QIcon(os.path.join(self.plugin_dir, "icons", "midv_tolkn.png"))
        
        self.actionloadthelayers = QAction(QIcon(":/plugins/midv_tolkn/icons/load_layers_domains.png"), "Ladda tolkningslager t QGIS", self.iface.mainWindow())
        self.actionloadthelayers.setWhatsThis("Laddar tolkningslager för gvmagasin m.m. till QGIS")
        self.actionloadthelayers.triggered.connect(lambda x: self.load_the_layers())

        self.actionNewDB = QAction(QIcon(":/plugins/midv_tolkn/icons/create_new.png"), "Skapa en ny tolkningsdatabas", self.iface.mainWindow())
        self.actionNewDB.triggered.connect(lambda x: self.new_db())

        self.actionVacuumDB = QAction(QIcon(":/plugins/midv_tolkn/icons/vacuum.png"), "Packa (vacuum) tolkn-db", self.iface.mainWindow())
        self.actionVacuumDB.setWhatsThis("Perform database vacuuming")
        self.actionVacuumDB.triggered.connect(lambda x: self.vacuum_db())

        self.actionZipDB = QAction(QIcon(":/plugins/midv_tolkn/icons/zip.png"), "Backup av tolknings-databas", self.iface.mainWindow())
        self.actionZipDB.setWhatsThis("En komprimerad zip-fil kommer att skapas i samma dir som tolknings-databasen.")
        self.actionZipDB.triggered.connect(lambda x: self.zip_db())

        self.actionUpgradeDB = QAction(QIcon(":/plugins/midv_tolkn/icons/create_new.png"), "Uppgradera tolknings-databas", self.iface.mainWindow())
        self.actionUpgradeDB.setWhatsThis("Uppgradera en befintlig tolknings-databas till ny databas-struktur.")
        self.actionUpgradeDB.triggered.connect(lambda x: self.upgrade_db())

        #self.actionabout = QAction(QIcon(":/plugins/midv_tolkn/icons/about.png"), "Information", self.iface.mainWindow())
        #self.actionabout.triggered.connect(lambda x: self.about)
        
        # Add button
        self.iface.addToolBarIcon(self.actionloadthelayers)
        
        # Add plugins menu items
        self.midv_menu = None # Midvatten-plugin-menyn
        self.menu = None # sub-menyn "Tolkningar"
        
        # Check if Midvatten-menyn existerar och get it
        for child in self.iface.mainWindow().menuBar().children(): 
            if isinstance(child,QMenu): 
                if child.title() == "Midvatten": # Put here your menu name
                    self.midv_menu = child

        # If the Midvatten menu does not exist, create it!
        self.owns_midv_menu = False #indicator that this plugin must not clean up the midvatten menu
        if not self.midv_menu:
            self.owns_midv_menu = True #indicator that this plugin must clean up the midvatten menu
            self.midv_menu = QMenu( "Midvatten", self.iface.mainWindow().menuBar() )
            menuBar = self.iface.mainWindow().menuBar()
            menuBar.addMenu(self.midv_menu)

        # check if there is a sub-menu Tolkningar
        for childchild in self.midv_menu.children(): 
            if isinstance(childchild,QMenu): 
                if childchild.title() == "&Tolkningar": # Put here your menu name
                    print('found sub-menu Tolkningar')
                    self.menu = childchild

        # If the tolkning submenu does not exist, create it
        if not self.menu:
            print('will add Tolkningar submenu')
            self.menu_separator1 = self.midv_menu.addSeparator()
            self.menu = QMenu(QCoreApplication.translate("Midvatten", "&Tolkningar"))
            self.midv_menu.addMenu(self.menu)
            self.menu_separator2 = self.midv_menu.addSeparator()
            
        self.menu.addAction(self.actionloadthelayers)   
        self.menu.addAction(self.actionNewDB)   
        self.menu.addAction(self.actionVacuumDB)
        self.menu.addAction(self.actionZipDB)
        self.menu.addAction(self.actionUpgradeDB)
        #self.menu.addAction(self.actionabout)

    def unload(self):    
        # remove tool bar button
        self.iface.removeToolBarIcon(self.actionloadthelayers)

        # Remove the plugin menu items and icons
        try:
                self.midv_menu.removeAction(self.menu.menuAction())
                self.midv_menu.removeAction(self.menu_separator1)
                self.midv_menu.removeAction(self.menu_separator2)
        except:
                pass
        if self.owns_midv_menu: #indicator that this plugin must clean up the midvatten menu
            menubar = self.midv_menu.parentWidget()
            menubar.removeAction(self.midv_menu.menuAction())
            self.midv_menu.deleteLater()

    def about(self):   
        utils.pop_up_info(msg='This feature is not yet implemented',title='Hold on...')

    def load_data_domains(self):
        #utils.pop_up_info(msg='This feature is not yet implemented',title='Hold on...')
        #return
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        err_flag = utils.verify_msettings_loaded_and_layer_edit_mode(qgis.utils.iface, self.ms)#verify midv settings are loaded
        if err_flag == 0:
            conn_ok, dd_tables = utils.sql_load_fr_db("select name from sqlite_master where name like 'zz_%'")
            if not conn_ok:
                return
            d_domain_tables = [str(dd_table[0]) for dd_table in dd_tables]
            err_flag = utils.verify_msettings_loaded_and_layer_edit_mode(qgis.utils.iface, self.ms, d_domain_tables)#verify none of the tables are already loaded and in edit mode
            if err_flag == 0:
                LoadLayers(qgis.utils.iface, self.ms.settingsdict,'Midvatten_data_domains')
        QApplication.restoreOverrideCursor()#now this long process is done and the cursor is back as normal

    def load_the_layers(self):
        LoadLayers(qgis.utils.iface,self.db)

    def new_db(self, set_locale=False):
        if not set_locale:
            set_locale = utils.getcurrentlocale()

        filenamepath = os.path.join(os.path.dirname(__file__),"metadata.txt" )
        iniText = QSettings(filenamepath , QSettings.IniFormat)
        verno = str(iniText.value('version')) 
        from .create_tolkn_db import newdb
        newdbinstance = newdb(verno, set_locale=set_locale)
        if not newdbinstance.dbpath=='':
            self.db = newdbinstance.dbpath

    def upgrade_db(self, set_locale=False):
        from_db = None
        #get full path to the original db to be updated
        if self.db:
            use_current_db = utils.Askuser("YesNo","""Do you want to upgrade %s?"""%self.db,'Current database?')
            if use_current_db.result == 0:
                from_db = None
            elif use_current_db.result == 1:
                from_db = self.db
            elif use_current_db.result == '':
                return
        if not from_db:
            from_db = QFileDialog.getOpenFileName(None, 'Ange tolknings-db som ska exporteras','',"Spatialite (*.sqlite)")[0]
        if not from_db:
            QApplication.restoreOverrideCursor()
            return None

        #get EPSG in the original db
        EPSG = utils.sql_load_fr_db("""SELECT srid FROM geom_cols_ref_sys WHERE Lower(f_table_name) = Lower('gvmag') AND Lower(f_geometry_column) = Lower('geometry')""",from_db)

        #preparations to create new db of new design
        if not set_locale:
            set_locale = utils.getcurrentlocale()

        filenamepath = os.path.join(os.path.dirname(__file__),"metadata.txt" )
        iniText = QSettings(filenamepath , QSettings.IniFormat)
        verno = str(iniText.value('version'))

        #now create database of the updated design
        from .create_tolkn_db import newdb
        newdbinstance = newdb(verno, user_select_CRS=False, EPSG_code = EPSG[1][0][0], set_locale=set_locale)

        #transfer data to the new database
        foo = utils.UpgradeDatabase(from_db,newdbinstance.dbpath, EPSG)

        #set new database as the current db and load these layers
        if not newdbinstance.dbpath=='':
            self.db = newdbinstance.dbpath
        self.load_the_layers()
        
    def vacuum_db(self):
        force_another_db = False
        if self.db:
            use_current_db = utils.Askuser("YesNo","""Vill du packa %s?"""%self.db,'Which database?')
            if use_current_db.result == 1:
                dbpath = self.db
                force_another_db = True
            elif use_current_db.result == 0:
                force_another_db = True
            elif use_current_db.result == '':
                return
        if not self.db or force_another_db:
            dbpath = QFileDialog.getOpenFileName(None, 'Ange db som ska packas','',"Spatialite (*.sqlite)")[0]

        QApplication.setOverrideCursor(Qt.WaitCursor)
        utils.sql_alter_db(dbpath,'vacuum')
        QApplication.restoreOverrideCursor()
        
    def zip_db(self):
        force_another_db = False
        dbpath=None
        if self.db:
            use_current_db = utils.Askuser("YesNo",'Vill du göra backup av %s?'%self.db,'Which database?')
            if use_current_db.result == 1:
                dbpath = self.db
                force_another_db = False
            elif use_current_db.result == 0:
                force_another_db = True
            elif use_current_db.result == '':
                return
        if not self.db or force_another_db:
            dbpath = QFileDialog.getOpenFileName(None, 'Ange db som du vill skapa backup utav','',"Spatialite (*.sqlite)")[0]

        if dbpath:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            connection = utils.dbconnection(dbpath)
            connection.connect2db()
            connection.conn.cursor().execute("begin immediate")

            file_path = os.path.realpath(dbpath)
            dir_path = os.path.dirname(file_path)
            current_dir = dir_path.split(os.sep)[-1]

            bkupname = dbpath + datetime.datetime.now().strftime('%Y%m%dT%H%M') + '.zip'
            zf = zipfile.ZipFile(bkupname, mode='w')
            zf.write(dbpath,os.path.basename(dbpath), compress_type=compression) #compression will depend on if zlib is found or not
            zf.close()
            connection.conn.rollback()
            connection.closedb()
            self.iface.messageBar().pushMessage("Information","Database backup was written to " + bkupname, 1,duration=15)
            QApplication.restoreOverrideCursor()
    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):

        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:
            # Adds plugin icon to Plugins toolbar
            self.iface.addToolBarIcon(action)

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

        self.actions.append(action)
        # Connect all actions
        self.dlg.dirOldButton.clicked.connect(self.select_oldDir)
        self.dlg.dirNewButton.clicked.connect(self.select_newDir)
        self.dlg.dirResultButton.clicked.connect(self.select_dirResult)
        self.dlg.mengdertilcsvButton.clicked.connect(self.getStats)
        self.dlg.selectdir_MButton.clicked.connect(self.select_output_dirM)
        self.dlg.skrivtilcsvButton.clicked.connect(self.exportLayers)
        self.dlg.compareButton.clicked.connect(self.comparefiles)
        self.dlg.comboBox.currentIndexChanged[str].connect(
            self.comboBox_itemChanged)
        self.dlg.addButton.clicked.connect(self.addItem)
        self.dlg.removeButton.clicked.connect(self.removeItem)
        self.dlg.clearButton.clicked.connect(self.clearSelection)
        self.dlg.kommuneCheck.toggled.connect(self.kommuneSelected)
        self.dlg.checkBox_fritekst.toggled.connect(
            self.comp_checkbox_handler_free)
        self.dlg.checkBox_nvdbid.toggled.connect(
            self.comp_checkbox_handler_nvdbid)
        self.dlg.checkBox_objekt.toggled.connect(
            self.comp_checkbox_handler_object)
        self.dlg.kontraktCheck.toggled.connect(self.kontraktSelected)
        self.dlg.fylkeBox.currentIndexChanged[str].connect(self.getKommune)
        self.dlg.fylkeBox.currentIndexChanged[str].connect(self.getKontrakt)
        self.dlg.fylkeBox.currentIndexChanged.connect(
            self.fylkeBox_itemChanged)
        self.dlg.kommuneBox.currentIndexChanged[str].connect(
            self.kommuneBox_itemChanged)
        self.dlg.kontraktBox.currentIndexChanged[str].connect(
            self.kontraktBox_itemChanged)
        self.dlg.mergeButton.clicked.connect(self.mergeLayers)
        self.dlg.selectdirButton.clicked.connect(self.select_output_dir)
        self.dlg.kjorButton.clicked.connect(self.runTask)
        self.dlg.saveButton.clicked.connect(self.saveAsPreset)
        self.dlg.vegsystemBox.currentIndexChanged[str].connect(
            self.vegsystemBox_itemChanged)
        self.dlg.searchTable.doubleClicked.connect(self.searchPreset)
        self.dlg.deleteButton.clicked.connect(self.deletePreset)
        self.dlg.statsButton.clicked.connect(self.loadStats)
        self.dlg.folderButton.clicked.connect(self.openFolder)
        getAllAreaData()
        getAllObjectData()
        getAllPresetData()
        self.dlg.vegsystemBox.addItems(returnVegreferanseData())
        return action
class tableManager:
    def __init__(self, iface):
        self.iface = iface
        #i18n
        pluginPath = QFileInfo(
            os.path.realpath(__file__)).path()  # patch by Régis Haubourg
        localeName = QLocale.system().name()
        if QFileInfo(pluginPath).exists():
            self.localePath = pluginPath + "/i18n/tablemanager_" + localeName + ".qm"
        if QFileInfo(self.localePath).exists():
            self.translator = QTranslator()
            self.translator.load(self.localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

    def setCurrentTheme(self, theThemeName):
        """ Set icons to the current theme """
        self.action.setIcon(self.getThemeIcon("tableManagerIcon.png"))

    def getThemeIcon(self, theName):
        """ get the icon from the best available theme """
        myCurThemePath = QgsApplication.activeThemePath(
        ) + "/plugins/" + theName
        myDefThemePath = QgsApplication.defaultThemePath(
        ) + "/plugins/" + theName
        myQrcThemePath = ":/plugins/tablemanager/icons/" + QgsApplication.themeName(
        ) + "/" + theName
        myQrcPath = ":/plugins/tablemanager/icons/" + theName
        if QFile.exists(myCurThemePath):
            return QIcon(myCurThemePath)
        elif QFile.exists(myDefThemePath):
            return QIcon(myDefThemePath)
        elif QFile.exists(myQrcThemePath):
            return QIcon(myQrcThemePath)
        elif QFile.exists(myQrcPath):
            return QIcon(myQrcPath)
        else:
            return QIcon()

    def initGui(self):
        # create action
        self.action = QAction(
            self.getThemeIcon("tableManagerIcon.png"),
            QCoreApplication.translate('TableManager', 'Table manager'),
            self.iface.mainWindow())
        #self.action = QAction(QIcon(':/plugins/tableManager/icons/tableManagerIcon.png'), QCoreApplication.translate('TableManager','Table manager'), self.iface.mainWindow())
        self.action.setWhatsThis(
            QCoreApplication.translate('TableManager',
                                       'Manages attribute table structure'))
        self.action.triggered.connect(self.run)
        self.iface.currentThemeChanged.connect(self.setCurrentTheme)
        # add toolbar button and menu item
        if hasattr(self.iface, 'addVectorToolBarIcon'):
            self.iface.addVectorToolBarIcon(self.action)
        else:
            self.iface.addToolBarIcon(self.action)
        if hasattr(self.iface, 'addPluginToVectorMenu'):
            self.iface.addPluginToVectorMenu(u"&Table Manager", self.action)
        else:
            self.iface.addPluginToMenu(u"&Table Manager", self.action)

    def unload(self):
        # remove the plugin menu item and icon
        if hasattr(self.iface, 'removePluginVectorMenu'):
            self.iface.removePluginVectorMenu(u"&Table Manager", self.action)
        else:
            self.iface.removePluginMenu(u"&Table Manager", self.action)
        if hasattr(self.iface, 'removeVectorToolBarIcon'):
            self.iface.removeVectorToolBarIcon(self.action)
        else:
            self.iface.removeToolBarIcon(self.action)

    def run(self):
        # create and show a configuration dialog or something similar
        layer = self.iface.activeLayer()
        if layer == None or layer.type() != layer.VectorLayer:
            QMessageBox.warning(
                self.iface.mainWindow(),
                QCoreApplication.translate('TableManager', 'Table manager'),
                QCoreApplication.translate('TableManager',
                                           'Please select a vector layer'))
        elif layer.isEditable():
            QMessageBox.warning(
                self.iface.mainWindow(),
                QCoreApplication.translate('TableManager', 'Table manager'),
                QCoreApplication.translate(
                    'TableManager',
                    'The selected layer is currently in editing mode.\nPlease exit this mode before managing the table.'
                ))
        else:
            dialoga = tablemanager.tableManager_gui.TableManager(self.iface)
            dialoga.exec_()
Example #26
0
class PdokServicesPlugin(object):
    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface

        # docked or dialog, defaults to dialog
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if isinstance(QSettings().value("/pdokservicesplugin/docked"), QVariant):
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False))
        # else:
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", False)
        #
        # # Create the dialog and keep reference
        # if "True" == self.docked or "true" == self.docked or True is self.docked:
        #     self.dlg = PdokServicesPluginDockWidget()
        #     self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        # else:
        #     self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())

        self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDatabaseFilePath(
        )).path() + "/python/plugins/pdokservicesplugin"
        # initialize locale
        localePath = ""
        if isinstance(QSettings().value("locale/userLocale"), QVariant):
            locale = QSettings().value("locale/userLocale").value()[0:2]
        else:
            locale = QSettings().value("locale/userLocale")[0:2]

        if QFileInfo(self.plugin_dir).exists():
            localePath = self.plugin_dir + "/i18n/pdokservicesplugin_" + locale + ".qm"

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        self.currentLayer = None
        self.SETTINGS_SECTION = '/pdokservicesplugin/'
        self.pointer = None
        self.pdokgeocoder = PDOKGeoLocator(self.iface)
        self.geocoderSourceModel = None

    def getSettingsValue(self, key, default=''):
        if QSettings().contains(self.SETTINGS_SECTION + key):
            key = self.SETTINGS_SECTION + key
            if Qgis.QGIS_VERSION_INT < 10900:  # qgis <= 1.8
                return str(QSettings().value(key).toString())
            else:
                return str(QSettings().value(key))
        else:
            return default

    def setSettingsValue(self, key, value):
        key = self.SETTINGS_SECTION + key
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue(key, QVariant(value))
        else:
            QSettings().setValue(key, value)

    def initGui(self):
        # Create action that will start plugin configuration
        runIcon = QIcon(os.path.join(self.plugin_dir, 'icon_add_service.svg'))
        self.run_action = QAction(runIcon, \
            "PDOK Services plugin", self.iface.mainWindow())

        self.servicesLoaded = False
        # connect the action to the run method
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if "True" == self.docked or "true" == self.docked or  True == self.docked:
        #     self.run_action.triggered.connect(self.showAndRaise)
        #     self.dlg.radioDocked.setChecked(True)
        #     # docked the dialog is immidiately visible, so should run NOW
        # else:
        #     self.run_action.triggered.connect(self.run)
        #     self.dlg.radioDocked.setChecked(False)
        #     self.setupfq()
        self.run_action.triggered.connect(self.run)
        #self.dlg.radioDocked.setChecked(False)
        self.setupfq()

        # Add toolbar button and menu item
        #self.iface.addToolBarIcon(self.action)

        self.toolbar = self.iface.addToolBar("PDOK services plugin")
        self.toolbar.setObjectName("PDOK services plugin")
        self.toolbar.addAction(self.run_action)
        self.toolbarSearch = QLineEdit()
        self.toolbarSearch.setMaximumWidth(200)
        self.toolbarSearch.setAlignment(Qt.AlignLeft)
        self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek")
        self.toolbar.addWidget(self.toolbarSearch)
        self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar)
        # address/point cleanup
        eraserIcon = QIcon(
            os.path.join(self.plugin_dir, 'icon_remove_cross.svg'))
        self.clean_action = QAction(eraserIcon, \
            "Cleanup", self.eraseAddress())
        self.toolbar.addAction(self.clean_action)
        self.clean_action.triggered.connect(self.eraseAddress)
        self.clean_action.setEnabled(False)

        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/icon_help.png"), \
                            "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("Pdok Services Plugin About")
        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction)

        self.aboutAction.triggered.connect(self.about)
        self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService)

        self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress)

        self.dlg.geocoderSearch.textEdited.connect(self.searchAddress)
        self.dlg.geocoderSearch.setPlaceholderText(
            "PDOK Locatieserver zoek, bv postcode of postcode huisnummer")

        self.dlg.geocoderResultSearch.textChanged.connect(
            self.filterGeocoderResult)
        self.dlg.geocoderResultSearch.setPlaceholderText(
            "een of meer zoekwoorden uit resultaat")

        #self.dlg.radioDocked.toggled.connect(self.set_docked)

        self.dlg.btnCheckPdokJson.clicked.connect(self.checkPdokJson)
        #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged)

        ui = self.dlg.ui
        cbxs = [
            ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr,
            ui.cbx_pcl, ui.cbx_hmp
        ]
        # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search
        for cbx in cbxs:
            cbx.stateChanged.connect(self.searchAddress)

        self.run(True)

    # for now hiding the pointer as soon as the extent changes
    #def extentsChanged(self):
    #    self.removePointer()

    def checkPdokJson(self):
        myversion = self.getSettingsValue('pdokversion', '1')
        msgtxt = ''
        msglvl = 0  # QgsMessageBar.INFO
        try:
            response = urllib.request.urlopen(
                'http://www.qgis.nl/pdok.version')
            str_response = response.read().decode('utf-8')
            pdokversion = json.loads(str_response)
            if pdokversion > int(myversion):
                response = urllib.request.urlopen(
                    'http://www.qgis.nl/pdok.json')
                str_response = response.read().decode('utf-8')
                pdokjson = json.loads(str_response)
                with open(self.plugin_dir + '/pdok.json', 'w') as outfile:
                    json.dump(pdokjson, outfile)
                msgtxt = "De laatste versie is opgehaald en zal worden gebruikt " + \
                    str(pdokversion) + ' (was ' + myversion +')'
                self.servicesLoaded = False  # reset reading of json
                self.run()
                self.setSettingsValue('pdokversion', pdokversion)
            else:
                msgtxt = "Geen nieuwere versie beschikbaar dan " + str(
                    pdokversion)
        except Exception as e:
            #print e
            msgtxt = "Fout bij ophalen van service info. Netwerk probleem?"
            msglvl = 2  # QgsMessageBar.CRITICAL
        # msg
        if hasattr(self.iface, 'messageBar'):
            self.iface.messageBar().pushMessage("PDOK services update",
                                                msgtxt,
                                                level=msglvl,
                                                duration=10)
        else:  # 1.8
            QMessageBox.information(self.iface.mainWindow(),
                                    "Pdok Services Plugin", msgtxt)

    # def set_docked(self, foo):
    #     self.setSettingsValue('docked', self.dlg.radioDocked.isChecked())
    #     #if Qgis.QGIS_VERSION_INT < 10900:
    #     #    # qgis <= 1.8
    #     #    QSettings().setValue("/pdokservicesplugin/docked", QVariant(self.dlg.radioDocked.isChecked()))
    #     #else:
    #     #    QSettings().setValue("/pdokservicesplugin/docked", self.dlg.radioDocked.isChecked())

    def showAndRaise(self):
        self.dlg.show()
        self.dlg.raise_()
        # also remove the pointer
        self.removePointer()

    def about(self):
        infoString = "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
        infoString += "Company - Zuidt - http://www.zuidt.nl\n"
        infoString += "Source: https://github.com/rduivenvoorde/pdokservicesplugin"
        QMessageBox.information(self.iface.mainWindow(),
                                "Pdok Services Plugin About", infoString)

    def unload(self):
        self.removePointer()
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu("&Pdok Services Plugin", self.run_action)
        self.iface.removePluginMenu("&Pdok Services Plugin", self.aboutAction)
        del self.toolbarSearch
        del self.run_action
        del self.aboutAction

    def showService(self, selectedIndexes):
        if len(selectedIndexes) == 0:
            self.currentLayer = None
            self.dlg.ui.layerInfo.setHtml('')
            self.dlg.ui.comboSelectProj.clear()
            return
        # needed to scroll To the selected row incase of using the keyboard / arrows
        self.dlg.servicesView.scrollTo(
            self.dlg.servicesView.selectedIndexes()[0])
        # itemType holds the data (== column 1)
        self.currentLayer = self.dlg.servicesView.selectedIndexes()[1].data(
            Qt.UserRole)
        if isinstance(self.currentLayer, QVariant):
            self.currentLayer = self.currentLayer.toMap()
            # QGIS 1.8: QVariants
            currentLayer = {}
            for key in list(self.currentLayer.keys()):
                val = self.currentLayer[key]
                currentLayer[str(key)] = str(val.toString())
            self.currentLayer = currentLayer
        url = self.currentLayer['url']
        title = self.currentLayer['title']
        style = ''
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        servicetitle = self.currentLayer['servicetitle']
        layername = self.currentLayer['layers']
        abstract = self.currentLayer['abstract']
        stype = self.currentLayer['type'].upper()
        minscale = ''
        if 'minscale' in self.currentLayer and self.currentLayer[
                'minscale'] != None and self.currentLayer['minscale'] != '':
            minscale = "min. schaal 1:" + self.currentLayer['minscale']
        maxscale = ''
        if 'maxscale' in self.currentLayer and self.currentLayer[
                'maxscale'] != None and self.currentLayer['maxscale'] != '':
            maxscale = "max. schaal 1:" + self.currentLayer['maxscale']
        self.dlg.ui.layerInfo.setText('')
        self.dlg.ui.btnLoadLayer.setEnabled(True)
        self.dlg.ui.layerInfo.setHtml(
            '<h4>%s</h4><h3>%s</h3><lu><li>%s</li><li>&nbsp;</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li></lu>'
            % (servicetitle, title, abstract, stype, url, layername, style,
               minscale, maxscale))
        self.dlg.ui.comboSelectProj.clear()
        if stype == "WMS":
            try:
                crs = self.currentLayer['crs']
            except KeyError:
                crs = 'EPSG:28992'
            crs = crs.split(',')
            self.dlg.ui.comboSelectProj.addItems(crs)
            for i in range(len(crs)):
                if crs[i] == 'EPSG:28992':
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)
        if stype == "WMTS":
            tilematrixsets = self.currentLayer['tilematrixsets'].split(',')
            self.dlg.ui.comboSelectProj.addItems(tilematrixsets)
            for i in range(len(tilematrixsets)):
                if tilematrixsets[i].startswith('EPSG:28992'):
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)

    def loadService(self):
        if self.currentLayer == None:
            return
        servicetype = self.currentLayer['type']
        url = self.currentLayer['url']
        # some services have an url with query parameters in it, we have to urlencode those:
        location, query = urllib.parse.splitquery(url)
        url = location
        if query != None and query != '':
            url += ('?' + urllib.parse.quote_plus(query))
        title = self.currentLayer['title']
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        else:
            style = ''  # == default for this service
        layers = self.currentLayer['layers']
        # mmm, tricky: we take the first one while we can actually want png/gif or jpeg
        if servicetype == "wms":
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                crs = 'EPSG:28992'
            else:
                crs = self.dlg.ui.comboSelectProj.currentText()
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                uri = url
                self.iface.addRasterLayer(
                    uri,  # service uri
                    title,  # name for layer (as seen in QGIS)
                    "wms",  # dataprovider key
                    [layers],  # array of layername(s) for provider (id's)
                    [""
                     ],  # array of stylename(s)  NOTE: ignoring styles here!!!
                    imgformat,  # image format searchstring
                    crs)  # crs code searchstring
            else:
                # qgis > 1.8
                uri = "crs=" + crs + "&layers=" + layers + "&styles=" + style + "&format=" + imgformat + "&url=" + url
                self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wmts":
            if Qgis.QGIS_VERSION_INT < 10900:
                QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", (
                    "Sorry, dit type layer: '" + servicetype.upper() +
                    "' \nkan niet worden geladen in deze versie van QGIS.\nMisschien kunt u QGIS 2.0 installeren (die kan het WEL)?\nOf is de laag niet ook beschikbaar als wms of wfs?"
                ), QMessageBox.Ok, QMessageBox.Ok)
                return
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                tilematrixset = 'EPSG:28992'
            else:
                tilematrixset = self.dlg.ui.comboSelectProj.currentText()
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            # special case for luchtfoto
            #if layers=="luchtfoto":
            #    # tileMatrixSet=nltilingschema&crs=EPSG:28992&layers=luchtfoto&styles=&format=image/jpeg&url=http://geodata1.nationaalgeoregister.nl/luchtfoto/wmts/1.0.0/WMTSCapabilities.xml
            #    # {u'layers': u'luchtfoto', u'imgformats': u'image/jpeg', u'title': u'PDOK-achtergrond luchtfoto', u'url': u'http://geodata1.nationaalgeoregister.nl/luchtfoto/wms', u'abstract': u'', u'tilematrixsets': u'nltilingschema', u'type': u'wmts'}
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url
            #else:
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url;
            #uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            if tilematrixset.startswith('EPSG:'):
                crs = tilematrixset
                i = crs.find(':', 5)
                if i > -1:
                    crs = crs[:i]
            elif tilematrixset.startswith('OGC:1.0'):
                crs = 'EPSG:3857'
            uri = "tileMatrixSet=" + tilematrixset + "&crs=" + crs + "&layers=" + layers + "&styles=default&format=" + imgformat + "&url=" + url
            #print "############ PDOK URI #################"
            #print uri
            self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wfs":
            location, query = urllib.parse.splitquery(url)
            #uri = location+"?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME="+layers+"&SRSNAME=EPSG:28992"
            #uri = location + "?SERVICE=WFS&REQUEST=GetFeature&TYPENAME=" + layers + "&SRSNAME=EPSG:28992"
            # adding a bbox paramater forces QGIS to NOT cache features but retrieve new features all the time
            # QGIS will update the BBOX to the right value
            #uri += "&BBOX=-10000,310000,290000,650000"
            uri = " pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:28992' typename='" + layers + "' url='" + url + "' version='2.0.0' "
            self.iface.addVectorLayer(uri, title, "WFS")
        elif servicetype == "wcs":
            # cache=AlwaysCache&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            uri = ''
            # cache=AlwaysCache
            # cache=PreferNetwork
            # cache=AlwaysNetwork
            # cache=AlwaysNetwork&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.1&identifier="+layers+"&url="+url
            # working for ahn1 ahn2 and ahn3: GEOTIFF_FLOAT32
            format = 'GEOTIFF_FLOAT32'
            # working for ahn25m is only image/tiff
            if layers == 'ahn25m':
                format = 'image/tiff'
            # we handcrated some wcs layers with 2 different image formats: tiff (RGB) and tiff (float32):
            if 'imgformats' in self.currentLayer:
                format = self.currentLayer['imgformats'].split(',')[0]
            uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=" + format + "&version=1.1.2&identifier=" + layers + "&url=" + url

            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.2&identifier=" + layers + "&url=" + url
            self.iface.addRasterLayer(uri, title, "wcs")
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", (
                "Sorry, dit type layer: '" + servicetype.upper() +
                "' \nkan niet worden geladen door de plugin of door QGIS.\nIs het niet beschikbaar als wms, wmts of wfs?"
            ), QMessageBox.Ok, QMessageBox.Ok)
            return

    def filterGeocoderResult(self, string):
        #print "filtering geocoder results: %s" % string
        self.dlg.geocoderResultView.selectRow(0)
        self.geocoderProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.geocoderProxyModel.setFilterFixedString(string)

    def searchAddressFromToolbar(self):
        self.removePointer()
        self.geocoderSourceModel.clear()
        self.geocode()

    def searchAddress(self):
        self.removePointer()
        #print "search geocoder for: %s" % self.dlg.geocoderSearch.text()
        self.geocoderSourceModel.clear()
        #self.geocode(self.dlg.geocoderSearch.text())
        self.suggest()

    def eraseAddress(self):
        """
        clean the input and remove the pointer
        """
        self.removePointer()
        if self.geocoderSourceModel is not None:
            self.geocoderSourceModel.clear()
        if self.dlg.geocoderSearch is not None:
            self.dlg.geocoderSearch.clear()
        if self.toolbarSearch is not None:
            self.toolbarSearch.clear()

    def filterLayers(self, string):
        # remove selection if one row is selected
        self.dlg.servicesView.selectRow(0)
        #self.currentLayer = None
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxyModel.setFilterFixedString(string)

    #def addSourceRow(self, service, layer):
    def addSourceRow(self, serviceLayer):
        # you can attache different "data's" to to an QStandarditem
        # default one is the visible one:
        itemType = QStandardItem("%s" % (serviceLayer["type"].upper()))
        # userrole is a free form one:
        # only attach the data to the first item
        # service layer = a dict/object with all props of the layer
        itemType.setData(serviceLayer, Qt.UserRole)
        itemType.setToolTip(
            "%s - %s" % (serviceLayer["type"].upper(), serviceLayer["title"]))
        # only wms services have styles (sometimes)
        layername = serviceLayer["title"]
        if 'style' in serviceLayer:
            itemLayername = QStandardItem(
                "%s [%s]" % (serviceLayer["title"], serviceLayer["style"]))
            layername = "%s [%s]" % (serviceLayer["title"],
                                     serviceLayer["style"])
        else:
            itemLayername = QStandardItem("%s" % (serviceLayer["title"]))
        itemLayername.setToolTip(
            "%s - %s" %
            (serviceLayer["type"].upper(), serviceLayer["servicetitle"]))
        # itemFilter is the item used to search filter in. That is why layername is a combi of layername + filter here
        itemFilter = QStandardItem(
            "%s %s %s %s" %
            (serviceLayer["type"], layername, serviceLayer["servicetitle"],
             serviceLayer["abstract"]))
        itemServicetitle = QStandardItem("%s" % (serviceLayer["servicetitle"]))
        itemServicetitle.setToolTip(
            "%s - %s" % (serviceLayer["type"].upper(), serviceLayer["title"]))
        self.sourceModel.appendRow(
            [itemLayername, itemType, itemServicetitle, itemFilter])

    # run method that performs all the real work
    def run(self, hiddenDialog=False):

        # enable possible remote pycharm debugging
        #import pydevd
        #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)

        # last viewed/selected tab
        if QSettings().contains("/pdokservicesplugin/currenttab"):
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                self.dlg.tabs.widget(QSettings().value(
                    "/pdokservicesplugin/currenttab").toInt()[0])
            else:
                self.dlg.tabs.widget(
                    int(QSettings().value("/pdokservicesplugin/currenttab")))

        if self.servicesLoaded == False:
            pdokjson = os.path.join(os.path.dirname(__file__), ".",
                                    "pdok.json")
            f = open(pdokjson, 'r', encoding='utf-8')
            self.pdok = json.load(f)
            f.close()

            self.proxyModel = QSortFilterProxyModel()
            self.sourceModel = QStandardItemModel()
            self.proxyModel.setSourceModel(self.sourceModel)
            # filter == search on itemFilter column:
            self.proxyModel.setFilterKeyColumn(3)
            self.dlg.servicesView.setModel(self.proxyModel)
            self.dlg.servicesView.setEditTriggers(
                QAbstractItemView.NoEditTriggers)

            self.geocoderProxyModel = QSortFilterProxyModel()
            self.geocoderSourceModel = QStandardItemModel()

            self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel)
            self.geocoderProxyModel.setFilterKeyColumn(0)
            self.dlg.geocoderResultView.setModel(self.geocoderProxyModel)
            self.dlg.geocoderResultView.setEditTriggers(
                QAbstractItemView.NoEditTriggers)

            #{"services":[
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"},
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}
            # ]}
            #
            for service in self.pdok["services"]:
                # service[layer] was an array
                if isinstance(service["layers"], str) or isinstance(
                        service["layers"], str):
                    self.addSourceRow(service)

            self.dlg.layerSearch.textChanged.connect(self.filterLayers)
            self.dlg.layerSearch.setPlaceholderText(
                "woord uit laagnaam, type of service ")
            self.dlg.servicesView.selectionModel().selectionChanged.connect(
                self.showService)
            self.dlg.servicesView.doubleClicked.connect(self.loadService)
            # actually I want to load a service when doubleclicked on header
            # but as I cannot get this to work, let's disable clicking it then
            self.dlg.servicesView.verticalHeader().setSectionsClickable(False)
            self.dlg.servicesView.horizontalHeader().setSectionsClickable(
                False)

            #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress)
            self.dlg.geocoderResultView.selectionModel(
            ).selectionChanged.connect(self.zoomToAddress)

            # hide itemFilter column:
            self.dlg.servicesView.hideColumn(3)
            self.servicesLoaded = True

        self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service")
        self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]")
        self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        #self.dlg.servicesView.verticalHeader().hide()
        #self.dlg.servicesView.resizeColumnsToContents()
        self.dlg.servicesView.setColumnWidth(
            0, 300)  # set name to 300px (there are some huge layernames)
        self.dlg.servicesView.horizontalHeader().setStretchLastSection(True)
        # show the dialog ?
        if not hiddenDialog:
            self.dlg.show()
        # Run the dialog event loop
        #result = self.dlg.exec_()
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue("/pdokservicesplugin/currenttab",
                                 QVariant(self.dlg.tabs.currentIndex()))
        else:
            QSettings().setValue("/pdokservicesplugin/currenttab",
                                 self.dlg.tabs.currentIndex())
        self.removePointer()

    def setupfq(self):
        """
        Setup the fq checkboxes in the gui, by looking into the settings for the
        'pdokservicesplugin/checkedfqs' key, which contains a list of type strings
        like ['weg','adres']
        """
        checked_fqs = self.getSettingsValue('checkedfqs', [])
        #self.info('setup fq: {}'.format(checked_fqs))
        if len(checked_fqs
               ) > 0:  # else there is not saved state... take gui defaults
            self.dlg.ui.cbx_gem.setChecked('gemeente' in checked_fqs)
            self.dlg.ui.cbx_wpl.setChecked('woonplaats' in checked_fqs)
            self.dlg.ui.cbx_weg.setChecked('weg' in checked_fqs)
            self.dlg.ui.cbx_pcd.setChecked('postcode' in checked_fqs)
            self.dlg.ui.cbx_adr.setChecked('adres' in checked_fqs)
            self.dlg.ui.cbx_pcl.setChecked('perceel' in checked_fqs)
            self.dlg.ui.cbx_hmp.setChecked('hectometerpaal' in checked_fqs)

    def createfq(self):
        """
        This creates a fq-string (Filter Query, see https://github.com/PDOK/locatieserver/wiki/Zoekvoorbeelden-Locatieserver)
        Based on the checkboxes in the dialog.
        Defaults to ''
        Example: 'fq=+type:adres+type:gemeente'  (only gemeente AND addresses)
        :return:
        """
        fqlist = []
        if self.dlg.ui.cbx_gem.isChecked():
            fqlist.append('gemeente')
        if self.dlg.ui.cbx_wpl.isChecked():
            fqlist.append('woonplaats')
        if self.dlg.ui.cbx_weg.isChecked():
            fqlist.append('weg')
        if self.dlg.ui.cbx_pcd.isChecked():
            fqlist.append('postcode')
        if self.dlg.ui.cbx_adr.isChecked():
            fqlist.append('adres')
        if self.dlg.ui.cbx_pcl.isChecked():
            fqlist.append('perceel')
        if self.dlg.ui.cbx_hmp.isChecked():
            fqlist.append('hectometerpaal')
        self.setSettingsValue('checkedfqs', fqlist)
        #self.info(self.getSettingsValue('checkedfqs', ['leeg?']))
        fq = ''
        if len(fqlist) > 0:
            fq = '&fq=+type:' + '+type:'.join(fqlist)
        return fq

    def suggest(self):
        self.dlg.ui.lookupinfo.setHtml('')
        search_text = self.dlg.geocoderSearch.text()
        if len(search_text) <= 1:
            # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
            #     "meer input aub: {}".format(search_text)
            #     ), QMessageBox.Ok, QMessageBox.Ok)
            return
        # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
        #     "zoeken: {}".format(search_text)
        # ), QMessageBox.Ok, QMessageBox.Ok)
        results = self.pdokgeocoder.suggest(search_text, self.createfq())
        if len(results) == 0:
            # ignore, as we are suggesting, maybe more characters will reveal something...
            return
        for result in results:
            #print address
            adrestekst = QStandardItem("%s" % (result["adrestekst"]))
            adrestekst.setData(result, Qt.UserRole)
            type = QStandardItem("%s" % (result["type"]))
            id = QStandardItem("%s" % (result["id"]))
            score = QStandardItem("%s" % (result["score"]))
            adrestekst.setData(result, Qt.UserRole)
            self.geocoderSourceModel.appendRow([adrestekst, type])
        self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
        self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(
            Qt.AlignLeft)
        self.dlg.geocoderResultView.resizeColumnsToContents()
        self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(
            True)

    def geocode(self):
        self.dlg.geocoderSearch.setText(self.toolbarSearch.text())
        self.suggest()
        if self.dlg.geocoderResultView.model().rowCount() > 0:
            self.dlg.geocoderResultView.selectRow(0)
            self.zoomToAddress()
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
                "Niets gevonden.\nProbeer een andere spelling, of alleen postcode/huisnummer?\n\nSelecteer meer (Locatieserver) 'typen' in de PdokServicesPlugin dialoog.\n\nOf gebruik de 'PDOK geocoder'-tab in de PdokServicesPlugin dialoog."
                ), QMessageBox.Ok, QMessageBox.Ok)

    # def geocode(self):
    #     self.dlg.ui.lookupinfo.setHtml('')
    #     search_text = self.toolbarSearch.text()
    #     addresses = self.pdokgeocoder.search(search_text)
    #     if len(addresses) == 0:
    #         QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
    #             "Niets gevonden. Probeer een andere spelling of alleen postcode/huisnummer."
    #             ), QMessageBox.Ok, QMessageBox.Ok)
    #         return
    #     for address in addresses:
    #         #print address
    #         adrestekst = QStandardItem("%s" % (address["adrestekst"]))
    #         adrestekst.setData(address, Qt.UserRole)
    #         straat = QStandardItem("%s" % (address["straat"]))
    #         nummer = QStandardItem("%s" % (address["nummer"]))
    #         postcode = QStandardItem("%s" % (address["postcode"]))
    #         plaats = QStandardItem("%s" % (address["plaats"]))
    #         gemeente = QStandardItem("%s" % (address["gemeente"]))
    #         provincie = QStandardItem("%s" % (address["provincie"]))
    #         self.geocoderSourceModel.appendRow([adrestekst, straat, nummer, postcode, plaats, gemeente, provincie])
    #
    #     self.dlg.geocoderResultView.selectRow(0)
    #     self.zoomToAddress()
    #
    #     self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
    #     self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Straat")
    #     self.geocoderSourceModel.setHeaderData(2, Qt.Horizontal, "Nr")
    #     self.geocoderSourceModel.setHeaderData(3, Qt.Horizontal, "Postcode")
    #     self.geocoderSourceModel.setHeaderData(4, Qt.Horizontal, "Plaats")
    #     self.geocoderSourceModel.setHeaderData(5, Qt.Horizontal, "Gemeente")
    #     self.geocoderSourceModel.setHeaderData(6, Qt.Horizontal, "Provincie")
    #
    #     self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(3).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(4).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(5).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(6).setTextAlignment(Qt.AlignLeft)
    #
    #     self.dlg.geocoderResultView.resizeColumnsToContents()
    #     self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def zoomToAddress(self):
        # get x,y from data of record
        self.removePointer()

        data = self.dlg.geocoderResultView.selectedIndexes()[0].data(
            Qt.UserRole)

        if 'centroide_rd' in data:  # free OR lookup service
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
        else:
            # no centroid yet, probably only object id, retrieve it via lookup service
            id = data['id']
            data = self.pdokgeocoder.lookup(id)
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
            lookup_data = data['data']
            lis = ''
            for key in lookup_data.keys():
                lis = lis + '<li>{}: {}</li>'.format(key, lookup_data[key])
            self.dlg.ui.lookupinfo.setHtml('<h4>{}</h4><lu>{}</lu>'.format(
                adrestekst, lis))

        # just always transform from 28992 to mapcanvas crs
        crs = self.iface.mapCanvas().mapSettings().destinationCrs()
        crs28992 = QgsCoordinateReferenceSystem()
        crs28992.createFromId(28992)
        crsTransform = QgsCoordinateTransform(crs28992, crs,
                                              QgsProject.instance())
        z = 1587
        if adrestekst.lower().startswith('adres'):
            z = 794
        elif adrestekst.lower().startswith('perceel'):
            z = 794
        elif adrestekst.lower().startswith('hectometer'):
            z = 1587
        elif adrestekst.lower().startswith('straat'):
            z = 3175
        elif adrestekst.lower().startswith('postcode'):
            z = 6350
        elif adrestekst.lower().startswith('woonplaats'):
            z = 25398
        elif adrestekst.lower().startswith('gemeente'):
            z = 50797
        elif adrestekst.lower().startswith('provincie'):
            z = 812750
        geom.transform(crsTransform)
        center = geom.asPoint()
        self.setPointer(center)
        # zoom to with center is actually setting a point rectangle and then zoom
        rect = QgsRectangle(center, center)
        self.iface.mapCanvas().setExtent(rect)
        self.iface.mapCanvas().zoomScale(z)
        self.iface.mapCanvas().refresh()

    def setPointer(self, point):
        self.removePointer()
        self.pointer = QgsVertexMarker(self.iface.mapCanvas())
        self.pointer.setColor(QColor(255, 255, 0))
        self.pointer.setIconSize(10)
        self.pointer.setPenWidth(5)
        self.pointer.setCenter(point)
        self.clean_action.setEnabled(True)

    def removePointer(self):
        if self.pointer is not None:
            self.iface.mapCanvas().scene().removeItem(self.pointer)
            self.clean_action.setEnabled(False)

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin',
                                 Qgis.Info)
Example #27
0
class XYZHubConnector(object):
    """base plugin"""
    def __init__(self, iface):
        """init"""
        import sys
        print(sys.version)
        self.iface = iface
        self.web_menu = "&XYZ Hub Connector"
        self.init_modules()
        self.obj = self

    def initGui(self):
        """startup"""

        parent = self.iface.mainWindow()

        ######## action, button

        icon = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/xyz.png"))
        icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/bbox.svg"))
        self.action_connect = QAction(icon, "XYZ Hub Connection", parent)
        self.action_connect.setWhatsThis(
            QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message"))
        self.action_connect.setStatusTip(
            QCoreApplication.translate(PLUGIN_NAME, "status tip message"))

        self.action_magic_sync = QAction("Magic Sync (EXPERIMENTAL)", parent)

        if self.iface.activeLayer() is None:
            self.action_magic_sync.setEnabled(False)

        # self.action_magic_sync.setVisible(False) # disable magic sync

        ######## CONNECT action, button

        self.action_connect.triggered.connect(self.open_connection_dialog)
        self.action_magic_sync.triggered.connect(self.open_magic_sync_dialog)

        ######## Add the toolbar + button
        self.toolbar = self.iface.addToolBar(PLUGIN_NAME)
        self.toolbar.setObjectName("XYZ Hub Connector")

        self.actions = [self.action_connect]

        for a in self.actions:
            self.iface.addPluginToWebMenu(self.web_menu, a)

        # # uncomment to use menu button
        # tool_btn = QToolButton(self.toolbar)
        # for a in self.actions:
        #     tool_btn.addAction(a)
        # tool_btn.setDefaultAction(self.action_connect)
        # tool_btn.setPopupMode(tool_btn.MenuButtonPopup)
        # self.xyz_widget_action = self.toolbar.addWidget(tool_btn) # uncomment to use menu button

        self.toolbar.addAction(self.action_connect)

        self.action_help = None

        progress = QProgressBar()
        progress.setMinimum(0)
        progress.setMaximum(0)
        progress.reset()
        progress.hide()
        # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis
        self.iface.statusBarIface().addPermanentWidget(progress)
        self.pb = progress

    def init_modules(self):
        # util.init_module()

        # parent = self.iface.mainWindow()
        parent = QgsProject.instance()

        self.secret = Secret(config.USER_PLUGIN_DIR + "/secret.ini")
        ######## Init xyz modules
        self.map_basemap_meta = basemap.load_default_xml()
        self.auth_manager = AuthManager(config.USER_PLUGIN_DIR + "/auth.ini")

        self.token_model = GroupTokenModel(parent)
        # self.layer = LayerManager(parent, self.iface)

        self.network = NetManager(parent)

        self.con_man = LoaderManager()
        self.con_man.config(self.network)
        self.layer_man = LayerManager()

        ######## data flow
        # self.conn_info = SpaceConnectionInfo()

        ######## token
        self.token_model.load_ini(config.USER_PLUGIN_DIR + "/token.ini")

        ######## CALLBACK

        self.con_man.ld_pool.signal.progress.connect(
            self.cb_progress_busy)  #, Qt.QueuedConnection
        self.con_man.ld_pool.signal.finished.connect(self.cb_progress_done)

        QgsProject.instance().layersWillBeRemoved["QStringList"].connect(
            self.layer_man.remove)
        QgsProject.instance().layersWillBeRemoved["QStringList"].connect(
            self.con_man.remove)

        # self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT

        if LOG_TO_FILE:
            QgsApplication.messageLog().messageReceived.connect(cb_log_qgis)

    def unload_modules(self):
        # self.con_man.disconnect_ux( self.iface)
        QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect(
            self.layer_man.remove)
        QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect(
            self.con_man.remove)

        # utils.disconnect_silent(self.iface.currentLayerChanged)

        # self.iface.mapCanvas().extentsChanged.disconnect( self.debug_reload)

        self.secret.deactivate()

        # close_file_logger()
        pass

    def unload(self):
        """teardown"""
        self.unload_modules()
        # remove the plugin menu item and icon
        self.iface.removePluginWebMenu(self.web_menu, self.action_help)

        self.toolbar.clear(
        )  # remove action from custom toolbar (toolbar still exist)
        self.toolbar.deleteLater()

        for a in self.actions:
            self.iface.removePluginWebMenu(self.web_menu, a)

    ###############
    # Callback
    ###############
    def cb_layer_selected(self, qlayer):
        flag_xyz = True if qlayer is not None and self.layer.is_xyz_supported_layer(
            qlayer) else False
        # disable magic sync
        # self.action_magic_sync.setEnabled(flag_xyz)

    ###############
    # Callback of action (main function)
    ###############
    def cb_success_msg(self, msg, info=""):
        self.iface.messageBar().pushMessage(msg, info, Qgis.Success, 5)

    def make_cb_success(self, msg, info=""):
        def _cb_success_msg():
            txt = info
            self.cb_success_msg(msg, txt)

        return _cb_success_msg

    def make_cb_success_args(self, msg, info=""):
        def _cb_success_msg(args):
            a, kw = parse_qt_args(args)
            txt = ". ".join(map(str, a))
            self.cb_success_msg(msg, txt)

        return _cb_success_msg

    def cb_handle_error_msg(self, e):
        err = parse_exception_obj(e)
        if isinstance(err, ChainInterrupt):
            e0, idx = err.args[0:2]
            if isinstance(
                    e0,
                (net_handler.NetworkError, net_handler.NetworkTimeout)):
                ok = self.show_net_err(e0)
                if ok: return
            elif isinstance(e0, EmptyXYZSpaceError):
                ret = exec_warning_dialog(
                    "XYZ Hub", "Requested query returns no features")
                return
        self.show_err_msgbar(err)

    def show_net_err(self, err):
        reply_tag, status, reason, body, err_str, url = err.args[:6]
        if reply_tag in ["count", "statistics"]:  # too many error
            # msg = "Network Error: %s: %s. %s"%(status, reason, err_str)
            return 1

        detail = "\n".join(["Request:", url, "", "Response:", body])
        msg = ("%s: %s\n" % (status, reason) +
               "There was a problem connecting to the server")
        if status == 403:
            msg += "\n\n" + "Please make sure that the token has WRITE permission"
        ret = exec_warning_dialog("Network Error", msg, detail)
        return 1

    def show_err_msgbar(self, err):
        self.iface.messageBar().pushMessage(TAG_PLUGIN, repr(err),
                                            Qgis.Warning, 3)
        msg = format_traceback(err)
        QgsMessageLog.logMessage(msg, TAG_PLUGIN, Qgis.Warning)

    def cb_progress_busy(self, n_active):
        if n_active > 1: return
        self.flag_pb_show = True
        self.cb_progress_refresh()

    def cb_progress_done(self):
        self.flag_pb_show = False
        self.cb_progress_refresh()

    def cb_progress_refresh(self):
        if not hasattr(self, "flag_pb_show"): return

        pb = self.pb
        if self.flag_pb_show:
            pb.show()
            # print_qgis("show",pb)
        else:
            pb.hide()
            # print_qgis("hide")

    ###############
    # Action (main function)
    ###############
    # unused
    def load_bbox(self, con, args):
        bbox = bbox_utils.extend_to_bbox(
            bbox_utils.get_bounding_box(self.iface))
        a, kw = parse_qt_args(args)
        kw["bbox"] = bbox
        kw["limit"] = 1000
        con.start(*a, **kw)

    # UNUSED
    def refresh_canvas(self):
        # self.iface.activeLayer().triggerRepaint()
        self.iface.mapCanvas().refresh()

    def previous_canvas_extent(self):
        self.iface.mapCanvas().zoomToPreviousExtent()

    #

    def new_main_dialog(self):
        parent = self.iface.mainWindow()
        dialog = MainDialog(parent)

        dialog.config(self.token_model)
        dialog.config_secret(self.secret)
        auth = self.auth_manager.get_auth()
        dialog.config_basemap(self.map_basemap_meta, auth)

        con = self.con_man.make_con("create")
        con.signal.finished.connect(
            dialog.btn_use.clicked.emit)  # can be optimized !!
        con.signal.error.connect(self.cb_handle_error_msg)

        con = self.con_man.make_con("list")
        con.signal.results.connect(make_fun_args(dialog.cb_display_spaces))
        con.signal.error.connect(self.cb_handle_error_msg)
        con.signal.error.connect(lambda e: dialog.cb_enable_token_ui())
        con.signal.finished.connect(dialog.cb_enable_token_ui)

        con = self.con_man.make_con("edit")
        con.signal.finished.connect(dialog.btn_use.clicked.emit)
        con.signal.error.connect(self.cb_handle_error_msg)

        con = self.con_man.make_con("delete")
        con.signal.results.connect(dialog.btn_use.clicked.emit)
        con.signal.error.connect(self.cb_handle_error_msg)

        con = self.con_man.make_con("stat")
        con.signal.results.connect(make_fun_args(
            dialog.cb_display_space_count))
        con.signal.error.connect(self.cb_handle_error_msg)

        ############ clear cache btn
        dialog.signal_clear_cache.connect(self.open_clear_cache_dialog)

        ############ add map tile btn
        dialog.signal_add_basemap.connect(self.add_basemap_layer)

        ############ btn: new, edit, delete space
        dialog.signal_new_space.connect(self.start_new_space)
        dialog.signal_edit_space.connect(self.start_edit_space)
        dialog.signal_del_space.connect(self.start_delete_space)

        ############ Use Token btn
        dialog.signal_use_token.connect(lambda a: self.con_man.finish_fast())
        dialog.signal_use_token.connect(self.start_use_token)

        ############ get count
        dialog.signal_space_count.connect(
            self.start_count_feat,
            Qt.QueuedConnection)  # queued -> non-blocking ui

        ############ connect btn
        dialog.signal_space_connect.connect(self.start_load_layer)

        ############ upload btn
        dialog.signal_upload_space.connect(self.start_upload_space)

        return dialog

    def start_new_space(self, args):
        con = self.con_man.get_con("create")
        con.start_args(args)

    def start_edit_space(self, args):
        con = self.con_man.get_con("edit")
        con.start_args(args)

    def start_delete_space(self, args):
        con = self.con_man.get_con("delete")
        con.start_args(args)

    def start_use_token(self, args):
        con = self.con_man.get_con("list")
        con.start_args(args)

    def start_count_feat(self, args):
        con = self.con_man.get_con("stat")
        con.start_args(args)

    def start_upload_space(self, args):
        con_upload = UploadLayerController(self.network, n_parallel=2)
        self.con_man.add_background(con_upload)
        # con_upload.signal.finished.connect( self.make_cb_success("Uploading finish") )
        con_upload.signal.results.connect(
            self.make_cb_success_args("Uploading finish"))
        con_upload.signal.error.connect(self.cb_handle_error_msg)

        con = InitUploadLayerController(self.network)
        self.con_man.add_background(con)

        con.signal.results.connect(con_upload.start_args)
        con.signal.error.connect(self.cb_handle_error_msg)

        con.start_args(args)

    def start_load_layer(self, args):
        # create new con
        # config
        # run

        ############ connect btn
        con_load = LoadLayerController(self.network, n_parallel=1)
        self.con_man.add_background(con_load)
        # con_load.signal.finished.connect( self.make_cb_success("Loading finish") )
        con_load.signal.results.connect(
            self.make_cb_success_args("Loading finish"))
        # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_load.signal.error.connect(self.cb_handle_error_msg)

        con_load.start_args(args)

        # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT

    def add_basemap_layer(self, args):
        a, kw = parse_qt_args(args)
        meta, app_id, app_code = a
        self.auth_manager.save(app_id, app_code)
        basemap.add_basemap_layer(meta, app_id, app_code)

    ###############
    # Open dialog
    ###############
    def open_clear_cache_dialog(self):
        dialog = ConfirmDialog(
            "Delete cache will make loaded layer unusable !!")
        ret = dialog.exec_()
        if ret != dialog.Ok: return

        utils.clear_cache()

    def open_connection_dialog(self):
        dialog = self.new_main_dialog()

        vlayer = self.iface.activeLayer()
        dialog.set_layer(vlayer)

        dialog.exec_()
        self.con_man.finish_fast()
        # self.startTime = time.time()

    # not used
    def open_magic_sync_dialog(self):
        pass
Example #28
0
class ImpEpanet(object):
    def __init__(self, iface):
        # Save a reference to the QGIS iface
        self.iface = iface
        self.canvas = self.iface.mapCanvas()
        self.dlg = ExportEpanetInpFilesDialog()
        self.sections = [
            'junctions', 'tanks', 'pipes', 'pumps', 'reservoirs', 'valves',
            'STATUS', 'PATTERNS', 'CURVES', 'CONTROLS', 'RULES', 'ENERGY',
            'REACTIONS', 'REACTIONS_I', 'EMITTERS', 'QUALITY', 'SOURCES',
            'MIXING', 'TIMES', 'REPORT', 'OPTIONS'
        ]

    def initGui(self):
        # Create action
        sys.path.append(os.path.dirname(__file__) + '/impcount.py')

        self.action = QAction(
            QIcon(":/plugins/ImportEpanetInpFiles/impepanet.png"),
            "Import Epanet Input File", self.iface.mainWindow())
        self.action.setWhatsThis("Import Epanet Input File")
        self.action.triggered.connect(self.run)
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu("&ImportEpanetInpFiles", self.action)

        self.actionexp = QAction(
            QIcon(":/plugins/ImportEpanetInpFiles/expepanet.png"),
            "Export Epanet Input File", self.iface.mainWindow())
        self.actionexp.setWhatsThis("Export Epanet Input File")
        self.actionexp.triggered.connect(self.runexp)
        self.iface.addToolBarIcon(self.actionexp)
        self.iface.addPluginToMenu("&ImportEpanetInpFiles", self.actionexp)

        self.dlg.ok_button.clicked.connect(self.ok)
        self.dlg.cancel_button.clicked.connect(self.cancel)
        self.dlg.toolButtonOut.clicked.connect(self.toolButtonOut)

    def unload(self):
        # Remove the plugin
        self.iface.removePluginMenu("&ImportEpanetInpFiles", self.action)
        self.iface.removeToolBarIcon(self.action)

        self.iface.removePluginMenu("&ImportEpanetInpFiles", self.actionexp)
        self.iface.removeToolBarIcon(self.actionexp)

    def run(self):
        filePath = QFileDialog.getOpenFileName(
            self.iface.mainWindow(), "Choose EPANET Input file",
            os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'),
            "Epanet Inp File (*.inp)")
        if filePath[0] == "":
            return
        epa2gis(filePath[0])
        self.iface.messageBar().clearWidgets()
        msgBox = QMessageBox()
        msgBox.setWindowTitle('ImportEpanetInpFiles')
        msgBox.setText(
            'Shapefiles have been created successfully in folder "_shapefiles_".'
        )
        msgBox.exec_()

    def runexp(self):
        self.dlg.out.setText('')
        self.layers = self.canvas.layers()
        self.layer_list = []
        self.layer_list = ['NONE']
        [self.layer_list.append(layer.name()) for layer in self.layers]

        for sect in self.sections:
            eval('self.dlg.sect_' + sect + '.clear()')
            eval('self.dlg.sect_' + sect + '.addItems(self.layer_list)')
            indices = [i for i, s in enumerate(self.layer_list) if sect in s]
            if indices:
                if sect == 'REACTIONS':
                    eval('self.dlg.sect_' + sect +
                         '.setCurrentIndex(indices[1])')
                else:
                    eval('self.dlg.sect_' + sect +
                         '.setCurrentIndex(indices[0])')

        self.dlg.setWindowFlags(Qt.CustomizeWindowHint
                                | Qt.WindowStaysOnTopHint
                                | Qt.WindowCloseButtonHint)
        self.dlg.show()

    def cancel(self):
        self.layer_list = []
        self.layer_list = ['NONE']
        for sect in self.sections:
            exec('self.dlg.sect_' + sect + '.clear()')
        self.dlg.close()

    def toolButtonOut(self):
        self.outEpanetName = QFileDialog.getSaveFileName(
            None, 'Save File',
            os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'),
            'Epanet Inp File (*.inp)')
        self.dlg.out.setText(self.outEpanetName[0])

    def selectOutp(self):
        msgBox = QMessageBox()
        msgBox.setIcon(QMessageBox.Warning)
        msgBox.setWindowTitle('Warning')
        msgBox.setText('Please define Epanet Inp File location.')
        msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint
                              | Qt.WindowCloseButtonHint)
        msgBox.exec_()
        return True

    def ok(self):
        # Here check if select OK button, get the layer fields
        # Initialize
        # [JUNCTIONS]
        if self.dlg.out.text() == '':
            if self.selectOutp():
                return
        elif os.path.isabs(self.dlg.out.text()) == False:
            if self.selectOutp():
                return

        self.outEpanetName = self.dlg.out.text()

        try:
            f = open(self.outEpanetName, "w")
            f.close()
        except:
            msgBox = QMessageBox()
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setWindowTitle('Warning')
            msgBox.setText('Please define Epanet Inp File location.')
            msgBox.setWindowFlags(Qt.CustomizeWindowHint
                                  | Qt.WindowStaysOnTopHint
                                  | Qt.WindowCloseButtonHint)
            msgBox.exec_()
            return

        if not self.layers:
            msgBox = QMessageBox()
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setWindowTitle('Warning')
            msgBox.setText('No layers selected.')
            msgBox.setWindowFlags(Qt.CustomizeWindowHint
                                  | Qt.WindowStaysOnTopHint
                                  | Qt.WindowCloseButtonHint)
            msgBox.exec_()
            return
        xypipes_id = []
        xypipesvert = []
        for sect in self.sections:
            exec('sect' + sect + '=[]') in globals(), locals()
            exec('xy' + sect + '=[]') in globals(), locals()
            if eval('self.dlg.sect_' + sect + '.currentText()') != 'NONE':
                # Get layer field names
                indLayerName = self.layer_list.index(
                    eval('self.dlg.sect_' + sect + '.currentText()')) - 1
                provider = self.layers[indLayerName].dataProvider()
                fields = provider.fields()
                field_names = [field.name() for field in fields]
                for elem in self.layers[indLayerName].getFeatures():
                    eval('sect' + sect +
                         '.append(dict(zip(field_names, elem.attributes())))')
                    if any(sect in s for s in self.sections[0:5]):
                        geom = elem.geometry()
                        if self.layers[indLayerName].geometryType() == 0:
                            eval('xy' + sect + '.append(geom.asPoint())')
                        elif self.layers[indLayerName].geometryType() == 1:
                            eval('xy' + sect + '.append(geom.asPolyline())')
                            if sect == 'pipes':
                                if len(geom.asPolyline()) > 2:
                                    for pp in range(
                                            len(geom.asPolyline()) - 2):
                                        xypipes_id.append(elem.attributes()[0])
                                        xypipesvert.append(
                                            geom.asPolyline()[pp])
                    if sect == 'junctions':
                        if 'Elevation' not in locals()['sect' +
                                                       sect][0].keys():
                            QMessageBox.warning(QWidget(), "Message",
                                                "Elevation field is missing.")
        # (myDirectory,nameFile) = os.path.split(self.iface.activeLayer().dataProvider().dataSourceUri())
        my_directory = ''
        f = open(self.outEpanetName, 'wt')
        f.write('[TITLE]\n')
        f.write('Export input file via plugin ExportEpanetInpFiles. \n\n')
        f.write('[JUNCTIONS]\n')
        node_i_ds = []
        for i in range(len(locals()['sectjunctions'])):
            node_i_ds.append(locals()['sectjunctions'][i]['ID'])
            f.write(locals()['sectjunctions'][i]['ID'] + '   ' +
                    str(locals()['sectjunctions'][i]['Elevation']) + '\n')
        f.write('\n[RESERVOIRS]\n')
        for i in range(len(locals()['sectreservoirs'])):
            node_i_ds.append(locals()['sectreservoirs'][i]['ID'])
            f.write(locals()['sectreservoirs'][i]['ID'] + '   ' +
                    str(locals()['sectreservoirs'][i]['Head']) + '\n')
        f.write('\n[TANKS]\n')
        for i in range(len(locals()['secttanks'])):
            node_i_ds.append(locals()['secttanks'][i]['ID'])
            if locals()['secttanks'][i]['VolumeCurv'] == None:
                locals()['secttanks'][i]['VolumeCurv'] = ""
            f.write(locals()['secttanks'][i]['ID'] + '   ' +
                    str(locals()['secttanks'][i]['Elevation']) + '   ' +
                    str(locals()['secttanks'][i]['InitLevel']) + '   ' +
                    str(locals()['secttanks'][i]['MinLevel']) + '   ' +
                    str(locals()['secttanks'][i]['MaxLevel']) + '   ' +
                    str(locals()['secttanks'][i]['Diameter']) + '   ' +
                    str(locals()['secttanks'][i]['MinVolume']) + '   ' +
                    str(locals()['secttanks'][i]['VolumeCurv']) + '   ' + '\n')
        f.write('\n[PIPES]\n')
        for i in range(len(locals()['sectpipes'])):
            if (locals()['sectpipes'][i]['NodeFrom']
                    in node_i_ds) and (locals()['sectpipes'][i]['NodeTo']
                                       in node_i_ds):
                f.write(locals()['sectpipes'][i]['ID'] + '   ' +
                        locals()['sectpipes'][i]['NodeFrom'] + '   ' +
                        locals()['sectpipes'][i]['NodeTo'] + '   ' +
                        str(locals()['sectpipes'][i]['Length']) + '   ' +
                        str(locals()['sectpipes'][i]['Diameter']) + '   ' +
                        str(locals()['sectpipes'][i]['Roughness']) + '   ' +
                        str(locals()['sectpipes'][i]['MinorLoss']) + '   ' +
                        locals()['sectpipes'][i]['Status'] + '\n')
        f.write('\n[PUMPS]\n')
        for i in range(len(locals()['sectpumps'])):
            if locals()['sectpumps'][i]['Curve'] != 'NULL':
                try:
                    locals()['sectpumps'][i]['Curve'] = 'HEAD ' + locals(
                    )['sectpumps'][i]['Curve']
                except:
                    locals()['sectpumps'][i]['Curve'] = 'HEAD '
            else:
                locals()['sectpumps'][i]['Curve'] = ''
            if locals()['sectpumps'][i]['Pattern'] != 'NULL':
                try:
                    locals()['sectpumps'][i]['Pattern'] = 'PATTERN ' + locals(
                    )['sectpumps'][i]['Pattern']
                except:
                    locals()['sectpumps'][i]['Pattern'] = "PATTERN "
            else:
                locals()['sectpumps'][i]['Pattern'] = ''
            if locals()['sectpumps'][i]['Power'] != 'NULL':
                try:
                    locals()['sectpumps'][i]['Power'] = 'POWER ' + locals(
                    )['sectpumps'][i]['Power']
                except:
                    locals()['sectpumps'][i]['Power'] = "POWER "
            else:
                locals()['sectpumps'][i]['Power'] = ''

            try:
                f.write(locals()['sectpumps'][i]['ID'] + '   ' +
                        locals()['sectpumps'][i]['NodeFrom'] + '   ' +
                        locals()['sectpumps'][i]['NodeTo'] + '   ' +
                        locals()['sectpumps'][i]['Curve'] + '   ' +
                        str(locals()['sectpumps'][i]['Pattern']) + '   ' +
                        str(locals()['sectpumps'][i]['Power']) + '\n')
            except:
                f.write(locals()['sectpumps'][i]['ID'] + '\n')

        f.write('\n[VALVES]\n')
        if self.dlg.sect_valves.currentText() != 'NONE':
            for i in range(len(locals()['sectvalves'])):
                try:
                    locals()['sectvalves'][i]['NodeFrom'] = locals(
                    )['sectvalves'][i]['NodeFrom'] + ''
                except:
                    locals()['sectvalves'][i]['NodeFrom'] = ""

                try:
                    locals()['sectvalves'][i]['NodeTo'] = locals(
                    )['sectvalves'][i]['NodeTo'] + ''
                except:
                    locals()['sectvalves'][i]['NodeTo'] = ""
                f.write("{}   {}   {}   {}    {}    {}    {}\n".format(
                    locals()['sectvalves'][i]['ID'],
                    locals()['sectvalves'][i]['NodeFrom'],
                    locals()['sectvalves'][i]['NodeTo'],
                    str(locals()['sectvalves'][i]['Diameter']),
                    locals()['sectvalves'][i]['Type'],
                    str(locals()['sectvalves'][i]['Setting']),
                    str(locals()['sectvalves'][i]['MinorLoss'])))

        f.write('\n[DEMANDS]\n')
        for i in range(len(locals()['sectjunctions'])):
            for u in range(int((len(locals()['sectjunctions'][i]) - 2) / 2)):
                if locals(
                )['sectjunctions'][i]['Demand' + str(u + 1)] == 0 and str(
                        locals()['sectjunctions'][i]['Pattern' +
                                                     str(u + 1)]) == 'None':
                    continue
                if str(locals()['sectjunctions'][i]
                       ['Pattern' + str(u + 1)]) == 'NULL' or str(
                           locals()['sectjunctions'][i]['Pattern' +
                                                        str(u + 1)]) == 'None':
                    locals()['sectjunctions'][i]['Pattern' + str(u + 1)] = ''
                f.write(
                    locals()['sectjunctions'][i]['ID'] + '   ' +
                    str(locals()['sectjunctions'][i]['Demand' + str(u + 1)]) +
                    '   ' +
                    str(locals()['sectjunctions'][i]['Pattern' + str(u + 1)]) +
                    '\n')

        f.write('\n[STATUS]\n')
        for i in range(len(locals()['sectSTATUS'])):
            f.write("{}   {}\n".format(
                locals()['sectSTATUS'][i]['Link_ID'],
                locals()['sectSTATUS'][i]['Status/Set']))

        f.write('\n[PATTERNS]\n')
        for i in range(len(locals()['sectPATTERNS'])):
            f.write("{}   {}\n".format(
                locals()['sectPATTERNS'][i]['Pattern_ID'],
                locals()['sectPATTERNS'][i]['Multiplier']))

        f.write('\n[CURVES]\n')
        for i in range(len(locals()['sectCURVES'])):
            f.write(";{}:\n   {}   {}   {}\n".format(
                locals()['sectCURVES'][i]['Type'],
                locals()['sectCURVES'][i]['Curve_ID'],
                str(locals()['sectCURVES'][i]['X-Value']),
                str(locals()['sectCURVES'][i]['Y-Value'])))

        f.write('\n[CONTROLS]\n')
        for i in range(len(locals()['sectCONTROLS'])):
            f.write("{}\n".format(locals()['sectCONTROLS'][i]['Controls']))

        f.write('\n[RULES]\n')
        for i in range(len(locals()['sectRULES'])):
            f.write("RULE {}\n   {}\n".format(
                locals()['sectRULES'][i]['Rule_ID'],
                locals()['sectRULES'][i]['Rule']))

        f.write('\n[ENERGY]\n')
        if locals()['sectENERGY']:
            try:
                f.write('Global Efficiency   ' +
                        str(locals()['sectENERGY'][0]['GlobalEffi']) + '\n')
            except:
                pass
            try:
                f.write('Global Price    ' +
                        str(locals()['sectENERGY'][0]['GlobalPric']) + '\n')
            except:
                pass
            try:
                f.write('Demand Charge   ' +
                        str(locals()['sectENERGY'][0]['DemCharge']) + '\n')
            except:
                pass

        f.write('\n[REACTIONS]\n')
        if locals()['sectREACTIONS']:
            try:
                f.write('Order Bulk   ' +
                        str(locals()['sectREACTIONS'][0]['OrderBulk']) + '\n')
            except:
                pass
            try:
                f.write('Order Tank    ' +
                        str(locals()['sectREACTIONS'][0]['OrderTank']) + '\n')
            except:
                pass
            try:
                f.write('Order Wall   ' +
                        str(locals()['sectREACTIONS'][0]['OrderWall']) + '\n')
            except:
                pass
            try:
                f.write('Global Bulk   ' +
                        str(locals()['sectREACTIONS'][0]['GlobalBulk']) + '\n')
            except:
                pass
            try:
                f.write('Global Wall   ' +
                        str(locals()['sectREACTIONS'][0]['GlobalWall']) + '\n')
            except:
                pass
            try:
                f.write('Limiting Potential   ' +
                        str(locals()['sectREACTIONS'][0]['LimPotent']) + '\n')
            except:
                pass
            try:
                f.write('Roughness Correlation   ' +
                        str(locals()['sectREACTIONS'][0]['RoughCorr']) + '\n')
            except:
                pass

        f.write('\n[REACTIONS]\n')
        for i in range(len(locals()['sectREACTIONS_I'])):
            f.write('{}    {}    {} \n'.format(
                locals()['sectREACTIONS_I'][i]['Type'],
                locals()['sectREACTIONS_I'][i]['Pipe/Tank'],
                str(locals()['sectREACTIONS_I'][i]['Coeff.'])))
        f.write('\n[EMITTERS]\n')
        for i in range(len(locals()['sectEMITTERS'])):
            f.write('{}    {}\n'.format(
                locals()['sectEMITTERS'][i]['Junc_ID'],
                str(locals()['sectEMITTERS'][i]['Coeff.'])))

        f.write('\n[SOURCES]\n')
        for i in range(len(locals()['sectSOURCES'])):
            try:
                locals()['sectSOURCES'][i]['Pattern'] = locals(
                )['sectSOURCES'][i]['Pattern'] + ''
            except:
                locals()['sectSOURCES'][i]['Pattern'] = ''
            f.write("{}   {}   {}   {}\n".format(
                locals()['sectSOURCES'][i]['Node_ID'],
                locals()['sectSOURCES'][i]['Type'],
                str(locals()['sectSOURCES'][i]['Strength']),
                locals()['sectSOURCES'][i]['Pattern']))

        f.write('\n[MIXING]\n')
        for i in range(len(locals()['sectMIXING'])):
            f.write('{}    {}    {} \n'.format(
                locals()['sectMIXING'][i]['Tank_ID'],
                locals()['sectMIXING'][i]['Model'],
                str(locals()['sectMIXING'][i]['Fraction'])))

        f.write('\n[TIMES]\n')
        if locals()['sectTIMES']:
            try:
                f.write('Duration   ' +
                        str(locals()['sectTIMES'][0]['Duration']) + '\n')
            except:
                pass
            try:
                f.write('Hydraulic Timestep    ' +
                        str(locals()['sectTIMES'][0]['HydStep']) + '\n')
            except:
                pass
            try:
                f.write('Quality Timestep   ' +
                        str(locals()['sectTIMES'][0]['QualStep']) + '\n')
            except:
                pass
            try:
                f.write('Pattern Timestep   ' +
                        str(locals()['sectTIMES'][0]['PatStep']) + '\n')
            except:
                pass
            try:
                f.write('Pattern Start   ' +
                        str(locals()['sectTIMES'][0]['PatStart']) + '\n')
            except:
                pass
            try:
                f.write('Report Timestep   ' +
                        str(locals()['sectTIMES'][0]['RepStep']) + '\n')
            except:
                pass
            try:
                f.write('Report Start   ' +
                        str(locals()['sectTIMES'][0]['RepStart']) + '\n')
            except:
                pass
            try:
                f.write('Start ClockTime   ' +
                        str(locals()['sectTIMES'][0]['StartClock']) + '\n')
            except:
                pass
            try:
                f.write('Statistic   ' +
                        str(locals()['sectTIMES'][0]['Statistic']) + '\n')
            except:
                pass

        f.write('\n[REPORT]\n')
        if locals()['sectREPORT']:
            try:
                f.write('Status   ' + locals()['sectREPORT'][0]['Status'] +
                        '\n')
            except:
                pass
            try:
                f.write('Summary    ' + locals()['sectREPORT'][0]['Summary'] +
                        '\n')
            except:
                pass
            try:
                f.write('Page   ' + locals()['sectREPORT'][0]['Page'] + '\n')
            except:
                pass

        f.write('\n[OPTIONS]\n')
        if locals()['sectOPTIONS']:
            try:
                f.write('Units   ' + str(locals()['sectOPTIONS'][0]['Units']) +
                        '\n')
            except:
                pass
            try:
                f.write('Headloss    ' +
                        str(locals()['sectOPTIONS'][0]['Headloss']) + '\n')
            except:
                pass
            try:
                f.write('Specific Gravity   ' +
                        str(locals()['sectOPTIONS'][0]['SpecGrav']) + '\n')
            except:
                pass
            try:
                f.write('Viscosity   ' +
                        str(locals()['sectOPTIONS'][0]['Viscosity']) + '\n')
            except:
                pass
            try:
                f.write('Trials   ' +
                        str(locals()['sectOPTIONS'][0]['Trials']) + '\n')
            except:
                pass
            try:
                f.write('Accuracy   ' +
                        str(locals()['sectOPTIONS'][0]['Accuracy']) + '\n')
            except:
                pass
            try:
                f.write('CHECKFREQ   ' +
                        str(locals()['sectOPTIONS'][0]['CheckFreq']) + '\n')
            except:
                pass
            try:
                f.write('MAXCHECK   ' +
                        str(locals()['sectOPTIONS'][0]['MaxCheck']) + '\n')
            except:
                pass
            try:
                f.write('DAMPLIMIT   ' +
                        str(locals()['sectOPTIONS'][0]['DampLimit']) + '\n')
            except:
                pass
            try:
                f.write('Unbalanced   ' +
                        str(locals()['sectOPTIONS'][0]['Unbalanced']) + '\n')
            except:
                pass
            try:
                f.write('Pattern   ' +
                        str(locals()['sectOPTIONS'][0]['PatID']) + '\n')
            except:
                pass
            try:
                f.write('Demand Multiplier   ' +
                        str(locals()['sectOPTIONS'][0]['DemMult']) + '\n')
            except:
                pass
            try:
                f.write('Emitter Exponent   ' +
                        str(locals()['sectOPTIONS'][0]['EmitExp']) + '\n')
            except:
                pass
            try:
                f.write('Quality   ' +
                        str(locals()['sectOPTIONS'][0]['Quality']) + '\n')
            except:
                pass
            try:
                f.write('Diffusivity   ' +
                        str(locals()['sectOPTIONS'][0]['Diffusivit']) + '\n')
            except:
                pass
            try:
                f.write('Tolerance   ' +
                        str(locals()['sectOPTIONS'][0]['Tolerance']) + '\n')
            except:
                pass

        f.write('\n[COORDINATES]\n')
        for i in range(len(locals()['sectjunctions'])):
            f.write(locals()['sectjunctions'][i]['ID'] + '   ' +
                    str(locals()['xyjunctions'][i][0]) + '   ' +
                    str(locals()['xyjunctions'][i][1]) + '\n')
        for i in range(len(locals()['sectreservoirs'])):
            f.write(locals()['sectreservoirs'][i]['ID'] + '   ' +
                    str(locals()['xyreservoirs'][i][0]) + '   ' +
                    str(locals()['xyreservoirs'][i][1]) + '\n')
        for i in range(len(locals()['secttanks'])):
            f.write(locals()['secttanks'][i]['ID'] + '   ' +
                    str(locals()['xytanks'][i][0]) + '   ' +
                    str(locals()['xytanks'][i][1]) + '\n')

        f.write('\n[VERTICES]\n')

        for l in range(len(xypipes_id)):
            f.write(xypipes_id[l] + '   ' + str(xypipesvert[l][0]) + '   ' +
                    str(xypipesvert[l][1]) + '\n')

        f.write('\n[END]\n')

        f.close()

        self.cancel()
        msgBox = QMessageBox()
        msgBox.setWindowTitle('Export Options')
        msgBox.setText('Export Epanet Inp File "' + self.outEpanetName +
                       '" succesful.')
        msgBox.exec_()
class PyArchInitPlugin(object):
    HOME = os.environ['PYARCHINIT_HOME']

    PARAMS_DICT = {
        'SERVER': '',
        'HOST': '',
        'DATABASE': '',
        'PASSWORD': '',
        'PORT': '',
        'USER': '',
        'THUMB_PATH': '',
        'EXPERIMENTAL': ''
    }

    path_rel = os.path.join(os.sep, HOME, 'pyarchinit_DB_folder', 'config.cfg')
    conf = open(path_rel, "r")
    data = conf.read()
    conf.close()
    PARAMS_DICT = eval(data)

    # TODO: find a better way to settings config
    # if 'EXPERIMENTAL' in PARAMS_DICT:
    #     PARAMS_DICT['EXPERIMENTAL'] = 'No'
    #     f = open(path_rel, "w")
    #     f.write(str(PARAMS_DICT))
    #     f.close()

    def __init__(self, iface):
        self.iface = iface
        userPluginPath = os.path.dirname(__file__)
        systemPluginPath = QgsApplication.prefixPath(
        ) + "/python/plugins/pyarchinit"

        overrideLocale = QgsSettings().value("locale/overrideFlag",
                                             QVariant)  # .toBool()
        if not overrideLocale:
            localeFullName = QLocale.system().name()
        else:
            localeFullName = QgsSettings().value("locale/userLocale",
                                                 QVariant)  # .toString()

        if QFileInfo(userPluginPath).exists():
            translationPath = userPluginPath + "/i18n/pyarchinit_plugin_" + localeFullName + ".qm"
        else:
            translationPath = systemPluginPath + "/i18n/pyarchinit_plugin_" + localeFullName + ".qm"

        self.localePath = translationPath
        if QFileInfo(self.localePath).exists():
            self.translator = QTranslator()
            self.translator.load(self.localePath)
            QCoreApplication.installTranslator(self.translator)

    def initGui(self):
        settings = QgsSettings()
        icon_paius = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons', 'pai_us.png'))
        self.action = QAction(QIcon(icon_paius), "pyArchInit Main Panel",
                              self.iface.mainWindow())
        self.action.triggered.connect(self.showHideDockWidget)

        # dock widget
        self.dockWidget = PyarchinitPluginDialog(self.iface)
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockWidget)

        # TOOLBAR
        self.toolBar = self.iface.addToolBar("pyArchInit")
        self.toolBar.setObjectName("pyArchInit")
        self.toolBar.addAction(self.action)

        self.dataToolButton = QToolButton(self.toolBar)
        self.dataToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        ######  Section dedicated to the basic data entry
        # add Actions data
        icon_site = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconSite.png'))
        self.actionSite = QAction(QIcon(icon_site), "Siti",
                                  self.iface.mainWindow())
        self.actionSite.setWhatsThis("Siti")
        self.actionSite.triggered.connect(self.runSite)

        icon_US = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconSus.png'))
        self.actionUS = QAction(QIcon((icon_US)), u"US",
                                self.iface.mainWindow())
        self.actionUS.setWhatsThis(u"US")
        self.actionUS.triggered.connect(self.runUS)

        icon_Finds = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'iconFinds.png'))
        self.actionInr = QAction(QIcon(icon_Finds), "Reperti",
                                 self.iface.mainWindow())
        self.actionInr.setWhatsThis("Reperti")
        self.actionInr.triggered.connect(self.runInr)

        icon_camp_exp = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'champion.png'))
        self.actionCampioni = QAction(QIcon(icon_camp_exp), "Campioni",
                                      self.iface.mainWindow())
        self.actionCampioni.setWhatsThis("Campioni")
        self.actionCampioni.triggered.connect(self.runCampioni)

        icon_Lapidei = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconAlma.png'))
        self.actionLapidei = QAction(QIcon(icon_Lapidei), "Lapidei",
                                     self.iface.mainWindow())
        self.actionLapidei.setWhatsThis("Lapidei")
        self.actionLapidei.triggered.connect(self.runLapidei)

        self.dataToolButton.addActions([
            self.actionSite, self.actionUS, self.actionInr,
            self.actionCampioni, self.actionLapidei
        ])
        self.dataToolButton.setDefaultAction(self.actionSite)

        self.toolBar.addWidget(self.dataToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the interpretations
        # add Actions interpretation
        self.interprToolButton = QToolButton(self.toolBar)
        self.interprToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_per = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconPer.png'))
        self.actionPer = QAction(QIcon(icon_per), "Periodizzazione",
                                 self.iface.mainWindow())
        self.actionPer.setWhatsThis("Periodizzazione")
        self.actionPer.triggered.connect(self.runPer)

        icon_Struttura = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'iconStrutt.png'))
        self.actionStruttura = QAction(QIcon(icon_Struttura), "Strutture",
                                       self.iface.mainWindow())
        self.actionPer.setWhatsThis("Strutture")
        self.actionStruttura.triggered.connect(self.runStruttura)

        self.interprToolButton.addActions(
            [self.actionStruttura, self.actionPer])
        self.interprToolButton.setDefaultAction(self.actionStruttura)

        self.toolBar.addWidget(self.interprToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the funerary archaeology
        # add Actions funerary archaeology
        self.funeraryToolButton = QToolButton(self.toolBar)
        self.funeraryToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_Schedaind = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconIND.png'))
        self.actionSchedaind = QAction(QIcon(icon_Schedaind), "Individui",
                                       self.iface.mainWindow())
        self.actionSchedaind.setWhatsThis("Individui")
        self.actionSchedaind.triggered.connect(self.runSchedaind)

        icon_Tafonomia = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'iconGrave.png'))
        self.actionTafonomia = QAction(QIcon(icon_Tafonomia),
                                       "Tafonomica/Sepolture",
                                       self.iface.mainWindow())
        self.actionTafonomia.setWhatsThis("Tafonomica/Sepolture")
        self.actionTafonomia.triggered.connect(self.runTafonomia)

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            icon_Detsesso = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'iconSesso.png'))
            self.actionDetsesso = QAction(QIcon(icon_Detsesso),
                                          "Determinazione Sesso",
                                          self.iface.mainWindow())
            self.actionDetsesso.setWhatsThis("Determinazione del sesso")
            self.actionDetsesso.triggered.connect(self.runDetsesso)

            icon_Deteta = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'iconEta.png'))
            self.actionDeteta = QAction(QIcon(icon_Deteta),
                                        u"Determinazione dell'età",
                                        self.iface.mainWindow())
            self.actionSchedaind.setWhatsThis(u"Determinazione dell'età")
            self.actionDeteta.triggered.connect(self.runDeteta)

        self.funeraryToolButton.addActions(
            [self.actionSchedaind, self.actionTafonomia])
        self.funeraryToolButton.setDefaultAction(self.actionSchedaind)

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.funeraryToolButton.addActions(
                [self.actionDetsesso, self.actionDeteta])

        self.toolBar.addWidget(self.funeraryToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to the topographical research
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.topoToolButton = QToolButton(self.toolBar)
            self.topoToolButton.setPopupMode(QToolButton.MenuButtonPopup)

            icon_UT = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'iconUT.png'))
            self.actionUT = QAction(QIcon(icon_UT), u"Unità Topografiche",
                                    self.iface.mainWindow())
            self.actionUT.setWhatsThis(u"Unità Topografiche")
            self.actionUT.triggered.connect(self.runUT)

            self.topoToolButton.addActions([self.actionUT])
            self.topoToolButton.setDefaultAction(self.actionUT)

            self.toolBar.addWidget(self.topoToolButton)

            self.toolBar.addSeparator()

        ######  Section dedicated to the documentation
        # add Actions documentation
        self.docToolButton = QToolButton(self.toolBar)
        self.docToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_documentazione = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'icondoc.png'))
        self.actionDocumentazione = QAction(QIcon(icon_documentazione),
                                            "Scheda Documentazione",
                                            self.iface.mainWindow())
        self.actionDocumentazione.setWhatsThis("Documentazione")
        self.actionDocumentazione.triggered.connect(self.runDocumentazione)

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            icon_imageViewer = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'photo.png'))
            self.actionimageViewer = QAction(QIcon(icon_imageViewer),
                                             "Gestione immagini",
                                             self.iface.mainWindow())
            self.actionimageViewer.setWhatsThis("Gestione immagini")
            self.actionimageViewer.triggered.connect(self.runImageViewer)

            icon_Directory_export = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'directoryExp.png'))
            self.actionImages_Directory_export = QAction(
                QIcon(icon_Directory_export), "Esportazione immagini",
                self.iface.mainWindow())
            self.actionImages_Directory_export.setWhatsThis(
                "Esportazione immagini")
            self.actionImages_Directory_export.triggered.connect(
                self.runImages_directory_export)

            icon_pdf_exp = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'pdf-icon.png'))
            self.actionpdfExp = QAction(QIcon(icon_pdf_exp),
                                        "Esportazione PDF",
                                        self.iface.mainWindow())
            self.actionpdfExp.setWhatsThis("Esportazione PDF")
            self.actionpdfExp.triggered.connect(self.runPdfexp)

        self.docToolButton.addActions([self.actionDocumentazione])

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.docToolButton.addActions([
                self.actionpdfExp, self.actionimageViewer, self.actionpdfExp,
                self.actionImages_Directory_export
            ])

        self.docToolButton.setDefaultAction(self.actionDocumentazione)

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.actionImages_Directory_export.setCheckable(True)
            self.actionpdfExp.setCheckable(True)
            self.actionimageViewer.setCheckable(True)

        self.toolBar.addWidget(self.docToolButton)

        self.toolBar.addSeparator()

        ######  Section dedicated to elaborations
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.elabToolButton = QToolButton(self.toolBar)
            self.elabToolButton.setPopupMode(QToolButton.MenuButtonPopup)

            # add Actions elaboration
            icon_Archeozoology = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'iconMegacero.png'))
            self.actionArcheozoology = QAction(QIcon(icon_Archeozoology),
                                               "Statistiche Archeozoologiche",
                                               self.iface.mainWindow())
            self.actionArcheozoology.setWhatsThis(
                "Statistiche Archeozoologiche")
            self.actionArcheozoology.triggered.connect(self.runArcheozoology)

            icon_GisTimeController = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons',
                             'iconTimeControll.png'))
            self.actionGisTimeController = QAction(
                QIcon(icon_GisTimeController), "Time Manager",
                self.iface.mainWindow())
            self.actionGisTimeController.setWhatsThis("Time Manager")
            self.actionGisTimeController.triggered.connect(
                self.runGisTimeController)

            icon_Comparision = '{}{}'.format(
                filepath,
                os.path.join(os.sep, 'resources', 'icons', 'comparision.png'))
            self.actionComparision = QAction(QIcon(icon_Comparision),
                                             "Comparazione immagini",
                                             self.iface.mainWindow())
            self.actionComparision.setWhatsThis("Comparazione immagini")
            self.actionComparision.triggered.connect(self.runComparision)

            self.elabToolButton.addActions([
                self.actionArcheozoology, self.actionComparision,
                self.actionGisTimeController
            ])
            self.elabToolButton.setDefaultAction(self.actionArcheozoology)

            self.toolBar.addWidget(self.elabToolButton)

            self.toolBar.addSeparator()

        ######  Section dedicated to the plugin management

        self.manageToolButton = QToolButton(self.toolBar)
        self.manageToolButton.setPopupMode(QToolButton.MenuButtonPopup)

        icon_thesaurus = '{}{}'.format(
            filepath,
            os.path.join(os.sep, 'resources', 'icons', 'thesaurusicon.png'))
        self.actionThesaurus = QAction(QIcon(icon_thesaurus),
                                       "Thesaurus sigle",
                                       self.iface.mainWindow())
        self.actionThesaurus.setWhatsThis("Thesaurus sigle")
        self.actionThesaurus.triggered.connect(self.runThesaurus)

        icon_Con = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconConn.png'))
        self.actionConf = QAction(QIcon(icon_Con), "Configurazione plugin",
                                  self.iface.mainWindow())
        self.actionConf.setWhatsThis("Configurazione plugin")
        self.actionConf.triggered.connect(self.runConf)

        icon_Dbmanagment = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons', 'backup.png'))
        self.actionDbmanagment = QAction(QIcon(icon_Dbmanagment),
                                         "Gestione database",
                                         self.iface.mainWindow())
        self.actionDbmanagment.setWhatsThis("Gestione database")
        self.actionDbmanagment.triggered.connect(self.runDbmanagment)

        icon_Info = '{}{}'.format(
            filepath, os.path.join(os.sep, 'resources', 'icons',
                                   'iconInfo.png'))
        self.actionInfo = QAction(QIcon(icon_Info), "Plugin info",
                                  self.iface.mainWindow())
        self.actionInfo.setWhatsThis("Plugin info")
        self.actionInfo.triggered.connect(self.runInfo)

        self.manageToolButton.addActions([
            self.actionConf, self.actionThesaurus, self.actionDbmanagment,
            self.actionInfo
        ])
        self.manageToolButton.setDefaultAction(self.actionConf)

        self.toolBar.addWidget(self.manageToolButton)

        self.toolBar.addSeparator()

        # menu
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionSite)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionUS)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionInr)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionCampioni)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionLapidei)

        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionStruttura)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionPer)

        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionSchedaind)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionTafonomia)

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionDetsesso)
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionDeteta)
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionUT)

        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionDocumentazione)

        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionimageViewer)
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionpdfExp)
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionImages_Directory_export)

            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionArcheozoology)
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionComparision)
            self.iface.addPluginToMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionGisTimeController)

        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionConf)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionThesaurus)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionDbmanagment)
        self.iface.addPluginToMenu("&pyArchInit - Archaeological GIS Tools",
                                   self.actionInfo)

        # MENU
        self.menu = QMenu("pyArchInit")
        # self.pyarchinitSite = pyarchinit_Site(self.iface)
        self.menu.addActions([
            self.actionSite, self.actionUS, self.actionInr,
            self.actionCampioni, self.actionLapidei
        ])
        self.menu.addSeparator()
        self.menu.addActions([self.actionPer, self.actionStruttura])
        self.menu.addSeparator()
        self.menu.addActions([self.actionTafonomia, self.actionSchedaind])
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.menu.addActions([self.actionDetsesso, self.actionDeteta])
        self.menu.addSeparator()
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.menu.addActions([self.actionUT])
        self.menu.addActions([self.actionDocumentazione])
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.menu.addActions([
                self.actionimageViewer, self.actionpdfExp,
                self.actionImages_Directory_export
            ])
        self.menu.addSeparator()
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.menu.addActions([
                self.actionArcheozoology, self.actionComparision,
                self.actionGisTimeController
            ])
        self.menu.addSeparator()
        self.menu.addActions([
            self.actionConf, self.actionThesaurus, self.actionDbmanagment,
            self.actionInfo
        ])
        menuBar = self.iface.mainWindow().menuBar()
        menuBar.addMenu(self.menu)

    ##
    def runSite(self):
        pluginGui = pyarchinit_Site(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runPer(self):
        pluginGui = pyarchinit_Periodizzazione(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runStruttura(self):
        pluginGui = pyarchinit_Struttura(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runUS(self):
        pluginGui = pyarchinit_US(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runInr(self):
        pluginGui = pyarchinit_Inventario_reperti(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runCampioni(self):
        pluginGui = pyarchinit_Campioni(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runLapidei(self):
        pluginGui = pyarchinit_Inventario_Lapidei(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runGisTimeController(self):
        pluginGui = pyarchinit_Gis_Time_Controller(self.iface)
        pluginGui.show()
        self.pluginGui = pluginGui  # save

    def runConf(self):
        pluginConfGui = pyArchInitDialog_Config()
        pluginConfGui.show()
        self.pluginGui = pluginConfGui  # save

    def runInfo(self):
        pluginInfoGui = pyArchInitDialog_Info()
        pluginInfoGui.show()
        self.pluginGui = pluginInfoGui  # save

    def runImageViewer(self):
        pluginImageView = Main()
        pluginImageView.show()
        self.pluginGui = pluginImageView  # save

    def runTafonomia(self):
        pluginTafonomia = pyarchinit_Tafonomia(self.iface)
        pluginTafonomia.show()
        self.pluginGui = pluginTafonomia  # save

    def runSchedaind(self):
        pluginIndividui = pyarchinit_Schedaind(self.iface)
        pluginIndividui.show()
        self.pluginGui = pluginIndividui  # save

    def runDetsesso(self):
        pluginSesso = pyarchinit_Detsesso(self.iface)
        pluginSesso.show()
        self.pluginGui = pluginSesso  # save

    def runDeteta(self):
        pluginEta = pyarchinit_Deteta(self.iface)
        pluginEta.show()
        self.pluginGui = pluginEta  # save

    def runArcheozoology(self):
        pluginArchezoology = pyarchinit_Archeozoology(self.iface)
        pluginArchezoology.show()
        self.pluginGui = pluginArchezoology  # save

    def runUT(self):
        pluginUT = pyarchinit_UT(self.iface)
        pluginUT.show()
        self.pluginGui = pluginUT  # save

    def runImages_directory_export(self):
        pluginImage_directory_export = pyarchinit_Images_directory_export()
        pluginImage_directory_export.show()
        self.pluginGui = pluginImage_directory_export  # save

    def runComparision(self):
        pluginComparision = Comparision()
        pluginComparision.show()
        self.pluginGui = pluginComparision  # save

    def runDbmanagment(self):
        pluginDbmanagment = pyarchinit_dbmanagment(self.iface)
        pluginDbmanagment.show()
        self.pluginGui = pluginDbmanagment  # save

    def runPdfexp(self):
        pluginPdfexp = pyarchinit_pdf_export(self.iface)
        pluginPdfexp.show()
        self.pluginGui = pluginPdfexp  # save

    def runThesaurus(self):
        pluginThesaurus = pyarchinit_Thesaurus(self.iface)
        pluginThesaurus.show()
        self.pluginGui = pluginThesaurus  # save

    def runDocumentazione(self):
        pluginDocumentazione = pyarchinit_Documentazione(self.iface)
        pluginDocumentazione.show()
        self.pluginGui = pluginDocumentazione  # save

    def unload(self):
        # Remove the plugin
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionSite)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionPer)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionStruttura)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionUS)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionInr)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionCampioni)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionLapidei)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionSchedaind)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionTafonomia)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionDocumentazione)
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionDetsesso)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionDeteta)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionTafonomia)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionArcheozoology)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionUT)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionimageViewer)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionImages_Directory_export)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools", self.actionpdfExp)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionComparision)
            self.iface.removePluginMenu(
                "&pyArchInit - Archaeological GIS Tools",
                self.actionGisTimeController)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionConf)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionThesaurus)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionInfo)
        self.iface.removePluginMenu("&pyArchInit - Archaeological GIS Tools",
                                    self.actionDbmanagment)

        self.iface.removeToolBarIcon(self.actionSite)
        self.iface.removeToolBarIcon(self.actionPer)
        self.iface.removeToolBarIcon(self.actionStruttura)
        self.iface.removeToolBarIcon(self.actionUS)
        self.iface.removeToolBarIcon(self.actionInr)
        self.iface.removeToolBarIcon(self.actionCampioni)
        self.iface.removeToolBarIcon(self.actionLapidei)
        self.iface.removeToolBarIcon(self.actionTafonomia)
        self.iface.removeToolBarIcon(self.actionSchedaind)
        self.iface.removeToolBarIcon(self.actionDocumentazione)
        if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si':
            self.iface.removeToolBarIcon(self.actionDetsesso)
            self.iface.removeToolBarIcon(self.actionDeteta)
            self.iface.removeToolBarIcon(self.actionArcheozoology)
            self.iface.removeToolBarIcon(self.actionUT)
            # self.iface.removeToolBarIcon(self.actionUpd)
            self.iface.removeToolBarIcon(self.actionimageViewer)
            self.iface.removeToolBarIcon(self.actionImages_Directory_export)
            self.iface.removeToolBarIcon(self.actionpdfExp)
            self.iface.removeToolBarIcon(self.actionComparision)
            self.iface.removeToolBarIcon(self.actionGisTimeController)
        self.iface.removeToolBarIcon(self.actionConf)
        self.iface.removeToolBarIcon(self.actionThesaurus)
        self.iface.removeToolBarIcon(self.actionInfo)
        self.iface.removeToolBarIcon(self.actionDbmanagment)

        self.dockWidget.setVisible(False)
        self.iface.removeDockWidget(self.dockWidget)

        # remove tool bar
        del self.toolBar

    def showHideDockWidget(self):
        if self.dockWidget.isVisible():
            self.dockWidget.hide()
        else:
            self.dockWidget.show()
Example #30
0
class AffineUI:

    def __init__(self, iface):
        self.ui = uic.loadUi(self.here / "ui.ui")
        self.iface = iface
        self.affine_namespace = Affine(self.ui)

    @property
    def here(self):
        return pathlib.Path(__file__).parent

    @property
    def project(self):
        return QgsProject.instance()

    def initGui(self):
        icon = QIcon(str(self.here / "icon.svg"))
        self.action = QAction(icon, "Affine Transformation...", self.iface.mainWindow())
        self.action.setWhatsThis("Configuration for test plugin")
        self.action.triggered.connect(self.run)
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToVectorMenu("&Geoprocessing Tools", self.action)

        self.ui.pushButtonRun.clicked.connect(self.affine)
        self.ui.pushButtonInvert.clicked.connect(self.invert)
        self.ui.pushButtonClose.clicked.connect(self.finish)

    def unload(self):
        self.iface.removePluginVectorMenu("&Geoprocessing Tools", self.action)
        self.iface.removeToolBarIcon(self.action)

    def run(self):
        self.ui.comboBoxLayer.clear()
        for name, layer in self.project.mapLayers().items():
            if layer.type() == 0:
                self.ui.comboBoxLayer.addItem(name)
        self.ui.show()

    def affine(self):
        warn = QgsMessageViewer()
        layer_name = self.ui.comboBoxLayer.currentText()
        vlayer = self.project.mapLayers().get(layer_name)
        if vlayer is None:
            warn.setMessageAsPlainText("Select a layer to transform")
            warn.showMessage()
            return
        if not vlayer.isEditable():
            warn.setMessageAsPlainText("Layer not in edit mode")
            warn.showMessage()
            return
        if self.ui.radioButtonWholeLayer.isChecked():
            vlayer.selectAll()
        if vlayer.geometryType() == QgsWkbTypes.PolygonGeometry:
            start = 1
        else:
            start = 0
        v = self.affine_namespace
        for fid in vlayer.selectedFeatureIds():
            feature = vlayer.getFeature(fid)
            geometry = feature.geometry()
            for i in itertools.count(start=start):
                vertex = geometry.vertexAt(i)
                if vertex == QgsPoint(0, 0):
                    break
                # matrix form: x' = A x + b
                # x' = a x + b y + tx
                # y' = c x + d y + ty
                newx = v.a * vertex.x() + v.b * vertex.y() + v.tx
                newy = v.c * vertex.x() + v.d * vertex.y() + v.ty
                vlayer.moveVertex(newx, newy, fid, i)
        if self.ui.checkBoxZoomToLayer.isChecked():
            self.iface.mapCanvas().zoomToSelected()

    def invert(self):
        # matrix form: x' = A x + b
        # --> x = A^-1 x' - A^-1 b
        # A^-1 = [d -b; -c a] / det A
        # only valid if det A = a d - b c != 0
        v = self.affine_namespace
        det = v.a * v.d - v.b * v.c
        if det == 0:
            warn = QgsMessageViewer()
            warn.setMessageAsPlainText("Transformation is not invertable")
            warn.showMessage()
            return
        v.a, v.b, v.c, v.d = v.d / det, -v.b / det, -v.c / det, v.a / det
        v.tx, v.ty = -v.a * v.tx - v.b * v.ty, -v.c * v.tx - v.d * v.ty

    def finish(self):
        self.ui.close()
    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 InaSAFE 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.addPluginToVectorMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action
class midv_tolkn:
    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(QFile.decodeName(__file__))
        self.db = None

    def initGui(self):
        # Create actions
        icon = QIcon(os.path.join(self.plugin_dir, "icons", "midv_tolkn.png"))

        self.actionloadthelayers = QAction(
            QIcon(
                os.path.join(self.plugin_dir, 'icons',
                             'load_layers_domains.png')),
            "Ladda tolkningslager t QGIS", self.iface.mainWindow())
        self.actionloadthelayers.setWhatsThis(
            "Laddar tolkningslager för gvmagasin m.m. till QGIS")
        self.actionloadthelayers.triggered.connect(
            lambda x: self.load_the_layers())

        self.actionNewDB = QAction(
            QIcon(os.path.join(self.plugin_dir, 'icons', 'create_new.png')),
            "Skapa en ny tolkningsdatabas", self.iface.mainWindow())
        self.actionNewDB.triggered.connect(lambda x: self.new_db())

        self.actionVacuumDB = QAction(
            QIcon(os.path.join(self.plugin_dir, 'icons', 'vacuum.png')),
            "Packa (vacuum) tolkn-db", self.iface.mainWindow())
        self.actionVacuumDB.setWhatsThis("Perform database vacuuming")
        self.actionVacuumDB.triggered.connect(lambda x: self.vacuum_db())

        self.actionZipDB = QAction(
            QIcon(os.path.join(self.plugin_dir, 'icons', 'zip.png')),
            "Backup av tolknings-databas", self.iface.mainWindow())
        self.actionZipDB.setWhatsThis(
            "En komprimerad zip-fil kommer att skapas i samma dir som tolknings-databasen."
        )
        self.actionZipDB.triggered.connect(lambda x: self.zip_db())

        self.actionUpgradeDB = QAction(
            QIcon(os.path.join(self.plugin_dir, 'icons', 'create_new.png')),
            "Uppgradera tolknings-databas", self.iface.mainWindow())
        self.actionUpgradeDB.setWhatsThis(
            "Uppgradera en befintlig tolknings-databas till ny databas-struktur."
        )
        self.actionUpgradeDB.triggered.connect(lambda x: self.upgrade_db())

        #self.actionabout = QAction(QIcon(":/plugins/midv_tolkn/icons/about.png"), "Information", self.iface.mainWindow())
        #self.actionabout.triggered.connect(lambda x: self.about)

        # Add button
        self.iface.addToolBarIcon(self.actionloadthelayers)

        # Add plugins menu items
        self.midv_menu = None  # Midvatten-plugin-menyn
        self.menu = None  # sub-menyn "Tolkningar"

        # Check if Midvatten-menyn existerar och get it
        for child in self.iface.mainWindow().menuBar().children():
            if isinstance(child, QMenu):
                if child.title() == "Midvatten":  # Put here your menu name
                    self.midv_menu = child

        # If the Midvatten menu does not exist, create it!
        self.owns_midv_menu = False  #indicator that this plugin must not clean up the midvatten menu
        if not self.midv_menu:
            self.owns_midv_menu = True  #indicator that this plugin must clean up the midvatten menu
            self.midv_menu = QMenu("Midvatten",
                                   self.iface.mainWindow().menuBar())
            menuBar = self.iface.mainWindow().menuBar()
            menuBar.addMenu(self.midv_menu)

        # check if there is a sub-menu Tolkningar
        for childchild in self.midv_menu.children():
            if isinstance(childchild, QMenu):
                if childchild.title(
                ) == "&Tolkningar":  # Put here your menu name
                    print('found sub-menu Tolkningar')
                    self.menu = childchild

        # If the tolkning submenu does not exist, create it
        if not self.menu:
            print('will add Tolkningar submenu')
            self.menu_separator1 = self.midv_menu.addSeparator()
            self.menu = QMenu(
                QCoreApplication.translate("Midvatten", "&Tolkningar"))
            self.midv_menu.addMenu(self.menu)
            self.menu_separator2 = self.midv_menu.addSeparator()

        self.menu.addAction(self.actionloadthelayers)
        self.menu.addAction(self.actionNewDB)
        self.menu.addAction(self.actionVacuumDB)
        self.menu.addAction(self.actionZipDB)
        self.menu.addAction(self.actionUpgradeDB)
        #self.menu.addAction(self.actionabout)

    def unload(self):
        # remove tool bar button
        self.iface.removeToolBarIcon(self.actionloadthelayers)

        # Remove the plugin menu items and icons
        try:
            self.midv_menu.removeAction(self.menu.menuAction())
            self.midv_menu.removeAction(self.menu_separator1)
            self.midv_menu.removeAction(self.menu_separator2)
        except:
            pass
        if self.owns_midv_menu:  #indicator that this plugin must clean up the midvatten menu
            menubar = self.midv_menu.parentWidget()
            menubar.removeAction(self.midv_menu.menuAction())
            self.midv_menu.deleteLater()

    def about(self):
        utils.pop_up_info(msg='This feature is not yet implemented',
                          title='Hold on...')

    def load_data_domains(self):
        #utils.pop_up_info(msg='This feature is not yet implemented',title='Hold on...')
        #return
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        err_flag = utils.verify_msettings_loaded_and_layer_edit_mode(
            qgis.utils.iface, self.ms)  #verify midv settings are loaded
        if err_flag == 0:
            conn_ok, dd_tables = utils.sql_load_fr_db(
                "select name from sqlite_master where name like 'zz_%'")
            if not conn_ok:
                return
            d_domain_tables = [str(dd_table[0]) for dd_table in dd_tables]
            err_flag = utils.verify_msettings_loaded_and_layer_edit_mode(
                qgis.utils.iface, self.ms, d_domain_tables
            )  #verify none of the tables are already loaded and in edit mode
            if err_flag == 0:
                LoadLayers(qgis.utils.iface, self.ms.settingsdict,
                           'Midvatten_data_domains')
        QApplication.restoreOverrideCursor(
        )  #now this long process is done and the cursor is back as normal

    def load_the_layers(self):
        LoadLayers(qgis.utils.iface, self.db)

    def new_db(self, set_locale=False):
        if not set_locale:
            set_locale = utils.getcurrentlocale()

        filenamepath = os.path.join(os.path.dirname(__file__), "metadata.txt")
        iniText = QSettings(filenamepath, QSettings.IniFormat)
        verno = str(iniText.value('version'))
        from .create_tolkn_db import newdb
        newdbinstance = newdb(verno, set_locale=set_locale)
        if not newdbinstance.dbpath == '':
            self.db = newdbinstance.dbpath

    def upgrade_db(self, set_locale=False):
        from_db = None
        #get full path to the original db to be updated
        if self.db:
            use_current_db = utils.Askuser(
                "YesNo", """Do you want to upgrade %s?""" % self.db,
                'Current database?')
            if use_current_db.result == 0:
                from_db = None
            elif use_current_db.result == 1:
                from_db = self.db
            elif use_current_db.result == '':
                return
        if not from_db:
            from_db = QFileDialog.getOpenFileName(
                None, 'Ange tolknings-db som ska exporteras', '',
                "Spatialite (*.sqlite)")[0]
        if not from_db:
            QApplication.restoreOverrideCursor()
            return None

        #get EPSG in the original db
        EPSG = utils.sql_load_fr_db(
            """SELECT srid FROM geom_cols_ref_sys WHERE Lower(f_table_name) = Lower('gvmag') AND Lower(f_geometry_column) = Lower('geometry')""",
            from_db)

        #preparations to create new db of new design
        if not set_locale:
            set_locale = utils.getcurrentlocale()

        filenamepath = os.path.join(os.path.dirname(__file__), "metadata.txt")
        iniText = QSettings(filenamepath, QSettings.IniFormat)
        verno = str(iniText.value('version'))

        #now create database of the updated design
        from .create_tolkn_db import newdb
        newdbinstance = newdb(verno,
                              user_select_CRS=False,
                              EPSG_code=EPSG[1][0][0],
                              set_locale=set_locale)

        #transfer data to the new database
        foo = utils.UpgradeDatabase(from_db, newdbinstance.dbpath, EPSG)

        #set new database as the current db and load these layers
        if not newdbinstance.dbpath == '':
            self.db = newdbinstance.dbpath
        self.load_the_layers()

    def vacuum_db(self):
        force_another_db = False
        if self.db:
            use_current_db = utils.Askuser("YesNo",
                                           """Vill du packa %s?""" % self.db,
                                           'Which database?')
            if use_current_db.result == 1:
                dbpath = self.db
                force_another_db = True
            elif use_current_db.result == 0:
                force_another_db = True
            elif use_current_db.result == '':
                return
        if not self.db or force_another_db:
            dbpath = QFileDialog.getOpenFileName(None,
                                                 'Ange db som ska packas', '',
                                                 "Spatialite (*.sqlite)")[0]

        QApplication.setOverrideCursor(Qt.WaitCursor)
        utils.sql_alter_db(dbpath, 'vacuum')
        QApplication.restoreOverrideCursor()

    def zip_db(self):
        force_another_db = False
        dbpath = None
        if self.db:
            use_current_db = utils.Askuser(
                "YesNo", 'Vill du göra backup av %s?' % self.db,
                'Which database?')
            if use_current_db.result == 1:
                dbpath = self.db
                force_another_db = False
            elif use_current_db.result == 0:
                force_another_db = True
            elif use_current_db.result == '':
                return
        if not self.db or force_another_db:
            dbpath = QFileDialog.getOpenFileName(
                None, 'Ange db som du vill skapa backup utav', '',
                "Spatialite (*.sqlite)")[0]

        if dbpath:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            connection = utils.dbconnection(dbpath)
            connection.connect2db()
            connection.conn.cursor().execute("begin immediate")

            file_path = os.path.realpath(dbpath)
            dir_path = os.path.dirname(file_path)
            current_dir = dir_path.split(os.sep)[-1]

            bkupname = dbpath + datetime.datetime.now().strftime(
                '%Y%m%dT%H%M') + '.zip'
            zf = zipfile.ZipFile(bkupname, mode='w')
            zf.write(dbpath,
                     os.path.basename(dbpath),
                     compress_type=compression
                     )  #compression will depend on if zlib is found or not
            zf.close()
            connection.conn.rollback()
            connection.closedb()
            self.iface.messageBar().pushMessage(
                "Information",
                "Database backup was written to " + bkupname,
                1,
                duration=15)
            QApplication.restoreOverrideCursor()
Example #33
0
class XYZHubConnector(object):
    """base plugin"""
    def __init__(self, iface):
        """init"""
        import sys
        print(sys.version)
        self.iface = iface
        self.web_menu = "&XYZ Hub Connector"
        self.init_modules()
        self.obj = self

    def initGui(self):
        """startup"""

        parent = self.iface.mainWindow()

        ######## action, button

        icon = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/xyz.png"))
        icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/bbox.svg"))
        self.action_connect = QAction(icon, "XYZ Hub Connection", parent)
        self.action_connect.setWhatsThis(
            QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message"))
        self.action_connect.setStatusTip(
            QCoreApplication.translate(PLUGIN_NAME, "status tip message"))

        self.action_sync_edit = QAction(
            QIcon("%s/%s" % (config.PLUGIN_DIR, "images/sync.svg")),
            "Push changes to XYZ Hub", parent)

        self.action_clear_cache = QAction(
            QIcon("%s/%s" % (config.PLUGIN_DIR, "images/delete.svg")),
            "Clear cache", parent)

        # self.action_sync_edit.setVisible(False) # disable magic sync
        self.edit_buffer.config_ui(self.enable_sync_btn)

        self.cb_layer_selected(self.iface.activeLayer())

        ######## CONNECT action, button

        self.action_connect.triggered.connect(self.open_connection_dialog)
        self.action_sync_edit.triggered.connect(self.open_sync_edit_dialog)
        self.action_clear_cache.triggered.connect(self.open_clear_cache_dialog)

        ######## Add the toolbar + button
        self.toolbar = self.iface.addToolBar(PLUGIN_NAME)
        self.toolbar.setObjectName("XYZ Hub Connector")

        self.actions_menu = [
            self.action_connect, self.action_sync_edit, self.action_clear_cache
        ]

        for a in [self.action_connect, self.action_sync_edit]:
            self.toolbar.addAction(a)

        for a in self.actions_menu:
            self.iface.addPluginToWebMenu(self.web_menu, a)

        # # uncomment to use menu button
        # tool_btn = QToolButton(self.toolbar)
        # tool_btn.setDefaultAction(self.action_connect)
        # tool_btn.setPopupMode(tool_btn.MenuButtonPopup)
        # self.xyz_widget_action = self.toolbar.addWidget(tool_btn) # uncomment to use menu button

        # self.toolbar.addAction(self.action_connect)

        self.action_help = None

        progress = QProgressBar()
        progress.setMinimum(0)
        progress.setMaximum(0)
        progress.reset()
        progress.hide()
        # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis
        self.iface.statusBarIface().addPermanentWidget(progress)
        self.pb = progress

    def init_modules(self):
        if LOG_TO_FILE:
            QgsApplication.messageLog().messageReceived.connect(
                cb_log_qgis)  #, Qt.QueuedConnection

        # util.init_module()

        # parent = self.iface.mainWindow()
        parent = QgsProject.instance()

        self.secret = Secret(config.USER_PLUGIN_DIR + "/secret.ini")
        ######## Init xyz modules
        self.map_basemap_meta = basemap.load_default_xml()
        self.auth_manager = AuthManager(config.USER_PLUGIN_DIR + "/auth.ini")

        self.token_model = GroupTokenModel(parent)

        self.network = NetManager(parent)

        self.con_man = LoaderManager()
        self.con_man.config(self.network)
        self.edit_buffer = EditBuffer()
        ######## data flow
        # self.conn_info = SpaceConnectionInfo()

        ######## token
        self.token_model.load_ini(config.USER_PLUGIN_DIR + "/token.ini")

        ######## CALLBACK

        self.con_man.ld_pool.signal.progress.connect(
            self.cb_progress_busy)  #, Qt.QueuedConnection
        self.con_man.ld_pool.signal.finished.connect(self.cb_progress_done)

        QgsProject.instance().layersWillBeRemoved["QStringList"].connect(
            self.edit_buffer.remove_layers)
        # QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.layer_man.remove_layers)

        # QgsProject.instance().layersAdded.connect( self.edit_buffer.config_connection)

        self.iface.currentLayerChanged.connect(
            self.cb_layer_selected)  # UNCOMMENT

        self.iface.mapCanvas().extentsChanged.connect(self.reload_tile,
                                                      Qt.QueuedConnection)

        QgsProject.instance().readProject.connect(self.import_project)
        self.import_project()

    def unload_modules(self):
        # self.con_man.disconnect_ux( self.iface)
        QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect(
            self.edit_buffer.remove_layers)
        # QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.layer_man.remove_layers)

        # QgsProject.instance().layersAdded.disconnect( self.edit_buffer.config_connection)
        self.edit_buffer.unload_connection()

        self.iface.currentLayerChanged.disconnect(
            self.cb_layer_selected)  # UNCOMMENT

        self.iface.mapCanvas().extentsChanged.disconnect(self.reload_tile)

        # utils.disconnect_silent(self.iface.currentLayerChanged)

        self.secret.deactivate()

        if LOG_TO_FILE:
            QgsApplication.messageLog().messageReceived.disconnect(cb_log_qgis)
        # close_file_logger()
        pass

    def unload(self):
        """teardown"""
        self.unload_modules()
        # remove the plugin menu item and icon
        self.iface.removePluginWebMenu(self.web_menu, self.action_help)

        self.toolbar.clear(
        )  # remove action from custom toolbar (toolbar still exist)
        self.toolbar.deleteLater()

        for a in self.actions_menu:
            self.iface.removePluginWebMenu(self.web_menu, a)
        # remove progress
        self.iface.statusBarIface().removeWidget(self.pb)

    ###############
    # Callback
    ###############
    def cb_layer_selected(self, qlayer):
        flag_xyz = True if qlayer is not None and is_xyz_supported_layer(
            qlayer) else False
        if flag_xyz:
            self.edit_buffer.config_connection([qlayer])
            self.edit_buffer.enable_ui(qlayer.id())
        else:
            msg = "No XYZHub Layer selected"
            self.enable_sync_btn(False, msg)
        # disable magic sync
        # self.action_sync_edit.setEnabled(flag_xyz)
    def enable_sync_btn(self, flag, msg=""):
        msg = msg or ("No changes detected since last push"
                      if not flag else "Push changes")
        self.action_sync_edit.setToolTip(msg)
        self.action_sync_edit.setEnabled(flag)

    ###############
    # Callback of action (main function)
    ###############
    def cb_success_msg(self, title, msg="", dt=5):
        self.iface.messageBar().pushMessage(config.TAG_PLUGIN,
                                            ": ".join([title,
                                                       msg]), Qgis.Success, dt)

    def make_cb_success(self, title, msg="", dt=5):
        def _cb_success_msg():
            self.cb_success_msg(title, msg, dt=dt)

        return _cb_success_msg

    def make_cb_success_args(self, title, msg="", dt=5):
        def _cb_success_msg(args):
            a, kw = parse_qt_args(args)
            txt = ". ".join(map(str, a))
            self.cb_success_msg(title, txt, dt=dt)

        return _cb_success_msg

    def cb_handle_error_msg(self, e):
        err = parse_exception_obj(e)
        if isinstance(err, ChainInterrupt):
            e0, idx = err.args[0:2]
        else:
            e0 = err
        if isinstance(e0,
                      (net_handler.NetworkError, net_handler.NetworkTimeout)):
            ok = self.show_net_err(e0)
            if ok: return
        elif isinstance(e0, EmptyXYZSpaceError):
            ret = exec_warning_dialog("XYZ Hub",
                                      "Requested query returns no features")
            return
        self.show_err_msgbar(err)

    def show_net_err(self, err):
        reply_tag, status, reason, body, err_str, url = err.args[:6]
        if reply_tag in ["count", "statistics"]:  # too many error
            # msg = "Network Error: %s: %s. %s"%(status, reason, err_str)
            return 1

        detail = "\n".join(["Request:", url, "", "Response:", body])
        msg = ("%s: %s\n" % (status, reason) +
               "There was a problem connecting to the server")
        if status in [401, 403]:
            msg += (
                "\n\n" + "Please input valid token with correct permissions." +
                "\n" + "Token is generated via " +
                "<a href='https://xyz.api.here.com/token-ui/'>https://xyz.api.here.com/token-ui/</a>"
            )
        ret = exec_warning_dialog("Network Error", msg, detail)
        return 1

    def show_err_msgbar(self, err):
        self.iface.messageBar().pushMessage("Error", repr(err), Qgis.Warning,
                                            3)
        msg = format_traceback(err)
        QgsMessageLog.logMessage(msg, config.TAG_PLUGIN, Qgis.Warning)

    def cb_progress_busy(self, n_active):
        if n_active > 1: return
        self.flag_pb_show = True
        self.cb_progress_refresh()

    def cb_progress_done(self):
        self.flag_pb_show = False
        self.cb_progress_refresh()

    def cb_progress_refresh(self):
        if not hasattr(self, "flag_pb_show"): return

        pb = self.pb
        if self.flag_pb_show:
            pb.show()
            # print_qgis("show",pb)
        else:
            pb.hide()
            # print_qgis("hide")

    ###############
    # Action (main function)
    ###############

    # UNUSED
    def refresh_canvas(self):
        # self.iface.activeLayer().triggerRepaint()
        self.iface.mapCanvas().refresh()

    def previous_canvas_extent(self):
        self.iface.mapCanvas().zoomToPreviousExtent()

    #

    def new_main_dialog(self):
        parent = self.iface.mainWindow()
        dialog = MainDialog(parent)

        dialog.config(self.token_model)
        dialog.config_secret(self.secret)
        auth = self.auth_manager.get_auth()
        dialog.config_basemap(self.map_basemap_meta, auth)

        con = self.con_man.make_con("create")
        con.signal.finished.connect(
            dialog.btn_use.clicked.emit)  # can be optimized !!
        con.signal.error.connect(self.cb_handle_error_msg)

        con = self.con_man.make_con("list")
        con.signal.results.connect(make_fun_args(dialog.cb_display_spaces))
        con.signal.error.connect(self.cb_handle_error_msg)
        con.signal.error.connect(lambda e: dialog.cb_enable_token_ui())
        con.signal.finished.connect(dialog.cb_enable_token_ui)

        con = self.con_man.make_con("edit")
        con.signal.finished.connect(dialog.btn_use.clicked.emit)
        con.signal.error.connect(self.cb_handle_error_msg)

        con = self.con_man.make_con("delete")
        con.signal.results.connect(dialog.btn_use.clicked.emit)
        con.signal.error.connect(self.cb_handle_error_msg)

        con = self.con_man.make_con("stat")
        con.signal.results.connect(make_fun_args(
            dialog.cb_display_space_count))
        con.signal.error.connect(self.cb_handle_error_msg)

        ############ clear cache btn
        dialog.signal_clear_cache.connect(self.open_clear_cache_dialog)

        ############ add map tile btn
        dialog.signal_add_basemap.connect(self.add_basemap_layer)

        ############ btn: new, edit, delete space
        dialog.signal_new_space.connect(self.start_new_space)
        dialog.signal_edit_space.connect(self.start_edit_space)
        dialog.signal_del_space.connect(self.start_delete_space)

        ############ Use Token btn
        dialog.signal_use_token.connect(lambda a: self.con_man.finish_fast())
        dialog.signal_use_token.connect(self.start_use_token)

        ############ get count
        dialog.signal_space_count.connect(
            self.start_count_feat,
            Qt.QueuedConnection)  # queued -> non-blocking ui

        ############ connect btn
        dialog.signal_space_connect.connect(self.start_load_layer)
        dialog.signal_space_tile.connect(self.start_load_tile)

        ############ upload btn
        dialog.signal_upload_space.connect(self.start_upload_space)

        return dialog

    def start_new_space(self, args):
        con = self.con_man.get_con("create")
        con.start_args(args)

    def start_edit_space(self, args):
        con = self.con_man.get_con("edit")
        con.start_args(args)

    def start_delete_space(self, args):
        con = self.con_man.get_con("delete")
        con.start_args(args)

    def start_use_token(self, args):
        con = self.con_man.get_con("list")
        con.start_args(args)

    def start_count_feat(self, args):
        con = self.con_man.get_con("stat")
        con.start_args(args)

    def start_upload_space(self, args):
        con_upload = UploadLayerController(self.network, n_parallel=2)
        self.con_man.add_background(con_upload)
        # con_upload.signal.finished.connect( self.make_cb_success("Uploading finish") )
        con_upload.signal.results.connect(
            self.make_cb_success_args("Uploading finish"))
        con_upload.signal.error.connect(self.cb_handle_error_msg)

        con = InitUploadLayerController(self.network)
        self.con_man.add_background(con)

        con.signal.results.connect(con_upload.start_args)
        con.signal.error.connect(self.cb_handle_error_msg)

        con.start_args(args)

    def start_load_layer(self, args):
        # create new con
        # config
        # run

        ############ connect btn
        con_load = LoadLayerController(self.network, n_parallel=1)
        self.con_man.add_background(con_load)
        # con_load.signal.finished.connect( self.make_cb_success("Loading finish") )
        con_load.signal.results.connect(
            self.make_cb_success_args("Loading finish"))
        # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_load.signal.error.connect(self.cb_handle_error_msg)

        con_load.start_args(args)

        # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT
    def start_load_tile(self, args):
        canvas = self.iface.mapCanvas()
        rect = bbox_utils.extend_to_rect(bbox_utils.get_bounding_box(canvas))
        level = tile_utils.get_zoom_for_current_map_scale(canvas)
        # rect = (-180,-90,180,90)
        # level = 0
        a, kw = parse_qt_args(args)

        kw["tile_schema"] = "here"
        kw["tile_ids"] = tile_utils.bboxToListColRow(*rect, level)
        # kw["limit"] = 100

        ############ connect btn
        con_load = TileLayerLoader(self.network, n_parallel=1)
        self.con_man.add_layer(con_load)
        # con_load.signal.finished.connect( self.make_cb_success("Tiles loaded") )
        con_load.signal.results.connect(
            self.make_cb_success_args("Tiles loaded", dt=2))
        # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
        con_load.signal.error.connect(self.cb_handle_error_msg)

        con_load.start_args(make_qt_args(*a, **kw))

    def reload_tile(self):
        canvas = self.iface.mapCanvas()
        rect = bbox_utils.extend_to_rect(bbox_utils.get_bounding_box(canvas))
        level = tile_utils.get_zoom_for_current_map_scale(canvas)
        kw = dict()
        kw["tile_schema"] = "here"
        kw["tile_ids"] = tile_utils.bboxToListColRow(*rect, level)
        # kw["limit"] = 100

        unique_con = set()
        lst_con = list()
        for qnode in [
                vl
                for vl in QgsProject.instance().layerTreeRoot().checkedLayers(
                ) if is_xyz_supported_layer(vl)
        ] + [
                g for g in QgsProject.instance().layerTreeRoot().findGroups()
                if len(g.children()) == 0 and g.isVisible()
                and is_xyz_supported_node(g)
        ]:
            xlayer_id = qnode.customProperty("xyz-hub-id")
            con = self.con_man.get_from_xyz_layer(xlayer_id)
            if con is None: continue
            if con in unique_con: continue
            lst_con.append(con)
            unique_con.add(con)
        # print_qgis(lst_con)
        # print_qgis(self.con_man._layer_ptr)

        for con in lst_con:
            print_qgis(con.status)
            print_qgis("loading tile", level, rect)
            con.restart(**kw)

    def add_basemap_layer(self, args):
        a, kw = parse_qt_args(args)
        meta, app_id, app_code = a
        self.auth_manager.save(app_id, app_code)
        basemap.add_basemap_layer(meta, app_id, app_code)

    ###############
    # import project function
    ###############

    def import_project(self):
        self.init_tile_loader()

    def init_tile_loader(self):
        cnt = 0
        for qnode in [
                g for g in QgsProject.instance().layerTreeRoot().findGroups()
                if is_xyz_supported_node(g)
        ]:
            try:
                layer = XYZLayer.load_from_qnode(qnode)
                con_load = TileLayerLoader(self.network,
                                           n_parallel=1,
                                           layer=layer)
                ptr = self.con_man.add_layer(con_load)
                # con_load.signal.finished.connect( self.make_cb_success("Tiles loaded") )
                con_load.signal.results.connect(
                    self.make_cb_success_args("Tiles loaded", dt=2))
                # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection)
                con_load.signal.error.connect(self.cb_handle_error_msg)

                cnt += 1
            except:
                pass

        # print_qgis(self.con_man._layer_ptr)
        self.cb_success_msg("Import XYZ Layer",
                            "%s XYZ Layer imported" % cnt,
                            dt=2)

    ###############
    # Open dialog
    ###############
    def open_clear_cache_dialog(self):
        dialog = ConfirmDialog(
            "Delete cache will make loaded layer unusable !!")
        ret = dialog.exec_()
        if ret != dialog.Ok: return

        utils.clear_cache()

    def open_connection_dialog(self):
        dialog = self.new_main_dialog()

        vlayer = self.iface.activeLayer()
        dialog.set_layer(vlayer)

        dialog.exec_()
        self.con_man.finish_fast()
        # self.startTime = time.time()
    def open_sync_edit_dialog(self):
        vlayer = self.iface.activeLayer()
        layer_buffer = self.edit_buffer.get_layer_buffer(vlayer.id())

        lst_added_feat, removed_ids = layer_buffer.get_sync_feat()
        conn_info = layer_buffer.get_conn_info()

        # print_qgis("lst_added_feat: ",lst_added_feat)
        # print_qgis("removed_feat: ", removed_ids)

        con = EditSyncController(self.network)
        self.con_man.add_background(con)
        con.signal.finished.connect(layer_buffer.sync_complete)
        con.signal.results.connect(
            self.make_cb_success_args("Sync edit finish"))
        con.signal.error.connect(self.cb_handle_error_msg)

        con.start(conn_info, layer_buffer, lst_added_feat, removed_ids)
class PointConnector(object):
    """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',
                                   'PointConnector_{}.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 = PointConnectorDialog()

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Point Connector')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'PointConnector')
        self.toolbar.setObjectName(u'PointConnector')
        self.addedLayers = 1

    # 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('PointConnector', 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 InaSAFE 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):
        self.action = QAction(QIcon(":/plugins/PointConnector/icon.png"),
                              "PointConnector", self.iface.mainWindow())
        self.action.setWhatsThis("Connect points")
        self.action.setStatusTip("Connect points following a from-to list")

        self.action.triggered.connect(self.run)

        if hasattr(self.iface, "addPluginToVectorMenu"):
            self.iface.addVectorToolBarIcon(self.action)
            self.iface.addPluginToVectorMenu("&PointConnector", self.action)
        else:
            self.iface.addToolBarIcon(self.action)
            self.iface.addPluginToMenu("&PointConnector", self.action)

    def unload(self):
        self.iface.removePluginVectorMenu("&PointConnector", self.action)
        self.iface.removeVectorToolBarIcon(self.action)
        self.iface.removeToolBarIcon(self.action)

    def run(self):

        self.dlg.populateComboBox()
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result == 1:
            # create layers dict
            #layers = QgsProject.instance().mapLayers()
            layers = {}
            for name, layer in QgsProject.instance().mapLayers().items():
                layers[layer.name()] = layer

            #choose point-source
            chosenPoint = self.dlg.pointsComboBox.currentText()

            if chosenPoint != 'Choose layer...':
                point_layer = layers[chosenPoint]

            else:
                pointPath = self.dlg.pointPathLineEdit.text()
                point_layer = QgsVectorLayer(
                    pointPath, 'points',
                    'ogr')  #shp-file with attribute field name

                try:
                    p = open(pointPath, 'r')
                    p.close()
                except IOError:
                    QMessageBox.information(
                        None, "Error",
                        "Shape-file not found. Check file path.")
                    return

            point_name_index = 0

            # choose csv-source
            lines_list = []
            chosenCsv = self.dlg.csvComboBox.currentText()

            if chosenCsv != 'Choose layer...':
                csv_layer = layers[chosenCsv]
                csv_features = csv_layer.getFeatures()
                for line in csv_features:
                    attrs = line.attributes()
                    lines_list.append(((str(attrs[0])), str(attrs[1])))
            else:
                csvPath = self.dlg.csvPathLineEdit.text()
                # test if csv is valid
                try:
                    f = codecs.open(csvPath, 'r', 'utf-8-sig')
                    for line in f:
                        pass
                    f = codecs.open(csvPath, 'r', 'utf-8-sig')

                except UnicodeDecodeError:
                    try:
                        f = open(csvPath, 'r')
                        re.search('\\\\', f) == None

                    except:
                        QMessageBox.information(
                            None, "Error",
                            "PointConnector can not read csv-file. Try saving it with utf-8 encoding or import it as a layer."
                        )
                        return
                except IOError:
                    QMessageBox.information(
                        None, "Error",
                        "Csv-file not found. Check file path or select a csv-layer."
                    )
                    return

                #creating lines list from file
                for line in f:
                    line = line.splitlines()
                    for s in line[:1]:
                        s = tuple(s.split(','))
                        lines_list.append(s)
                f.close()

            point_layer_crs = point_layer.crs().authid()
            lines_layer = QgsVectorLayer(
                'LineString?crs=' + point_layer_crs,
                'PointConnector lines ' + str(self.addedLayers), 'memory')
            pr = lines_layer.dataProvider()

            lines_layer.startEditing()
            pr.addAttributes([
                QgsField('id', QVariant.Int),
                QgsField('from', QVariant.String),
                QgsField('to', QVariant.String)
            ])

            #creating point coordinate dict
            points = point_layer.getFeatures()
            points_dict = {}

            #Progress bar widget
            progressMessageBar = iface.messageBar().createMessage(
                "Building point database...")
            progress = QProgressBar()
            progress.setMaximum(point_layer.featureCount())
            progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            progressMessageBar.layout().addWidget(progress)
            iface.messageBar().pushWidget(progressMessageBar, Qgis.Info)

            i = 0
            for p in points:
                geom = p.geometry()
                attrs = p.attributes()
                p = geom.asPoint()
                key = attrs[point_name_index]
                points_dict[str(
                    key)] = p  #attrs[point_name_index] = name field
                i += 1
                progress.setValue(i)

            iface.messageBar().clearWidgets()
            QgsProject.instance().addMapLayer(point_layer)

            #Progress bar widget
            progressMessageBar = iface.messageBar().createMessage(
                "Drawing lines...")
            progress = QProgressBar()
            progress.setMaximum(len(lines_list))
            progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            progressMessageBar.layout().addWidget(progress)
            iface.messageBar().pushWidget(progressMessageBar, Qgis.Info)

            #Drawing the lines
            i = 1
            not_processed_list = []

            for line in lines_list:
                if (line[0] in list(points_dict.keys())
                        and line[1] in list(points_dict.keys())):
                    frPoint = points_dict[line[0]]
                    toPoint = points_dict[line[1]]
                    attrs = [i, line[0], line[1]]
                    new_line = QgsGeometry.fromPolyline(
                        [QgsPoint(frPoint),
                         QgsPoint(toPoint)])
                    feat = QgsFeature()
                    feat.setGeometry(new_line)
                    feat.setAttributes(attrs)
                    (res, outFeats) = pr.addFeatures([feat])
                    lines_layer.commitChanges()
                    if res != True:
                        pass
                    i += 1
                    progress.setValue(i)
                else:
                    not_processed_list.append(line)
                    progress.setValue(i)

            iface.messageBar().clearWidgets()

            # add lines layer to canvas
            QgsProject.instance().addMapLayer(lines_layer)
            self.addedLayers += 1

            if not not_processed_list:
                QMessageBox.information(None, 'Success',
                                        'All lines drawn without error')
            else:
                QMessageBox.information(
                    None, 'Error',
                    str(len(not_processed_list)) + ' out of ' +
                    str(len(lines_list)) + ' line(s) not drawn.')
class GimpSelectionFeaturePlugin(QObject):

  def __init__(self, iface):
    super().__init__()
    self.iface = iface
    self.name = u"&Gimp Selection Feature"
    self.dock = self.exitsPluginGimp = None
    self.translate = Translate( 'gimpselectionfeature' )

  def initGui(self):
    def setExistsPluginGimp():
      def getDirPluginGimp():
        dirPlugin = None
        mask = r".*gimp.[0-9]+.[0-9]+/%s" % nameDirPlugin # Linux Format
        for root, dirs, files in os.walk( dirHome ):
          if re.match( mask, root.replace('\\', '/'), re.IGNORECASE ):
            dirPlugin = root
            break

        return dirPlugin

      def copyNewPlugin():
        shutil.copy2( gimpPlugin, gimpPluginInstall )
        if sys.platform != 'win32': # Add executable
          st =  os.stat( gimpPluginInstall )
          os.chmod( gimpPluginInstall, st.st_mode | stat.S_IEXEC )

      dirHome = os.path.expanduser('~')
      nameDirPlugin = "plug-ins"
      dirPluginGimp = getDirPluginGimp()
      if dirPluginGimp is None:
        msg = "Not found diretory 'GIMP' or 'GIMP {}' in '{}'".format( nameDirPlugin, dirHome )
        self.exitsPluginGimp = { 'isOk': False, 'msg': msg }
        return

      namePlugin = 'socket_server_selection.py'
      gimpPlugin = os.path.join( os.path.dirname(__file__), namePlugin )
      gimpPluginInstall = os.path.join( dirPluginGimp, namePlugin )
      if not os.path.exists( gimpPluginInstall ) or not filecmp.cmp( gimpPlugin, gimpPluginInstall ):
        copyNewPlugin()

      self.exitsPluginGimp = { 'isOk': True }

    name = "Gimp Selection Feature"
    about = QCoreApplication.translate('GimpSelectionFeature', 'Adding selected area in GIMP how a feature in shapefile')
    icon = QIcon( os.path.join( os.path.dirname(__file__), 'gimpselectionfeature.svg' ) )
    self.action = QAction( icon, name, self.iface.mainWindow() )
    self.action.setObjectName( name.replace(' ', '') )
    self.action.setWhatsThis( about )
    self.action.setStatusTip( about )
    self.action.setCheckable( True )
    self.action.triggered.connect( self.run )

    self.iface.addRasterToolBarIcon( self.action )
    self.iface.addPluginToRasterMenu( self.name, self.action )

    setExistsPluginGimp()
    if not self.exitsPluginGimp['isOk']:
      return

    self.dock = DockWidgetGimpSelectionFeature( self.iface )
    self.iface.addDockWidget( Qt.RightDockWidgetArea , self.dock )
    self.dock.visibilityChanged.connect( self.dockVisibilityChanged )

  def unload(self):
    self.iface.removeRasterToolBarIcon( self.action )
    self.iface.removePluginRasterMenu( self.name, self.action )

    if self.exitsPluginGimp['isOk']:
      self.dock.close()
      del self.dock
      self.dock = None

    del self.action

  @pyqtSlot()
  def run(self):
    if not self.exitsPluginGimp['isOk']:
      ( t, m ) = ( GimpSelectionFeature.nameModulus, self.exitsPluginGimp['msg'] )
      self.iface.messageBar().pushMessage( t, m, Qgis.Critical, 5 )
      self.action.setChecked( False )
      return

    if self.dock.isVisible():
      self.dock.hide()
    else:
      self.dock.show()

  @pyqtSlot(bool)
  def dockVisibilityChanged(self, visible):
    self.action.setChecked( visible )
class QgisMapBiomasAPI:
    """Plugin implementation
    """
    def __init__(self, iface):
        """
        Constructor

        Args:
            iface (qgis.gui.QgisInterface): a reference to the QGIS GUI interface
        """
        self.iface = iface
        self.plugin_dir = os.path.dirname(__file__)
        self.locale = QSettings().value('locale/userLocale')[0:2]
        self.dockwidget = None
        self.action = None
        self.name = 'MapBiomas API'
        self.about = 'MapBiomas API for QGIS'
        self.token = None
        self.biome = None
        self.state = None

        # initialize locale
        locale_path = os.path.join(
            self.plugin_dir, 'i18n', '{}_{}.qm'.format('mapbiomas-api',
                                                       self.locale))
        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

    def tr(self, msg):
        return QCoreApplication.translate("QgisMapBiomasAPI", msg)

    def initProcessing(self):
        self.provider = Provider()
        QgsApplication.processingRegistry().addProvider(self.provider)

    def initGui(self):
        """
        This method is called by QGIS when the main GUI starts up or 
        when the plugin is enabled in the Plugin Manager.
        Only want to register the menu items and toolbar buttons here,
        and connects action with run method.
        """

        self.initProcessing()

        icon = QIcon(os.path.join(self.plugin_dir, 'icon.png'))
        self.action = QAction(icon, self.name, self.iface.mainWindow())
        self.action.setWhatsThis(self.about)
        self.action.setStatusTip(self.about)
        self.action.setCheckable(True)
        self.action.triggered.connect(self.run)

        # for plugin menu/toolbar
        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(self.name, self.action)

    def unload(self):
        """
        Will be executed when the plugin is disabled. 
        Either in the Plugin Manager or when QGIS shuts down.
        It removes the previously defined QAction object from
        the menu and remove the plugin icon from the toolbar.
        """

        # for plugin menu/toolbar
        self.iface.removeToolBarIcon(self.action)
        self.iface.removePluginMenu(self.name, self.action)

        if self.dockwidget is not None:
            # disconnect triggers here
            self.dockwidget.pushButton.clicked.disconnect(self.do_something)
            self.dockwidget.checkBoxStartDetected.toggled[bool].disconnect(
                self.dockwidget.startDetectedAt.setEnabled)
            self.dockwidget.checkBoxEndDetected.toggled[bool].disconnect(
                self.dockwidget.endDetectedAt.setEnabled)
            self.dockwidget.checkBoxStartPublished.toggled[bool].disconnect(
                self.dockwidget.startPublishedAt.setEnabled)
            self.dockwidget.checkBoxEndPublished.toggled[bool].disconnect(
                self.dockwidget.endPublishedAt.setEnabled)
            self.dockwidget.close()
            self.dockwidget.visibilityChanged.disconnect(
                self.visibility_changed)
            self.iface.removeDockWidget(self.dockwidget)
            del self.dockwidget

        # remove processing provider
        QgsApplication.processingRegistry().removeProvider(self.provider)

    def run(self):
        """
        Executes the custom plugin functionality.
        This method is called by the previously defined QAction object (callback), 
        which went into the toolbar icon and the menu entry.
        """
        if self.dockwidget is None:
            self.dockwidget = DockMapBiomasApi()
            self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget)
            self.dockwidget.visibilityChanged.connect(self.visibility_changed)
            self.init()
            self.dockwidget.show()
        else:
            if self.dockwidget.isVisible():
                self.dockwidget.hide()
            else:
                self.dockwidget.show()

    def visibility_changed(self, change):
        """
        Change icon checked status with dockwidget visibility
        """
        self.action.setChecked(change)

    def info(self, msg, level=Qgis.Info, duration=5):
        """
        docstring
        """
        self.iface.messageBar().pushMessage(msg, level, duration)

    def log(self, msg, level=Qgis.Info):
        """
        docstring
        """
        QgsMessageLog.logMessage(msg, self.name, level)

    def sign_in(self):
        """
        Creation of an access token in the JWT standard 
        to be used in the Authorization header and
        populate BIOME and STATE if empty
        """

        err = None

        email = self.dockwidget.email.text()
        password = self.dockwidget.password.text()

        if password and email:
            try:
                self.token, err = MapbiomasApi.token({
                    "email": email,
                    "password": password
                })
            except Exception as e:
                err = str(e)
            if self.token is not None:
                if self.biome is None:
                    self.biome, err = territories.get(self.token,
                                                      {"category": "BIOME"})
                if self.state is None:
                    self.state, err = territories.get(self.token,
                                                      {"category": "STATE"})
        else:
            err = self.tr('Email and password are required.')

        return err

    def get_alerts(self):

        filters = {}
        territories = []

        if self.dockwidget.BIOME.count:
            territories.extend(
                [self.biome[k] for k in self.dockwidget.BIOME.checkedItems()])

        if self.dockwidget.STATE.count:
            territories.extend(
                [self.state[k] for k in self.dockwidget.STATE.checkedItems()])

        if territories:
            filters["territoryIds"] = territories

        if self.dockwidget.checkBoxStartDetected.isChecked():
            filters["startDetectedAt"] = self.dockwidget.startDetectedAt.date(
            ).toString('yyyy-MM-dd')

        if self.dockwidget.checkBoxEndDetected.isChecked():
            filters["endDetectedAt"] = self.dockwidget.endDetectedAt.date(
            ).toString('yyyy-MM-dd')

        if self.dockwidget.checkBoxStartPublished.isChecked():
            filters[
                "startPublishedAt"] = self.dockwidget.startPublishedAt.date(
                ).toString('yyyy-MM-dd')

        if self.dockwidget.checkBoxEndPublished.isChecked():
            filters["endPublishedAt"] = self.dockwidget.endPublishedAt.date(
            ).toString('yyyy-MM-dd')

        try:
            data, err = publishedAlerts.get(self.token, filters)
        except Exception as e:
            err = str(e)

        if err is None:
            with NamedTemporaryFile("w+t",
                                    prefix=self.tr("alerts_"),
                                    suffix=".geojson",
                                    delete=False) as outfile:
                json.dump(data, outfile)
                fn = outfile.name
            if not "territoryIds" in filters and (len(data["features"])
                                                  == publishedAlerts.LIMIT):
                self.info(
                    self.tr('The number of alerts was limited to {}').format(
                        publishedAlerts.LIMIT))
            # add vector layer
            layer = QgsVectorLayer(fn, 'MapBiomasAPI', 'ogr')
            if layer.isValid():
                locale_style = os.path.join(
                    self.plugin_dir, 'i18n',
                    'mapbiomas-api_{}.qml'.format(self.locale))
                if os.path.exists(locale_style):
                    layer.loadNamedStyle(locale_style)
                else:
                    layer.loadNamedStyle(
                        os.path.join(self.plugin_dir, 'mapbiomas-api.qml'))
                QgsProject.instance().addMapLayer(layer)
            else:
                self.log("Invalid layer file: {}".format(fn))
                self.info(
                    self.tr("Unknown error. Invalid layer. Try it again."),
                    level=Qgis.Critical)
        elif err == 'Você não tem permissão para realizar esta ação':
            self.dockwidget.pushButton.setText(self.tr('SIGN IN'))
            self.dockwidget.options.setDisabled(True)
            self.dockwidget.mGroupBox.setCollapsed(False)
            self.info(self.tr("The session has expired. Sign in again."),
                      level=Qgis.Critical)
        else:
            self.info(err, level=Qgis.Critical)

    def do_something(self):
        """Sign in or get alerts
        """
        if self.dockwidget.pushButton.text() == self.tr('SIGN IN'):
            err = self.sign_in()
            if err is None:
                self.dockwidget.BIOME.addItems(self.biome.keys())
                self.dockwidget.STATE.addItems(self.state.keys())
                self.dockwidget.pushButton.setText(self.tr('GET ALERTS'))
                self.dockwidget.options.setEnabled(True)
                self.dockwidget.mGroupBox.setCollapsed(True)
            else:
                self.info(err, level=Qgis.Critical)
        else:
            self.get_alerts()

    def init(self):
        """
        Fill options, default values and connect triggers of the dockwidget
        """

        # connect triggers
        self.dockwidget.pushButton.clicked.connect(self.do_something)
        self.dockwidget.checkBoxStartDetected.toggled[bool].connect(
            self.dockwidget.startDetectedAt.setEnabled)
        self.dockwidget.checkBoxEndDetected.toggled[bool].connect(
            self.dockwidget.endDetectedAt.setEnabled)
        self.dockwidget.checkBoxStartPublished.toggled[bool].connect(
            self.dockwidget.startPublishedAt.setEnabled)
        self.dockwidget.checkBoxEndPublished.toggled[bool].connect(
            self.dockwidget.endPublishedAt.setEnabled)

        # set defaults
        self.dockwidget.endDetectedAt.setDate(QDate.currentDate())
        self.dockwidget.endPublishedAt.setDate(QDate.currentDate())
Example #37
0
    def add_action(self,
                   name,
                   icon_path,
                   text,
                   callback,
                   toggle_flag=False,
                   enabled_flag=True,
                   checkable_flag=False,
                   visible_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 name: Objectname of the action. Serves also as key for the stored actions.
        :type name: str

        :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 toggle_flag: A flag indicating if the action should connect
            the toggled or triggered signal by default.
            Defaults to triggered (False)
        :type toggle_flag: bool

        :param checkable_flag: A flag indicating if the action should be checkable
            by default. Defaults to False.
        :type checkable: bool

        :param visible_flag: A flag indicating if the action should be displayed
            by default. Defaults to True.
        :type visible: 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.setObjectName(name)
        if toggle_flag:
            action.toggled.connect(callback)
        else:
            action.triggered.connect(callback)
        action.setEnabled(enabled_flag)
        action.setCheckable(checkable_flag)
        action.setVisible(visible_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[name] = action

        return action
class VoGISProfilToolMainDialog(QDialog):
    def __init__(self, interface, settings):
        QDialog.__init__(self, interface.mainWindow())

        # Set up the user interface from Designer.
        self.ui = Ui_VoGISProfilToolMain()
        self.ui.setupUi(self)
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setText(
            QApplication.translate("code", "Profil erstellen"))
        self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText(
            QApplication.translate("code", "Schließen"))

        self.ui.grpCadastre.toggled.connect(self._toggleCadastreLayer)
        self.ui.cmbCadastreLayer.currentIndexChanged.connect(
            self._updateCadastreLayer)

        self.settings = settings
        self.iface = interface
        self.selectingVisibleRasters = False
        self.thread = None

        if self.settings.onlyHektoMode is True:
            self.ui.IDC_widRaster.hide()
            self.adjustSize()

        self.ui.IDC_dblspinDistance.setValue(self.settings.equiDistance)
        self.ui.IDC_dblspinVertexCnt.setValue(self.settings.vertexCnt)

        validator = QIntValidator(-32768, 32768, self)
        self.ui.IDC_tbNoDataExport.setValidator(validator)

        self.ui.IDC_tbFromX.setText("-30000")
        self.ui.IDC_tbFromY.setText("240000")
        self.ui.IDC_tbToX.setText("-20000")
        self.ui.IDC_tbToY.setText("230000")

        self.__addRastersToGui()
        self.__addPolygonsToGui()

        for line_lyr in self.settings.mapData.lines.lines():
            self.ui.IDC_cbLineLayers.addItem(line_lyr.name, line_lyr)

        if self.settings.mapData.lines.count() < 1:
            self.ui.IDC_rbDigi.setChecked(True)
            self.ui.IDC_rbShapeLine.setEnabled(False)

        #Einstellungen fuer Linie zeichen
        self.action = QAction(
            QIcon(":/plugins/vogisprofiltoolmain/icons/icon.png"),
            "VoGIS-Profiltool", self.iface.mainWindow())
        self.action.setWhatsThis("VoGIS-Profiltool")

        self.canvas = self.iface.mapCanvas()
        self.tool = ProfiletoolMapTool(self.canvas, self.action)
        self.savedTool = self.canvas.mapTool()
        self.polygon = False

        self.rubberband = QgsRubberBand(self.canvas, self.polygon)
        self.rubberband.setLineStyle(Qt.SolidLine)
        self.rubberband.setWidth(4.0)
        self.rubberband.setColor(QColor(0, 255, 0))
        #http://www.qgis.org/api/classQgsRubberBand.html#a6f7cdabfcf69b65dfc6c164ce2d01fab

        self.pointsToDraw = []
        self.dblclktemp = None
        self.drawnLine = None

    def accept(self):
        try:
            nodata = self.ui.IDC_tbNoDataExport.text()
            self.settings.nodata_value = int(nodata) if nodata != "" else None
            QgsMessageLog.logMessage(
                "Maindlg: nodata: {0}".format(self.settings.nodata_value),
                "VoGis", Qgis.Info)

            if self.settings.onlyHektoMode is True and self.settings.mapData.rasters.count(
            ) > 0:
                self.settings.onlyHektoMode = False

            if self.settings.onlyHektoMode is False:
                if self.settings.mapData.rasters.count() < 1:
                    retVal = QMessageBox.warning(
                        self.iface.mainWindow(), "VoGIS-Profiltool",
                        QApplication.translate(
                            "code",
                            "Keine Rasterebene vorhanden oder sichtbar! Nur hektometrieren?"
                        ), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
                    if retVal == QMessageBox.No:
                        return
                    else:
                        self.settings.onlyHektoMode = True
                        self.settings.createHekto = True

            if self.__getSettingsFromGui() is False:
                return

            if self.settings.onlyHektoMode is False:
                if len(self.settings.mapData.rasters.selectedRasters()) < 1:
                    QMessageBox.warning(
                        self.iface.mainWindow(), "VoGIS-Profiltool",
                        QApplication.translate("code",
                                               "Kein Raster selektiert!"))
                    return

            QgsMessageLog.logMessage(
                "modeLine!=line: {0}".format(
                    self.settings.modeLine != enumModeLine.line), "VoGis",
                Qgis.Info)
            QgsMessageLog.logMessage(
                "customLine is None: {0}".format(
                    self.settings.mapData.customLine is None), "VoGis",
                Qgis.Info)

            if self.settings.modeLine != enumModeLine.line and self.settings.mapData.customLine is None:
                QMessageBox.warning(
                    self.iface.mainWindow(), "VoGIS-Profiltool",
                    QApplication.translate("code",
                                           "Keine Profillinie vorhanden!"))
                return

            if len(self.settings.mapData.polygons.selected_polygons()
                   ) > 0 and len(
                       self.settings.mapData.rasters.selectedRasters()) > 1:
                raster_names = list(
                    raster.name for raster in
                    self.settings.mapData.rasters.selectedRasters())
                sel_raster, ok_clicked = QInputDialog.getItem(
                    self.iface.mainWindow(), "DHM?",
                    "Welches DHM soll zur Flächenverschneidung verwendet werden?",
                    raster_names, 0, False)
                if ok_clicked is False:
                    return

                self.settings.intersection_dhm_idx = raster_names.index(
                    sel_raster)

            QApplication.setOverrideCursor(Qt.WaitCursor)

            create_profile = CreateProfile(self.iface, self.settings)
            thread = QThread(self)
            create_profile.moveToThread(thread)
            create_profile.finished.connect(self.profiles_finished)
            create_profile.error.connect(self.profiles_error)
            create_profile.progress.connect(self.profiles_progress)
            thread.started.connect(create_profile.create)
            thread.start(QThread.LowestPriority)
            self.thread = thread
            self.create_profile = create_profile
            self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
        except:
            QApplication.restoreOverrideCursor()
            ex = "{0}".format(traceback.format_exc())
            msg = "Unexpected ERROR:\n\n{0}".format(ex[:2000])
            QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool",
                                 msg)

    def profiles_finished(self, profiles, intersections, cadastre):
        QApplication.restoreOverrideCursor()
        self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(True)
        self.thread.quit()
        self.thread.wait()

        #QGIS 2.0 http://gis.stackexchange.com/a/58754 http://gis.stackexchange.com/a/57090
        self.iface.mainWindow().statusBar().showMessage(
            "VoGIS-Profiltool, {0} Profile".format(len(profiles)))
        QgsMessageLog.logMessage("Profile Count: {0}".format(len(profiles)),
                                 "VoGis", Qgis.Info)

        if len(profiles) < 1:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(
                self.iface.mainWindow(), "VoGIS-Profiltool",
                QApplication.translate(
                    "code", "Es konnten keine Profile erstellt werden."))
            return

        dlg = VoGISProfilToolPlotDialog(self.iface, self.settings, profiles,
                                        intersections, cadastre)
        dlg.show()
        dlg.exec_()

    def profiles_error(self, exception_string):
        QApplication.restoreOverrideCursor()
        QgsMessageLog.logMessage(
            "Error during profile creation: {0}".format(exception_string),
            "VoGis", Qgis.Critical)
        QMessageBox.critical(self.iface.mainWindow(), "VoGIS-Profiltool",
                             exception_string)

    def profiles_progress(self, msg):
        self.iface.mainWindow().statusBar().showMessage(msg)
        self.ui.IDC_lblCreateStatus.setText(msg)
        QApplication.processEvents()

    def reject(self):
        if not self.thread is None:
            if self.thread.isRunning():
                self.create_profile.abort()
                return

        self.rubberband.reset(self.polygon)
        QDialog.reject(self)

    def selectVisibleRasters(self):
        self.refreshRasterList()
        self.selectingVisibleRasters = True
        extCanvas = self.iface.mapCanvas().extent()
        #alle raster in den einstellunge deselektieren
        for r in self.settings.mapData.rasters.rasters():
            r.selected = False
        #alle raster in der ListView deselektieren
        for idx in range(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            item.setCheckState(Qt.Unchecked)
        #Raster im Extent selektieren
        canvasCrs = self.iface.mapCanvas().mapSettings().destinationCrs()
        for idx in range(self.ui.IDC_listRasters.count()):
            item = self.ui.IDC_listRasters.item(idx)
            raster = item.data(Qt.UserRole)
            for r in self.settings.mapData.rasters.rasters():
                layerCrs = r.grid.crs()
                ct = QgsCoordinateTransform(layerCrs, canvasCrs,
                                            QgsProject.instance())
                extent = ct.transform(r.grid.extent())
                if extCanvas.intersects(extent):
                    if r.id == raster.id:
                        r.selected = True
                        item.setCheckState(Qt.Checked)
        self.selectingVisibleRasters = False

    def lineLayerChanged(self, idx):
        if self.ui.IDC_rbShapeLine.isChecked() is False:
            self.ui.IDC_rbShapeLine.setChecked(True)
        lineLyr = (self.ui.IDC_cbLineLayers.itemData(
            self.ui.IDC_cbLineLayers.currentIndex()))

        lyr = lineLyr.line
        if hasattr(lyr, "selectedFeatureCount"):
            if (lyr.selectedFeatureCount() < 1):
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(False)
            else:
                self.ui.IDC_chkOnlySelectedFeatures.setChecked(True)

    def valueChangedEquiDistance(self, val):
        if self.ui.IDC_rbEquiDistance.isChecked() is False:
            self.ui.IDC_rbEquiDistance.setChecked(True)

    def valueChangedVertexCount(self, val):
        if self.ui.IDC_rbVertexCount.isChecked() is False:
            self.ui.IDC_rbVertexCount.setChecked(True)

    def lvRasterItemChanged(self, item):
        if self.selectingVisibleRasters is True:
            return
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        raster_lyr = item_data
        self.settings.mapData.rasters.getById(
            raster_lyr.id).selected = selected

    def lvPolygonItemChanged(self, item):
        if item.checkState() == Qt.Checked:
            selected = True
        if item.checkState() == Qt.Unchecked:
            selected = False

        item_data = item.data(Qt.UserRole)
        poly_lyr = item_data
        self.settings.mapData.polygons.getById(poly_lyr.id).selected = selected

    def refreshRasterList(self):
        root = QgsProject.instance().layerTreeRoot()
        avail_lyrs = root.findLayers()

        raster_coll = RasterCollection()

        for lyr in avail_lyrs:
            if lyr.isVisible():
                mapLayer = lyr.layer()
                lyr_type = mapLayer.type()
                lyr_name = mapLayer.name()
                if lyr_type == QgsMapLayer.RasterLayer:
                    if mapLayer.bandCount() < 2:
                        new_raster = Raster(mapLayer.id(), lyr_name, mapLayer)
                        raster_coll.addRaster(new_raster)

        self.settings.mapData.rasters = raster_coll
        self.__addRastersToGui()

    def __addRastersToGui(self):
        self.ui.IDC_listRasters.clear()
        check = Qt.Unchecked
        if self.settings.mapData.rasters.count() == 1:
            check = Qt.Checked
            self.settings.mapData.rasters.rasters()[0].selected = True

        for raster_lyr in self.settings.mapData.rasters.rasters():
            item = QListWidgetItem(raster_lyr.name)
            item.setData(Qt.UserRole, raster_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listRasters.addItem(item)

    def __addPolygonsToGui(self):
        self.ui.IDC_listPolygons.clear()
        self.ui.cmbCadastreLayer.clear()
        check = Qt.Unchecked
        for poly_lyr in self.settings.mapData.polygons.polygons():
            item = QListWidgetItem(poly_lyr.name)
            item.setData(Qt.UserRole, poly_lyr)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(check)
            self.ui.IDC_listPolygons.addItem(item)
            self.ui.cmbCadastreLayer.addItem(poly_lyr.name, poly_lyr.id)

    def drawLine(self):
        if self.ui.IDC_rbDigi.isChecked() is False:
            self.ui.IDC_rbDigi.setChecked(True)
        self.dblckltemp = None
        self.rubberband.reset(self.polygon)
        self.__cleanDigi()
        self.__activateDigiTool()
        self.canvas.setMapTool(self.tool)

    def __createDigiFeature(self, pnts):
        u = Util(self.iface)
        f = u.createQgLineFeature(pnts)
        self.settings.mapData.customLine = f

    def __lineFinished(self, position):
        self.showNormal()
        self.raise_()
        self.activateWindow()

        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
            position["x"], position["y"])
        newPoint = QgsPointXY(mapPos.x(), mapPos.y())
        self.pointsToDraw.append(newPoint)
        #launch analyses
        self.iface.mainWindow().statusBar().showMessage(str(self.pointsToDraw))
        if len(self.pointsToDraw) < 2:
            self.__cleanDigi()
            self.pointsToDraw = []
            self.dblclktemp = newPoint
            self.drawnLine = None
            QMessageBox.warning(
                self, "VoGIS-Profiltool",
                QApplication.translate(
                    "code", "Profillinie digitalisieren abgebrochen!"))
        self.drawnLine = self.__createDigiFeature(self.pointsToDraw)
        self.__cleanDigi()

        self.pointsToDraw = []
        self.dblclktemp = newPoint

    def __cleanDigi(self):
        self.pointsToDraw = []
        self.canvas.unsetMapTool(self.tool)
        self.canvas.setMapTool(self.savedTool)

    def __activateDigiTool(self):
        self.tool.moved.connect(self.__moved)
        self.tool.rightClicked.connect(self.__rightClicked)
        self.tool.leftClicked.connect(self.__leftClicked)
        self.tool.doubleClicked.connect(self.__doubleClicked)
        self.tool.deactivated.connect(self.__deactivateDigiTool)

    def __deactivateDigiTool(self):
        # TODO: how to check if not connected???
        try:
            self.tool.moved.disconnect(self.__moved)
        except:
            pass
        try:
            self.tool.leftClicked.disconnect(self.__leftClicked)
        except:
            pass
        try:
            self.tool.rightClicked.disconnect(self.__rightClicked)
        except:
            pass
        try:
            self.tool.doubleClicked.disconnect(self.__doubleClicked)
        except:
            pass
        try:
            self.iface.mainWindow().statusBar().showMessage("")
        except:
            pass

    def __moved(self, position):
        if len(self.pointsToDraw) > 0:
            mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
                position["x"], position["y"])
            self.rubberband.reset(self.polygon)
            newPnt = QgsPointXY(mapPos.x(), mapPos.y())
            pnts = self.pointsToDraw + [newPnt]
            self.rubberband.setToGeometry(QgsGeometry.fromPolylineXY(pnts),
                                          None)

    def __rightClicked(self, position):
        self.__lineFinished(position)

    def __leftClicked(self, position):
        mapPos = self.canvas.getCoordinateTransform().toMapCoordinates(
            position["x"], position["y"])
        newPoint = QgsPointXY(mapPos.x(), mapPos.y())
        if newPoint == self.dblclktemp:
            self.dblclktemp = None
            return
        else:
            if len(self.pointsToDraw) == 0:
                self.rubberband.reset(self.polygon)
            self.pointsToDraw.append(newPoint)

    def __doubleClicked(self, position):
        pass

    #not in use right now
    def __lineCancel(self):
        pass

    def __getSettingsFromGui(self):
        self.settings.linesExplode = (
            self.ui.IDC_chkLinesExplode.checkState() == Qt.Checked)
        self.settings.linesMerge = (
            self.ui.IDC_chkLinesMerge.checkState() == Qt.Checked)
        self.settings.onlySelectedFeatures = (
            self.ui.IDC_chkOnlySelectedFeatures.checkState() == Qt.Checked)
        self.settings.equiDistance = self.ui.IDC_dblspinDistance.value()
        self.settings.vertexCnt = self.ui.IDC_dblspinVertexCnt.value()
        #self.settings.createHekto = (self.ui.IDC_chkCreateHekto.checkState() == Qt.Checked)
        self.settings.nodesAndVertices = (
            self.ui.IDC_chkNodesAndVertices.checkState() == Qt.Checked)

        self.settings.mapData.selectedLineLyr = (
            self.ui.IDC_cbLineLayers.itemData(
                self.ui.IDC_cbLineLayers.currentIndex()))

        if self.settings.onlySelectedFeatures is True and self.settings.mapData.selectedLineLyr.line.selectedFeatureCount(
        ) < 1:
            QMessageBox.warning(
                self.iface.mainWindow(), "VoGIS-Profiltool",
                QApplication.translate(
                    "code",
                    u"Der gewählte Layer hat keine selektierten Elemente."))
            return False

        if self.ui.IDC_rbDigi.isChecked():
            self.settings.modeLine = enumModeLine.customLine
        elif self.ui.IDC_rbShapeLine.isChecked():
            self.settings.modeLine = enumModeLine.line
        else:
            #self.ui.IDC_rbStraigthLine
            self.settings.modeLine = enumModeLine.straightLine

        if self.ui.IDC_rbEquiDistance.isChecked():
            self.settings.modeVertices = enumModeVertices.equiDistant
        else:
            self.settings.modeVertices = enumModeVertices.vertexCnt

        if self.ui.IDC_rbStraigthLine.isChecked():
            ut = Util(self.iface)
            if ut.isFloat(self.ui.IDC_tbFromX.text(),
                          QApplication.translate("code",
                                                 "Rechtswert von")) is False:
                return False
            else:
                fromX = float(self.ui.IDC_tbFromX.text())
            if ut.isFloat(self.ui.IDC_tbFromY.text(),
                          QApplication.translate("code",
                                                 "Hochwert von")) is False:
                return False
            else:
                fromY = float(self.ui.IDC_tbFromY.text())
            if ut.isFloat(self.ui.IDC_tbToX.text(),
                          QApplication.translate("code",
                                                 "Rechtswert nach")) is False:
                return False
            else:
                toX = float(self.ui.IDC_tbToX.text())
            if ut.isFloat(self.ui.IDC_tbToY.text(),
                          QApplication.translate("code",
                                                 "Hochwert nach")) is False:
                return False
            else:
                toY = float(self.ui.IDC_tbToY.text())

            fromPnt = QgsPointXY(fromX, fromY)
            toPnt = QgsPointXY(toX, toY)

            self.settings.mapData.customLine = ut.createQgLineFeature(
                [fromPnt, toPnt])

        return True

    def _toggleCadastreLayer(self, toggled):
        if toggled:
            layerId = self.ui.cmbCadastreLayer.itemData(
                self.ui.cmbCadastreLayer.currentIndex())
            self.settings.mapData.cadastre = layerId
        else:
            self.settings.mapData.cadastre = None

    def _updateCadastreLayer(self, index):
        if self.ui.grpCadastre.isChecked():
            layerId = self.ui.cmbCadastreLayer.itemData(index)
            self.settings.mapData.cadastre = layerId
    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.addPluginToWebMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action
    def add_menu_action(self,
                        icon_path: str,
                        text: str,
                        callback: Callable,
                        enabled_flag: bool = True,
                        add_to_menu: bool = True,
                        menu_type: str = None,
                        add_to_toolbar: bool = True,
                        status_tip: str = None,
                        whats_this: str = None,
                        parent: QWidget = None) -> QAction:
        """
        Add a toolbar icon to the toolbar, associating it with an action linked
        to a function called on click; the action is also added to self.actions['menus'] list.

        Args:

            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.
            text: Text that should be shown in menu items for this action.
            callback: Function to be called when the action is triggered.
            enabled_flag: Whether the action should be enabled by default or not.
            add_to_menu: Whether the action should be added to the menu.
            menu_type: Type of menu add the action to, other than the main one (None).
            add_to_toolbar: Whether the action should also be added to the toolbar.
            status_tip: Optional text to show in a popup when mouse pointer hovers over the action.
            whats_this: Optional text to show in the status bar when the mouse pointer
                hovers over the action.
            parent: Parent Qt widget for the new action

        Returns:
            The action that was created.
        """
        if not menu_type:
            logger.debug("Add action \"%s\" to \"plugin\" toolbar menu" % text)
        else:
            logger.debug("Add action \"%s\" to \"%s\" toolbar menu" %
                         (text, menu_type))
        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)
        # Optionally setup "Status" tip dialog
        if status_tip is not None:
            action.setStatusTip(status_tip)
        # Optionally setup "what's this?" tip dialog
        if whats_this is not None:
            action.setWhatsThis(whats_this)
        # Optionally adds plugin menu icon to Plugins toolbar
        if add_to_toolbar:
            self.iface.addToolBarIcon(action)
        # Add menu items to proper plugin category
        if add_to_menu:
            if not menu_type:
                self.iface.addPluginToMenu(self.menu, action)
            elif menu_type.lower() == "database":
                self.iface.addPluginToDatabaseMenu(self.menu, action)
            elif menu_type.lower() == "raster":
                self.iface.addPluginToRasterMenu(self.menu, action)
            elif menu_type.lower() == "vector":
                self.iface.addPluginToVectorMenu(self.menu, action)
            elif menu_type.lower() == "web":
                self.iface.addPluginToWebMenu(self.menu, action)
            else:
                logger.error("Invalid menu choice")
                raise RuntimeError("Invalid choice for action adding: %s" %
                                   menu_type)
        # Updates actions array and return inserted elements
        self.actions['menus'].append(action)
        return action
Example #41
0
def create_action(
        icon_path,
        text,
        callback,
        enabled_flag=True,
        status_tip=None,
        whats_this=None,
        parent=None,
        object_name=None):

    """
    # adapted from RedLayers by E. Ferreguti
    Create an action.

    :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 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.

    :param object_name: Optional name to identify objects during customization
    :type object_name: str

    :returns: The action that was created.
    :rtype: QAction
    """

    icon = QIcon(icon_path)

    action = QAction(icon, text, parent)
    if callback:
        action.triggered.connect(callback)
    action.setEnabled(enabled_flag)

    if status_tip:
        action.setStatusTip(status_tip)

    if whats_this:
        action.setWhatsThis(whats_this)

    if object_name:
        action.setObjectName(object_name)

    return action
Example #42
0
class QgepPlugin(object):
    """
    A plugin for wastewater management
    http://www.github.com/qgep/QGEP
    """
    # The networkAnalyzer will manage the networklayers and pathfinding
    network_analyzer = None

    # Remember not to reopen the dock if there's already one opened
    profile_dock = None

    # Wizard
    wizarddock = None

    # The layer ids the plugin will need
    edgeLayer = None
    nodeLayer = None
    specialStructureLayer = None
    networkElementLayer = None

    profile = None

    def __init__(self, iface):
        self.iface = iface
        self.canvas = iface.mapCanvas()
        self.nodes = None
        self.edges = None

        self.initLogger()
        setup_i18n()

    def tr(self, source_text):
        """
        This does not inherit from QObject but for the translation to work (in particular to have translatable strings
        picked up) we need a tr method.
        :rtype : unicode
        :param source_text: The text to translate
        :return: The translated text
        """
        return QApplication.translate('QgepPlugin', source_text)

    def initLogger(self):
        """
        Initializes the logger
        """
        self.logger = logging.getLogger(__package__)

        settings = QSettings()

        loglevel = settings.value("/QGEP/LogLevel", 'Warning')
        logfile = settings.value("/QGEP/LogFile", None)

        if hasattr(self.logger, 'qgepFileHandler'):
            self.logger.removeHandler(self.logger.qgepFileHandler)
            del self.logger.qgepFileHandler

        self.logger.addHandler(QgepQgsLogHandler())

        if logfile:
            log_handler = logging.FileHandler(logfile)
            fmt = logging.Formatter(LOGFORMAT)
            log_handler.setFormatter(fmt)
            self.logger.addHandler(log_handler)
            self.logger.fileHandler = log_handler

        if 'Debug' == loglevel:
            self.logger.setLevel(logging.DEBUG)
        elif 'Info' == loglevel:
            self.logger.setLevel(logging.INFO)
        elif 'Warning' == loglevel:
            self.logger.setLevel(logging.WARNING)
        elif 'Error' == loglevel:
            self.logger.setLevel(logging.ERROR)

        fp = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                          "metadata.txt")

        ini_text = QSettings(fp, QSettings.IniFormat)
        verno = ini_text.value("version")

        self.logger.info('QGEP plugin version ' + verno + ' started')

    def initGui(self):
        """
        Called to setup the plugin GUI
        """
        self.network_layer_notifier = QgepLayerNotifier(
            self.iface.mainWindow(), ['vw_network_node', 'vw_network_segment'])
        self.wastewater_networkelement_layer_notifier = QgepLayerNotifier(
            self.iface.mainWindow(), ['vw_wastewater_node', 'vw_qgep_reach'])
        self.toolbarButtons = []

        # Create toolbar button
        self.profileAction = QAction(
            QIcon(
                os.path.join(plugin_root_path(),
                             "icons/wastewater-profile.svg")),
            self.tr("Profile"), self.iface.mainWindow())
        self.profileAction.setWhatsThis(self.tr("Reach trace"))
        self.profileAction.setEnabled(False)
        self.profileAction.setCheckable(True)
        self.profileAction.triggered.connect(self.profileToolClicked)

        self.downstreamAction = QAction(
            QIcon(
                os.path.join(plugin_root_path(),
                             "icons/wastewater-downstream.svg")),
            self.tr("Downstream"), self.iface.mainWindow())
        self.downstreamAction.setWhatsThis(self.tr("Downstream reaches"))
        self.downstreamAction.setEnabled(False)
        self.downstreamAction.setCheckable(True)
        self.downstreamAction.triggered.connect(self.downstreamToolClicked)

        self.upstreamAction = QAction(
            QIcon(
                os.path.join(plugin_root_path(),
                             "icons/wastewater-upstream.svg")),
            self.tr("Upstream"), self.iface.mainWindow())
        self.upstreamAction.setWhatsThis(self.tr("Upstream reaches"))
        self.upstreamAction.setEnabled(False)
        self.upstreamAction.setCheckable(True)
        self.upstreamAction.triggered.connect(self.upstreamToolClicked)

        self.wizardAction = QAction(
            QIcon(os.path.join(plugin_root_path(), "icons/wizard.svg")),
            "Wizard", self.iface.mainWindow())
        self.wizardAction.setWhatsThis(
            self.tr("Create new manholes and reaches"))
        self.wizardAction.setEnabled(False)
        self.wizardAction.setCheckable(True)
        self.wizardAction.triggered.connect(self.wizard)

        self.connectNetworkElementsAction = QAction(
            QIcon(
                os.path.join(plugin_root_path(),
                             "icons/link-wastewater-networkelement.svg")),
            QApplication.translate('qgepplugin',
                                   'Connect wastewater networkelements'),
            self.iface.mainWindow())
        self.connectNetworkElementsAction.setEnabled(False)
        self.connectNetworkElementsAction.setCheckable(True)
        self.connectNetworkElementsAction.triggered.connect(
            self.connectNetworkElements)

        self.refreshNetworkTopologyAction = QAction(
            QIcon(os.path.join(plugin_root_path(),
                               "icons/refresh-network.svg")),
            "Refresh network topology", self.iface.mainWindow())
        self.refreshNetworkTopologyAction.setWhatsThis(
            self.tr("Refresh network topology"))
        self.refreshNetworkTopologyAction.setEnabled(False)
        self.refreshNetworkTopologyAction.setCheckable(False)
        self.refreshNetworkTopologyAction.triggered.connect(
            self.refreshNetworkTopologyActionClicked)

        self.aboutAction = QAction(self.tr('About'), self.iface.mainWindow())
        self.aboutAction.triggered.connect(self.about)

        self.settingsAction = QAction(self.tr('Settings'),
                                      self.iface.mainWindow())
        self.settingsAction.triggered.connect(self.showSettings)

        # Add toolbar button and menu item
        self.toolbar = QToolBar(QApplication.translate('qgepplugin', 'QGEP'))
        self.toolbar.addAction(self.profileAction)
        self.toolbar.addAction(self.upstreamAction)
        self.toolbar.addAction(self.downstreamAction)
        self.toolbar.addAction(self.wizardAction)
        self.toolbar.addAction(self.refreshNetworkTopologyAction)
        self.toolbar.addAction(self.connectNetworkElementsAction)

        self.iface.addPluginToMenu("&QGEP", self.profileAction)
        self.iface.addPluginToMenu("&QGEP", self.settingsAction)
        self.iface.addPluginToMenu("&QGEP", self.aboutAction)

        self.iface.addToolBar(self.toolbar)

        # Local array of buttons to enable / disable based on context
        self.toolbarButtons.append(self.profileAction)
        self.toolbarButtons.append(self.upstreamAction)
        self.toolbarButtons.append(self.downstreamAction)
        self.toolbarButtons.append(self.wizardAction)
        self.toolbarButtons.append(self.refreshNetworkTopologyAction)

        self.network_layer_notifier.layersAvailable.connect(
            self.onLayersAvailable)
        self.network_layer_notifier.layersUnavailable.connect(
            self.onLayersUnavailable)

        # Init the object maintaining the network
        self.network_analyzer = QgepGraphManager()
        self.network_analyzer.message_emitted.connect(
            self.iface.messageBar().pushMessage)
        # Create the map tool for profile selection
        self.profile_tool = QgepProfileMapTool(self.iface, self.profileAction,
                                               self.network_analyzer)
        self.profile_tool.profileChanged.connect(self.onProfileChanged)

        self.upstream_tree_tool = QgepTreeMapTool(self.iface,
                                                  self.upstreamAction,
                                                  self.network_analyzer)
        self.upstream_tree_tool.setDirection("upstream")
        self.upstream_tree_tool.treeChanged.connect(self.onTreeChanged)
        self.downstream_tree_tool = QgepTreeMapTool(self.iface,
                                                    self.downstreamAction,
                                                    self.network_analyzer)
        self.downstream_tree_tool.setDirection("downstream")
        self.downstream_tree_tool.treeChanged.connect(self.onTreeChanged)

        self.maptool_connect_networkelements = QgepMapToolConnectNetworkElements(
            self.iface, self.connectNetworkElementsAction)

        self.wastewater_networkelement_layer_notifier.layersAvailableChanged.connect(
            self.connectNetworkElementsAction.setEnabled)

        self.processing_provider = QgepProcessingProvider()
        QgsApplication.processingRegistry().addProvider(
            self.processing_provider)

    def unload(self):
        """
        Called when unloading
        """
        self.toolbar.removeAction(self.profileAction)
        self.toolbar.removeAction(self.upstreamAction)
        self.toolbar.removeAction(self.downstreamAction)
        self.toolbar.removeAction(self.wizardAction)
        self.toolbar.removeAction(self.refreshNetworkTopologyAction)
        self.toolbar.removeAction(self.connectNetworkElementsAction)

        self.toolbar.deleteLater()

        self.iface.removePluginMenu("&QGEP", self.profileAction)
        self.iface.removePluginMenu("&QGEP", self.aboutAction)

        QgsApplication.processingRegistry().removeProvider(
            self.processing_provider)

    def onLayersAvailable(self, layers):
        for b in self.toolbarButtons:
            b.setEnabled(True)

        self.network_analyzer.setReachLayer(layers['vw_network_segment'])
        self.network_analyzer.setNodeLayer(layers['vw_network_node'])

    def onLayersUnavailable(self):
        for b in self.toolbarButtons:
            b.setEnabled(False)

    def profileToolClicked(self):
        """
        Is executed when the profile button is clicked
        """
        self.openDock()
        # Set the profile map tool
        self.profile_tool.setActive()

    def upstreamToolClicked(self):
        """
        Is executed when the user clicks the upstream search tool
        """
        self.openDock()
        self.upstream_tree_tool.setActive()

    def downstreamToolClicked(self):
        """
        Is executed when the user clicks the downstream search tool
        """
        self.openDock()
        self.downstream_tree_tool.setActive()

    def refreshNetworkTopologyActionClicked(self):
        """
        Is executed when the user clicks the refreshNetworkTopologyAction tool
        """
        self.network_analyzer.refresh()

    def wizard(self):
        """
        """
        if not self.wizarddock:
            self.wizarddock = QgepWizard(self.iface.mainWindow(), self.iface)
        self.logger.debug('Opening Wizard')
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.wizarddock)
        self.wizarddock.show()

    def connectNetworkElements(self, checked):
        self.iface.mapCanvas().setMapTool(self.maptool_connect_networkelements)

    def openDock(self):
        """
        Opens the dock
        """
        if self.profile_dock is None:
            self.logger.debug('Open dock')
            self.profile_dock = QgepProfileDockWidget(self.iface.mainWindow(),
                                                      self.iface.mapCanvas(),
                                                      self.iface.addDockWidget)
            self.profile_dock.closed.connect(self.onDockClosed)
            self.profile_dock.showIt()

            self.plotWidget = QgepPlotSVGWidget(self.profile_dock,
                                                self.network_analyzer)
            self.plotWidget.specialStructureMouseOver.connect(
                self.highlightProfileElement)
            self.plotWidget.specialStructureMouseOut.connect(
                self.unhighlightProfileElement)
            self.plotWidget.reachMouseOver.connect(
                self.highlightProfileElement)
            self.plotWidget.reachMouseOut.connect(
                self.unhighlightProfileElement)
            self.profile_dock.addPlotWidget(self.plotWidget)
            self.profile_dock.setTree(self.nodes, self.edges)

    def onDockClosed(self):  # used when Dock dialog is closed
        """
        Gets called when the dock is closed
        All the cleanup of the dock has to be done here
        """
        self.profile_dock = None

    def onProfileChanged(self, profile):
        """
        The profile changed: update the plot
        @param profile: The profile to plot
        """
        self.profile = profile.copy()

        if self.plotWidget:
            self.plotWidget.setProfile(profile)

    def onTreeChanged(self, nodes, edges):
        if self.profile_dock:
            self.profile_dock.setTree(nodes, edges)
        self.nodes = nodes
        self.edges = edges

    def highlightProfileElement(self, obj_id):
        if self.profile is not None:
            self.profile.highlight(str(obj_id))

    def unhighlightProfileElement(self):
        if self.profile is not None:
            self.profile.highlight(None)

    def about(self):
        from .gui.dlgabout import DlgAbout

        DlgAbout(self.iface.mainWindow()).exec_()

    def showSettings(self):
        settings_dlg = QgepSettingsDialog(self.iface.mainWindow())
        settings_dlg.exec_()
Example #43
0
class MetaSearchPlugin(object):

    """base plugin"""

    def __init__(self, iface):
        """init"""

        self.iface = iface
        self.context = StaticContext()
        self.action_run = None
        self.action_help = None
        self.dialog = None
        self.web_menu = '&MetaSearch'

    def initGui(self):
        """startup"""

        # run
        run_icon = QIcon('%s/%s' % (self.context.ppath,
                                    'images/MetaSearch.png'))
        self.action_run = QAction(run_icon, 'MetaSearch',
                                  self.iface.mainWindow())
        self.action_run.setWhatsThis(QCoreApplication.translate('MetaSearch',
                                                                'MetaSearch plugin'))
        self.action_run.setStatusTip(QCoreApplication.translate('MetaSearch',
                                                                'Search Metadata Catalogs'))

        self.action_run.triggered.connect(self.run)

        self.iface.addWebToolBarIcon(self.action_run)
        self.iface.addPluginToWebMenu(self.web_menu, self.action_run)

        # help
        help_icon = QgsApplication.getThemeIcon('/mActionHelpContents.svg')
        self.action_help = QAction(help_icon, 'Help', self.iface.mainWindow())
        self.action_help.setWhatsThis(QCoreApplication.translate('MetaSearch',
                                                                 'MetaSearch plugin help'))
        self.action_help.setStatusTip(QCoreApplication.translate('MetaSearch',
                                                                 'Get Help on MetaSearch'))
        self.action_help.triggered.connect(self.help)

        self.iface.addPluginToWebMenu(self.web_menu, self.action_help)

        # prefab the dialog but not open it yet
        self.dialog = MetaSearchDialog(self.iface)

    def unload(self):
        """teardown"""

        # remove the plugin menu item and icon
        self.iface.removePluginWebMenu(self.web_menu, self.action_run)
        self.iface.removePluginWebMenu(self.web_menu, self.action_help)
        self.iface.removeWebToolBarIcon(self.action_run)

    def run(self):
        """open MetaSearch"""

        self.dialog.exec_()

    def help(self):
        """open help in user's default web browser"""

        open_url(get_help_url())
Example #44
0
class QRAVE:
    """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
        self.tm = QgsApplication.taskManager()
        self.qproject = QgsProject.instance()

        self.pluginIsActive = False

        self.dockwidget = None
        self.metawidget = None

        # Populated on load from a URL
        self.acknowledgements = None

        # 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',
                                   'QRAVE_{}.qm'.format(locale))
        self.settings = Settings(iface=self.iface)

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)
            QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Riverscapes Plugin (QRAVE)')

        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'QRAVE')
        self.toolbar.setObjectName(u'QRAVE')

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

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

        self.openAction = QAction(
            QIcon(':/plugins/qrave_toolbar/RaveAddIn_16px.png'),
            self.tr(u'Riverscapes Plugin (QRAVE)'), self.iface.mainWindow())
        self.openAction.triggered.connect(self.toggle_widget)

        self.openAction.setStatusTip('Toggle the project viewer')
        self.openAction.setWhatsThis('Toggle the project viewer')

        self.openProjectAction = QAction(
            QIcon(':/plugins/qrave_toolbar/OpenProject.png'),
            self.tr(u'Open Riverscapes Project'), self.iface.mainWindow())
        self.openProjectAction.triggered.connect(self.projectBrowserDlg)

        self.openProjectAction.setStatusTip('Open QRAVE project')
        self.openProjectAction.setWhatsThis('Open QRAVE project')

        self.helpButton = QToolButton()
        self.helpButton.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.helpButton.setMenu(QMenu())
        self.helpButton.setPopupMode(QToolButton.MenuButtonPopup)

        m = self.helpButton.menu()

        # TODO: get the local help working
        # self.helpAction = QAction(
        #     QIcon(':/plugins/qrave_toolbar/Help.png'),
        #     self.tr('Help'),
        #     self.iface.mainWindow()
        # )
        # self.helpAction.triggered.connect(partial(showPluginHelp, None, filename=':/plugins/qrave_toolbar/help/build/html/index'))
        # self.websiteAction = QAction(
        #     QIcon(':/plugins/qrave_toolbar/RaveAddIn_16px.png'),
        #     self.tr('Website'),
        #     self.iface.mainWindow()
        # )
        # self.websiteAction.triggered.connect(lambda: QDesktopServices.openUrl(QUrl("http://rave.riverscapes.xyz")))

        self.helpAction = QAction(QIcon(':/plugins/qrave_toolbar/Help.png'),
                                  self.tr('Help'), self.iface.mainWindow())
        self.helpAction.triggered.connect(lambda: QDesktopServices.openUrl(
            QUrl("http://rave.riverscapes.xyz")))

        self.raveOptionsAction = QAction(
            QIcon(':/plugins/qrave_toolbar/Options.png'), self.tr('Settings'),
            self.iface.mainWindow())
        self.raveOptionsAction.triggered.connect(self.options_load)

        self.net_sync_action = QAction(
            QIcon(':/plugins/qrave_toolbar/refresh.png'),
            self.tr('Update resources'), self.iface.mainWindow())
        self.net_sync_action.triggered.connect(
            lambda: self.net_sync_load(force=True))

        self.find_resources_action = QAction(
            QIcon(':/plugins/qrave_toolbar/BrowseFolder.png'),
            self.tr('Find Resources folder'), self.iface.mainWindow())
        self.find_resources_action.triggered.connect(self.locateResources)

        self.about_action = QAction(
            QIcon(':/plugins/qrave_toolbar/RaveAddIn_16px.png'),
            self.tr('About QRAVE'), self.iface.mainWindow())
        self.about_action.triggered.connect(self.about_load)

        m.addAction(self.helpAction)
        # m.addAction(self.websiteAction)
        m.addAction(self.raveOptionsAction)
        m.addAction(self.net_sync_action)
        m.addSeparator()
        m.addAction(self.find_resources_action)
        m.addAction(self.about_action)
        self.helpButton.setDefaultAction(self.helpAction)

        self.toolbar.addAction(self.openAction)
        self.toolbar.addAction(self.openProjectAction)
        self.toolbar.addWidget(self.helpButton)

        # Do a check to see if the stored version is different than the current version
        lastVersion = self.settings.getValue('pluginVersion')

        # This does a lazy netsync (i.e. it will run it if it feels like it)
        versionChange = lastVersion != __version__
        self.net_sync_load(force=versionChange)

        if versionChange:
            QgsMessageLog.logMessage(
                "Version change detected: {} ==> {}".format(
                    lastVersion, __version__),
                'QRAVE',
                level=Qgis.Info)
            self.settings.setValue('pluginVersion', __version__)

    def onProjectLoad(self, doc):
        # If the project has the plugin enabled then restore it.
        qrave_enabled, type_conversion_ok = self.qproject.readEntry(
            CONSTANTS['settingsCategory'], 'enabled')
        if type_conversion_ok and qrave_enabled == '1':
            self.toggle_widget(forceOn=True)
            if self.dockwidget is not None:
                self.dockwidget.reload_tree()

    def onClosePlugin(self):
        """Cleanup necessary items here when plugin dockwidget is closed"""
        if self.metawidget is not None:
            self.metawidget.hide()
        if self.dockwidget is not None:
            self.dockwidget.hide()

        # disconnects
        self.dockwidget.closingPlugin.disconnect(self.onClosePlugin)
        self.qproject.readProject.disconnect(self.onProjectLoad)
        # remove this statement if dockwidget is to remain
        # for reuse if plugin is reopened
        self.dockwidget = None

        self.pluginIsActive = False

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        if self.metawidget is not None:
            self.metawidget.hide()
        if self.dockwidget is not None:
            self.dockwidget.hide()

        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'&Riverscapes Plugin (QRAVE)'), action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar

    def toggle_widget(self, forceOn=False):
        """Toggle the widget open and closed when clicking the toolbar"""
        if not self.pluginIsActive:
            self.pluginIsActive = True

            # dockwidget may not exist if:
            #    first run of plugin
            #    removed on close (see self.onClosePlugin method)
            if self.dockwidget is None:
                # Create the dockwidget (after translation) and keep reference
                self.dockwidget = QRAVEDockWidget()
                self.metawidget = QRAVEMetaWidget()
                # Hook metadata changes up to the metawidget
                self.dockwidget.metaChange.connect(self.metawidget.load)

                # Run a network sync operation to get the latest stuff. Don't force it.
                #  This is just a quick check
                self.net_sync_load()

            # connect to provide cleanup on closing of dockwidget
            self.dockwidget.closingPlugin.connect(self.onClosePlugin)

            # show the dockwidget
            self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget)
            self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.metawidget)
            self.dockwidget.show()

        else:
            if self.dockwidget is not None:
                if self.dockwidget.isHidden():
                    self.dockwidget.show()
                elif forceOn is False:
                    self.dockwidget.hide()

        # The metawidget always starts hidden
        if self.metawidget is not None:
            self.metawidget.hide()

        if self.dockwidget is not None and not self.dockwidget.isHidden():
            self.qproject.writeEntry(CONSTANTS['settingsCategory'], 'enabled',
                                     True)
        else:
            self.qproject.removeEntry(CONSTANTS['settingsCategory'], 'enabled')

    def net_sync_load(self, force=False):
        """
        Periodically check for new files
        """

        lastDigestSync = self.settings.getValue('lastDigestSync')
        lastVersion = self.settings.getValue('pluginVersion')

        currTime = int(time())  # timestamp in seconds
        plugin_init = self.settings.getValue('initialized')
        autoUpdate = self.settings.getValue('autoUpdate')

        self.netsync = NetSync('Sync QRAVE resource files')

        perform_sync = False

        # setting the force flag overrides everything else
        if force:
            perform_sync = True

        # Otherwise you only get a sync if 'autoUpdate' is turned on
        elif autoUpdate:
            # If this is an old version or the plugin is uninitialized
            if not plugin_init or lastVersion != __version__ or self.netsync.need_sync:
                perform_sync = True
            # If we haven't checked for more than `digestSyncFreqHours` hours
            elif isinstance(lastDigestSync, int) \
                    and ((currTime - lastDigestSync) / 3600) > CONSTANTS['digestSyncFreqHours']:
                perform_sync = True

        if perform_sync is False:
            self.netsync = None
            return

        # Trigger the dockwidget to repaint after the netsync
        if self.dockwidget is not None:
            self.netsync.taskCompleted.connect(self.dockwidget.reload_tree)

        # FOR DEBUGGING ONLY. NEVER IN PRODUCTION
        # self.netsync.run()

        # COMMENT THIS OUT AND USE THE LINE ABOVE FOR SYNCHRONOUS DEBUGGING
        self.tm.addTask(self.netsync)

    def projectBrowserDlg(self):
        """
        Browse for a project directory
        :return:
        """
        last_browse_path = self.settings.getValue('lastBrowsePath')
        last_dir = os.path.dirname(
            last_browse_path) if last_browse_path is not None else None

        dialog_return = QFileDialog.getOpenFileName(
            self.dockwidget, "Open a Riverscapes project", last_dir,
            self.tr("Riverscapes Project files (project.rs.xml)"))
        if dialog_return is not None and dialog_return[
                0] != "" and os.path.isfile(dialog_return[0]):
            # We set the proect path in the project settings. This way it will be saved with the QgsProject file
            if self.dockwidget is None or self.dockwidget.isHidden() is True:
                self.toggle_widget(forceOn=True)
            self.dockwidget.add_project(dialog_return[0])

    def locateResources(self):
        """This the OS-agnostic "show in Finder" or "show in explorer" equivalent
        It should open the folder of the item in question

        Args:
            fpath (str): [description]
        """
        qurl = QUrl.fromLocalFile(RESOURCES_DIR)
        QDesktopServices.openUrl(qurl)

    def options_load(self):
        """
        Open the options/settings dialog
        """
        dialog = OptionsDialog()
        if self.dockwidget:
            dialog.dataChange.connect(self.dockwidget.dataChange)
        dialog.exec_()

    def about_load(self):
        """
        Open the About dialog
        """
        dialog = AboutDialog()
        if self.acknowledgements is None:
            self.acknowledgements = requests.get(
                'http://rave.riverscapes.xyz/dotnetack.html').text

        dialog.acknowledgements.setText(self.acknowledgements)
        dialog.exec_()