Exemplo n.º 1
0
class DebugVSPlugin(QObject):
    def __init__(self, iface):
        super().__init__()
        self.iface = iface
        self.ptvsd = None
        try:
            import ptvsd
            self.ptvsd = ptvsd
        except:
            pass
        self.port = 5678
        self.host = 'localhost'
        self.actionsScript = []

        self.toolButton = QToolButton()
        self.toolButton.setMenu(QMenu())
        self.toolButton.setPopupMode(QToolButton.MenuButtonPopup)
        self.toolBtnAction = self.iface.addToolBarWidget(self.toolButton)

        self.msgBar = iface.messageBar()
        self.pluginName = 'DebugVS'
        self.nameActionEnable = 'Enable Debug for Visual Studio'
        self.action = None
        # Check exist sys.argv - /ptvsd/.../pydevd_process_net_command
        if not hasattr(sys, 'argv'):
            sys.argv = []

    def initGui(self):
        # Action Run
        icon = QIcon(os.path.join(os.path.dirname(__file__), 'code.svg'))
        self.actionEnable = QAction(icon, self.nameActionEnable,
                                    self.iface.mainWindow())
        self.actionEnable.setToolTip(self.nameActionEnable)
        self.actionEnable.triggered.connect(self.enable)
        self.iface.addPluginToMenu(f"&{self.nameActionEnable}",
                                   self.actionEnable)
        # Action Load Script
        title = 'Load script'
        icon = QgsApplication.getThemeIcon('mActionScriptOpen.svg')
        self.actionLoad = QAction(icon, title, self.iface.mainWindow())
        self.actionLoad.setToolTip(title)
        self.actionLoad.triggered.connect(self.load)
        self.iface.addPluginToMenu(f"&{self.nameActionEnable}",
                                   self.actionLoad)
        #
        m = self.toolButton.menu()
        m.addAction(self.actionEnable)
        m.addAction(self.actionLoad)
        self.toolButton.setDefaultAction(self.actionEnable)

    def unload(self):
        for action in [self.actionEnable, self.actionLoad
                       ] + self.actionsScript:
            self.iface.removePluginMenu(f"&{self.nameActionEnable}", action)
            self.iface.removeToolBarIcon(action)
            self.iface.unregisterMainWindowAction(action)

        self.iface.removeToolBarIcon(self.toolBtnAction)

    def _addActionScript(self, filename):
        icon = QgsApplication.getThemeIcon('processingScript.svg')
        title = os.path.split(filename)[-1]
        action = QAction(icon, title, self.iface.mainWindow())
        action.setToolTip(filename)
        action.triggered.connect(self.run)
        m = self.toolButton.menu()
        m.addAction(action)

        self.actionsScript.append(action)

    def _existsActionScript(self, filename):
        filenames = [a.toolTip() for a in self.actionsScript]
        return filename in filenames

    def _checkEnable(self):
        if not self.ptvsd.is_attached():
            self.msgBar.popWidget()
            msg = f"{self.nameActionEnable} AND attach in Visual Studio Code"
            self.msgBar.pushWarning(self.pluginName, msg)
            return False
        return True

    @pyqtSlot(bool)
    def enable(self, checked):
        self.msgBar.popWidget()
        if self.ptvsd is None:
            self.msgBar.pushCritical(self.pluginName,
                                     "Need install ptvsd: pip3 install ptvsd")
            return
        msgPort = f'"request": "attach", "Port": {self.port}, "host": "{self.host}"'
        if self.ptvsd.is_attached():
            self.msgBar.pushWarning(
                self.pluginName,
                f"Remote Debug for Visual Studio is active({msgPort})")
            return
        t_, self.port = self.ptvsd.enable_attach(address=(self.host,
                                                          self.port))
        msgPort = f'"request": "attach", "Port": {self.port}, "host": "{self.host}"'
        self.msgBar.pushInfo(
            self.pluginName,
            f"Remote Debug for Visual Studio is running({msgPort})")

    @pyqtSlot(bool)
    def load(self, checked):
        if not self._checkEnable():
            return

        filename, _ = QFileDialog.getOpenFileName(None, 'Debug script', '',
                                                  'Python Files (*.py)')
        if not filename:
            return

        self.ptvsd.wait_for_attach()
        execfile_(filename)

        if not self._existsActionScript(filename):
            self._addActionScript(filename)

    @pyqtSlot(bool)
    def run(self, checked):
        if not self._checkEnable():
            return

        action = self.sender()
        filename = action.toolTip()

        self.ptvsd.wait_for_attach()
        execfile_(filename)
Exemplo n.º 2
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()
        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()
Exemplo n.º 3
0
class QWaterPlugin(object):
    # Store settings in QGIS projects under this key
    SETTINGS = "QWater"  #"ghydraulics""QWater"

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

        # Create the dialog (after translation) and keep reference
        self.dlg = QWaterSettingsDialog()  #QWater_SettingsDialog()
        #self.dlg.setWindowModality( Qt.WindowStaysOnTopHint ) #ApplicationModal
        self.dlg.setWindowFlag(Qt.WindowStaysOnTopHint)
        self.VazaoClasse = QWater_02Flow()
        self.common = QWater_00Common()
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        try:
            pluginMetadata = configparser.ConfigParser()
            pluginMetadata.read(os.path.join(self.plugin_dir, 'metadata.txt'))
            self.VERSION = pluginMetadata.get('general', 'version')
            '''
            from qgis.gui import QgsPluginManagerInterface
            plugInter = iface.pluginManagerInterface()
            #plugInter.showPluginManager()
            meta = plugInter.pluginMetadata(self.SETTINGS)#'QWater'
            self.VERSION = meta['version_installed']
            '''
        except:
            self.VERSION = "3.0.0"

        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'QWater_{}.qm'.format(locale))

        if os.path.exists(locale_path):  #se n for pt traduz pra ingles
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        QgsMessageLog.logMessage(
            'Qt:{} QWater:{} Lng: {}'.format(qVersion(), self.VERSION, locale),
            self.SETTINGS, Qgis.Info)

    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(QWaterPlugin.SETTINGS, message)

    def initGui(self):
        # create actions
        defIconPath = ":/plugins/QWater/icons/qwater.svg"
        self.action = QAction(QIcon(':/plugins/QWater/icons/sizing.svg'),
                              'Calculate economic diameters',
                              self.iface.mainWindow())
        self.action.setWhatsThis(
            "Calculate economic pipe diameters based on flow data.")
        self.settingsAction = QAction(
            QIcon(':/plugins/QWater/icons/00settings.svg'), 'Settings',
            self.iface.mainWindow())
        self.makeModelAction = QAction(
            QIcon(':/plugins/QWater/icons/makemodel.svg'), 'Make Model',
            self.iface.mainWindow())
        self.fillFieldsAction = QAction(
            QIcon(':/plugins/QWater/icons/fields_fill.svg'), 'Fill up Fields',
            self.iface.mainWindow())
        self.writeInpAction = QAction(
            QIcon(':/plugins/QWater/icons/epanet.svg'),
            'Write EPANET INP file', self.iface.mainWindow())
        self.runEpanetAction = QAction(QIcon(':/plugins/QWater/icons/run.svg'),
                                       'Run EPANET simulation',
                                       self.iface.mainWindow())
        self.aboutAction = QAction(
            QIcon(":/plugins/QWater/icons/qwater.svg"),
            QCoreApplication.translate('GHydraulics', "&About"),
            self.iface.mainWindow())

        self.LoadStylesAction = QAction(
            QIcon(":/plugins/QWater/icons/style.svg"), "Load default styles",
            self.iface.mainWindow())
        self.GetElevationAction = QAction(
            QIcon(":/plugins/QWater/icons/getelevation.svg"),
            "Get Elevation from Raster", self.iface.mainWindow())
        self.vazaoAction = QAction(QIcon(':/plugins/QWater/icons/01vazao.svg'),
                                   self.tr('Calc Flow'),
                                   self.iface.mainWindow())
        self.renameAction = QAction(
            QIcon(':/plugins/QWater/icons/01rename.svg'), 'Renumber Network',
            self.iface.mainWindow())
        self.updateDN_Action = QAction(
            QIcon(":/plugins/QWater/icons/qwater.svg"), "Update DN field",
            self.iface.mainWindow())

        # Connect actions to triggers
        self.action.triggered.connect(self.run)
        self.settingsAction.triggered.connect(self.showSettings)
        self.makeModelAction.triggered.connect(self.makeModel)
        self.fillFieldsAction.triggered.connect(self.fillFields)
        self.writeInpAction.triggered.connect(self.writeInpFile)
        self.GetElevationAction.triggered.connect(self.GetElevation)
        self.updateDN_Action.triggered.connect(self.update_DN)

        self.runEpanetAction.triggered.connect(self.runEpanet)
        self.aboutAction.triggered.connect(self.about)

        self.RenameClasse = Rename_Tools(self.iface)
        self.renameAction.triggered.connect(self.RenameCall)

        Qwflow = QWater_02Flow().CalcFlow
        self.vazaoAction.triggered.connect(
            self.VazaoClasse.CalcFlow
        )  #self.Vazao #ListNoDemandNodes #QWater_02Flow.CalcFlow

        self.LoadStylesAction.triggered.connect(self.LoadStyles)

        #Create toolbar
        self.toolbar = self.iface.addToolBar('&QWater')
        self.toolbar.setObjectName('&QWater')

        # add toolbar buttons
        self.toolbar.addAction(self.settingsAction)
        self.toolbar.addAction(self.makeModelAction)
        self.toolbar.addAction(self.renameAction)
        self.toolbar.addAction(self.fillFieldsAction)
        self.toolbar.addAction(self.vazaoAction)
        self.toolbar.addAction(self.action)
        self.toolbar.addAction(self.runEpanetAction)
        #self.iface.addToolBarIcon(self.settingsAction)

        #Add separator
        self.toolbar.addSeparator()

        # Add ToolButton (with Menu)
        self.menuButton = QToolButton()  #QPushButton()#QToolButton
        self.menuButton.setMenu(QMenu())
        self.menuButton.setPopupMode(QToolButton.MenuButtonPopup)
        # self.menuButton.setAutoRaise(True)

        m = self.menuButton.menu()
        m.addAction(self.LoadStylesAction)
        m.addAction(self.writeInpAction)
        m.addAction(self.GetElevationAction)
        m.addAction(self.updateDN_Action)

        self.menuButton.setDefaultAction(self.GetElevationAction)
        self.menuButtonAction = self.toolbar.addWidget(self.menuButton)

        # add menu items
        self.iface.addPluginToMenu("&QWater", self.settingsAction)
        self.iface.addPluginToMenu('&QWater', self.makeModelAction)
        self.iface.addPluginToMenu('&QWater', self.renameAction)
        self.iface.addPluginToMenu('&QWater', self.fillFieldsAction)
        self.iface.addPluginToMenu('&QWater', self.vazaoAction)
        self.iface.addPluginToMenu("&QWater", self.action)
        self.iface.addPluginToMenu('&QWater', self.runEpanetAction)

        # tools submenu
        self.tools_menu = QMenu('&Tools')
        self.tools_menu.addAction(self.LoadStylesAction)
        self.tools_menu.addAction(self.writeInpAction)
        self.tools_menu.addAction(self.GetElevationAction)
        self.tools_menu.addAction(self.updateDN_Action)

        # Projects submenu
        self.project_menu = QMenu('&Projects')

        self.newProjectAction = QAction(self.iface.actionNewProject().icon(),
                                        'New Project', self.iface.mainWindow())
        self.newProjectAction.triggered.connect(self.newProject)
        self.project_menu.addAction(self.newProjectAction)

        self.sampleDwCmdAction = QAction(
            QIcon(':/python/plugins/ghydraulic/icon.xpm'),
            'Sample Darcy-Weisbach, cubic meters/day', self.iface.mainWindow())
        self.sampleDwCmdAction.triggered.connect(self.openDwCmdSample)
        self.project_menu.addAction(self.sampleDwCmdAction)

        self.sampleDwLpsAction = QAction(
            QIcon(':/python/plugins/ghydraulic/icon.xpm'),
            'Sample Darcy-Weisbach, liters/second', self.iface.mainWindow())
        self.sampleDwLpsAction.triggered.connect(self.openDwLpsSample)
        self.project_menu.addAction(self.sampleDwLpsAction)

        self.sampleHwGpmAction = QAction(
            QIcon(':/python/plugins/ghydraulic/icon.xpm'),
            'Sample Hazen-Williams, gallons/min', self.iface.mainWindow())
        self.sampleHwGpmAction.triggered.connect(self.openHwGpmSample)
        self.project_menu.addAction(self.sampleHwGpmAction)

        # Back in main menu
        self.iface.addPluginToMenu("&QWater", self.tools_menu.menuAction())
        self.iface.addPluginToMenu("&QWater", self.project_menu.menuAction())
        self.iface.addPluginToMenu("&QWater", self.aboutAction)

    def unload(self):
        # remove the plugin menu item and icon
        self.iface.removePluginMenu("&QWater", self.aboutAction)
        self.iface.removePluginMenu('&QWater', self.runEpanetAction)
        self.iface.removePluginMenu("&QWater", self.writeInpAction)
        self.iface.removePluginMenu("&QWater", self.GetElevationAction)
        self.iface.removePluginMenu("&QWater", self.LoadStylesAction)
        self.iface.removePluginMenu("&QWater", self.updateDN_Action)

        self.iface.removePluginMenu('&QWater', self.vazaoAction)
        self.iface.removePluginMenu('&QWater', self.makeModelAction)
        self.iface.removePluginMenu('&QWater', self.fillFieldsAction)
        self.iface.removePluginMenu('&QWater', self.renameAction)
        self.iface.removePluginMenu("&QWater", self.settingsAction)
        self.iface.removePluginMenu("&QWater", self.action)
        self.iface.removePluginMenu("&QWater", self.project_menu.menuAction())
        self.iface.removePluginMenu("&QWater", self.tools_menu.menuAction())
        self.iface.removeToolBarIcon(self.settingsAction)
        self.toolbar.removeAction(self.settingsAction)
        self.toolbar.removeAction(self.LoadStylesAction)
        self.toolbar.removeAction(self.GetElevationAction)
        self.toolbar.removeAction(self.updateDN_Action)

        self.toolbar.removeAction(self.vazaoAction)
        self.toolbar.removeAction(self.runEpanetAction)
        self.toolbar.removeAction(self.action)
        self.toolbar.removeAction(self.renameAction)

        # remove the toolbar
        del self.toolbar

    def RenameCall(self):
        self.RenameClasse.initGui()

    def fillFields(self):
        proj = QgsProject.instance()
        autolen = proj.readEntry(QWaterPlugin.SETTINGS, 'autolength', "0")[0]
        undefs = False
        preencheu = False
        fillCOLUMNS = {
            'JUNCTIONS': {
                'ELEVATION': 0
            },
            'PIPES': {
                'LENGTH': 'CALCULA',
                'DIAMETER': 54.6,
                'ROUGHNESS': 1,
                'MINORLOSS': 0,
                'STATUS': 'OPEN'
            }
        }
        for secao in ['PIPES', 'JUNCTIONS']:
            vLayer = self.common.PegaQWaterLayer(secao)
            if vLayer != False:
                feicoes = vLayer.getFeatures()
                vLayer.startEditing()
                for feicao in feicoes:
                    camposPadroes = fillCOLUMNS[secao]
                    for (campo, valorPad) in camposPadroes.items():
                        featVal = feicao[campo]
                        if campo == 'LENGTH' and autolen == '1':
                            ext = feicao.geometry().length()
                            feicao[campo] = ext
                            preencheu = True
                        else:
                            if featVal == NULL or featVal is None:
                                feicao[campo] = valorPad
                                preencheu = True
                    vLayer.updateFeature(feicao)
            else:
                undefs = True
#        self.warning('Fill Fields call not working yet')
        if not undefs:
            if preencheu:
                self.warning('Successfull fill in!', Qgis.Info)
            else:
                self.warning('Nothing to fill in!', Qgis.Info)

    # Calculate economic diameters
    def run(self):
        # Check for "LPS" flow units
        dlg = self.dlg  #GHydraulicsSettingsDialog()
        template = dlg.getTemplate()
        inp = GHydraulicsInpReader(template)
        inpunits = inp.getValue('OPTIONS', 'Units').upper()
        if inpunits != EpanetModel.LPS:
            self.warning(
                '"Calculate economic diameters" requires "LPS" flow units instead of "'
                + inpunits + '". Please change the template INP file.')
            return

        maker = GHydraulicsModelMaker(template)
        self.checkModel(maker)

        # Let user agree to the change
        selectedbutton = QMessageBox.question(
            self.iface.mainWindow(), self.SETTINGS,
            "This will overwrite all DIAMETER and ROUGHNESS field values using Pipes Table data from settings Dialog. Do you want to continue?",
            QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel)
        if QMessageBox.Cancel == selectedbutton:
            return

        # Execute the action
        ecodia = GhyEconomicDiameter(GHydraulicsModel.RESULT_FLO,
                                     EpanetModel.DIAMETER)
        maker.beginEditCommand('Calculate economic diameters')
        try:
            maker.eachLayer(ecodia.commitEconomicDiametersForLayer,
                            [EpanetModel.PIPES])
        except GHydraulicsException as e:
            self.warning(str(e))
        maker.endEditCommand()
        self.update_DN()

    # Display the About dialog
    def about(self):
        infoString = self.tr(
            self.SETTINGS + " Plugin " + self.VERSION +
            "<br />This plugin integrates EPANET with QGIS.<br />Copyright (c) 2017 - 2017 Jorge Almerio<br /><a href=\"https://github.com/jorgealmerio/QWater/blob/master/README.md\">github.com/jorgealmerio/QWater</a>\n"
        )
        QMessageBox.information(self.iface.mainWindow(),
                                "About " + self.SETTINGS, infoString)

    # Display the settings dialog
    def showSettings(self):
        dlg = self.dlg  #QWaterSettingsDialog()
        proj = QgsProject.instance()
        layers = proj.mapLayers()
        hasVectorLayers = False

        msgs = ''
        QWaterEntries = proj.entryList(QWaterPlugin.SETTINGS, '')
        GhydraulicsEntries = proj.entryList('ghydraulics', '')
        # Restore selected layers
        for secao in EpanetModel.GIS_SECTIONS:
            #Create QgsMapLayerComboBox filters
            widget = dlg.findChild(QgsMapLayerComboBox, 'CMB' + secao)
            if secao in GHydraulicsModel.NODE_SECTIONS:
                widget.setFilters(QgsMapLayerProxyModel.PointLayer)
            else:
                if secao == 'ZONES':
                    widget.setFilters(QgsMapLayerProxyModel.PolygonLayer)
                else:
                    widget.setFilters(QgsMapLayerProxyModel.LineLayer)
            widget.setAllowEmptyLayer(
                True
            )  #added in QGIS 3.0: Sets whether an optional empty layer ("not set") option is shown in the combo box
            #Read and restore file Entries
            if secao in QWaterEntries:
                lyrName = proj.readEntry(QWaterPlugin.SETTINGS, secao, "")[0]
                layerEntry = proj.mapLayersByName(lyrName)
                if layerEntry:
                    widget.setLayer(layerEntry[0])
                    msgs += '\n{}:{} -> QWater Layer found'.format(
                        secao, lyrName)
                else:
                    msgs += '\n{}:{} -> QWater Layer NOT found'.format(
                        secao, lyrName)
                    widget.setLayer(None)
            elif secao in GhydraulicsEntries:  #if has Not QWater settings try to get ghydraulics settings
                pickle_list = str(proj.readEntry('ghydraulics', secao, "")[0])
                if '' != pickle_list:
                    # Windows QGIS injects some carriage returns here
                    pickle_list = pickle_list.replace(
                        '\r', '').encode()  #use encode convet to byte
                    try:
                        l = loads(pickle_list)
                        valor = l
                        if valor:
                            layerEntry = proj.mapLayersByName(valor[0])
                            if layerEntry:
                                widget.setLayer(layerEntry[0])
                                msgs += '\n{}:{} -> GHydraulics Layer found'.format(
                                    secao, layerEntry[0].name())
                            else:
                                widget.setLayer(None)
                                msgs += '\n{}:{} -> GHydraulics Layer NOT found'.format(
                                    secao, valor[0])
                        else:
                            widget.setLayer(None)
                            msgs += '\n{} -> GHydraulics Previous Settings Null'.format(
                                secao)
                    except (KeyError):
                        widget.setLayer(None)
                        # fix_print_with_import
                        print('Error on section:' + secao)
                        continue
            else:
                msgs += '\n{} -> Previous Settings NOT found'.format(secao)
                widget.setLayer(None)

        #if msgs!='':
        #    print msgs

        # Restore template inp file
        template = dlg.getTemplate()
        dlg.ui.inpFileLineEdit.setText(template)
        # Restore auto length checkbox
        dlg.ui.autoLengthCB.setChecked(dlg.getAutoLength())
        # Restore backdrop checkbox
        dlg.ui.writeBackdropCB.setChecked(dlg.getWriteBackdrop())

        # Restore data variables
        dataDefs = QWaterModel.DATA_DEFS
        for dataDf, defVal in dataDefs.items():
            #Get widget
            widget = dlg.findChild(QLineEdit, 'Txt_' + dataDf)
            inVar = proj.readEntry(QWaterPlugin.SETTINGS, dataDf, defVal)[0]
            widget.setText(inVar)

        #Carrega Tubos
        tubosMat = proj.readEntry(QWaterPlugin.SETTINGS, "TUBOS_MAT", "0")[0]
        if tubosMat == '0':  #se nao tiver lista de materiais definidas carrega o padrao do modelo
            tubos = QWaterModel.TUBOS_MAT
        else:
            tubos = eval(tubosMat)
            if not isinstance(tubos[0][0], str):
                QgsMessageLog.logMessage('Wrong Pipes settings' + tubosMat,
                                         self.SETTINGS,
                                         Qgis.Warning)  #Show Warning Message
                tubos = QWaterModel.TUBOS_MAT
            #else:
            #QgsMessageLog.logMessage('Right Pipes settings'+tubosMat,self.SETTINGS,Qgis.Info) #Show Info Message
        self.carregaTabMats(tubos)

        # Exibe o resumo de extensoes de rede se tiver PIPES definido
        ProjVar = proj.readEntry(QWaterPlugin.SETTINGS, 'PIPES')[0]

        if ProjVar != '':
            try:
                myLayer = proj.mapLayersByName(ProjVar)[0]
                tot, geo = QWater_00Common().CompRealGeom(myLayer)

                msgTxt = self.tr(
                    u'<span style=" color:#0000ff;">Geometric Length: {0:.2f} m</span>'
                ).format(geo)
                dlg.ui.lbl_extGeo.setText(msgTxt)
                msgTxt = ''

                if tot > 0:
                    msgTxt = self.tr(
                        u'<span style=" color:#37c322;">Length Field Sum: {0:.2f} m</span>'
                    ).format(tot)
                dlg.ui.lbl_extReal.setText(msgTxt)
                msgTxt = ''
            except:
                pass

        #Call Combobox Zones activated signal to refresh it
        cmbZones = dlg.ui.CMBZONES
        cmbZones.activated.emit(cmbZones.currentIndex())

        dlg.ui.Txt_POPINI.editingFinished.emit()
        # show the dialog
        dlg.show()
        #for i in range(0, dlg.UNUSED_ITEM+1):
        #    dlg.ui.treeWidget.topLevelItem(i).setExpanded(True)
        #result = dlg.exec_()
        result = dlg.exec_()
        if result:
            self.accepted()

    def accepted(self):
        # Store layers
        dlg = self.dlg  #QWaterSettingsDialog()
        proj = QgsProject.instance()
        for secao in EpanetModel.GIS_SECTIONS:
            #Get QgsMapLayerComboBoxs
            widget = dlg.findChild(QgsMapLayerComboBox, 'CMB' + secao)
            curlyr = widget.currentLayer()
            if not (curlyr is None):
                lyrName = curlyr.name()
            else:
                lyrName = ''
            #print secao,widget,lyrName
            proj.writeEntry(self.SETTINGS, secao, lyrName)

        #proj.writeEntry("ghydraulics",EpanetModel.GIS_SECTIONS[i], dumps(layers))
        # Store Inp file
        templatedir = os.path.join(os.path.dirname(__file__), 'etc')
        template = str(dlg.ui.inpFileLineEdit.text()).replace(
            templatedir + os.path.sep, '')
        proj.writeEntry(self.SETTINGS, "templateinpfile", template)
        # Store auto length configuration
        autoLength = dlg.STRING_FALSE
        if dlg.ui.autoLengthCB.isChecked():
            autoLength = dlg.STRING_TRUE
        proj.writeEntry(self.SETTINGS, dlg.AUTO_LENGTH, autoLength)
        # Store backdrop configuration
        writeBackdrop = dlg.STRING_FALSE
        if dlg.ui.writeBackdropCB.isChecked():
            writeBackdrop = dlg.STRING_TRUE
        proj.writeEntry(self.SETTINGS, dlg.WRITE_BACKDROP, writeBackdrop)

        # Store data variables
        dataDefs = QWaterModel.DATA_DEFS
        for dataDf, defVal in dataDefs.items():
            #Get widget
            widget = dlg.findChild(QLineEdit, 'Txt_' + dataDf)
            inVar = widget.text()
            proj.writeEntry(QWaterPlugin.SETTINGS, dataDf, inVar)

        proj.writeEntry(QWaterPlugin.SETTINGS, "TUBOS_MAT",
                        str(self.tableToArray()))

    # Display a message once
    def explainOnce(self, key, title, message):
        proj = QgsProject.instance()
        if GHydraulicsModel.STRING_TRUE == str(
                proj.readEntry(QWaterPlugin.SETTINGS, key)[0]):
            return True
        reply = QMessageBox.question(self.iface.mainWindow(), title, message,
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.Yes)
        if QMessageBox.Yes == reply:
            proj.writeEntry(QWaterPlugin.SETTINGS, key,
                            GHydraulicsModel.STRING_TRUE)
            return True
        return False

    # Check if all fields are in place
    def checkModel(self, maker):
        checker = maker.checker
        if 0 == checker.getLayerCount(
                EpanetModel.JUNCTIONS) or 0 == checker.getLayerCount(
                    EpanetModel.PIPES):
            question = 'Your junction and/or pipe layer configuration is incomplete. Do you want configure the layers now?'
            reply = QMessageBox.question(self.iface.mainWindow(),
                                         GHydraulicsModelChecker.TITLE,
                                         question,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if reply == QMessageBox.Yes:
                self.showSettings()
            if 0 == checker.getLayerCount(
                    EpanetModel.JUNCTIONS) or 0 == checker.getLayerCount(
                        EpanetModel.PIPES):
                return False
        self.checkForModifications(checker)
        missing = checker.checkFields()
        if 0 < len(missing):
            fieldlist = []
            for name in list(missing.keys()):
                fieldlist.append('<br/>Layer "' + name + '": ' +
                                 ', '.join(missing[name]))
            message = 'Your model is missing some fields.' + ''.join(
                fieldlist) + '<br/>Would you like to add them?'
            reply = QMessageBox.question(self.iface.mainWindow(),
                                         GHydraulicsModelChecker.TITLE,
                                         message,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if QMessageBox.Yes != reply:
                return False
            if not checker.addFields(missing):
                QMessageBox.critical(self.iface.mainWindow(),
                                     GHydraulicsModelChecker.TITLE,
                                     'Not all fields could be added.',
                                     QMessageBox.Ok)
                return False
        crss = checker.getCrsDictionary()
        if 1 != len(crss):
            message = 'Your model uses more than one coordinate reference system. Please use only one.'
            QMessageBox.critical(self.iface.mainWindow(),
                                 GHydraulicsModelChecker.TITLE, message,
                                 QMessageBox.Ok, QMessageBox.Ok)
            return False

        missing = checker.checkIds()
        if 0 < len(missing):
            question = 'There are ' + str(
                len(missing)
            ) + ' duplicate ' + GHydraulicsModel.ID_FIELD + ' values. Do want to fix this automatically now?'
            reply = QMessageBox.question(self.iface.mainWindow(),
                                         GHydraulicsModelChecker.TITLE,
                                         question,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if QMessageBox.Yes != reply:
                return False
            if not maker.enforceUniqueIds():
                return False
        multis = checker.getMultipartCount()
        if 0 < multis:
            question = 'There are ' + str(
                multis
            ) + ' pipes with multipart geometries possibly causing problems. Do you want to explode them now?'
            reply = QMessageBox.question(self.iface.mainWindow(),
                                         GHydraulicsModelChecker.TITLE,
                                         question,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if QMessageBox.Yes == reply:
                maker.explodeMultipartPipes()

    # Fill the node1, node2 fields
    def makeModel(self):
        if self.common.PegaQWaterLayer('PIPES') == False:
            return
        dlg = self.dlg  #GHydraulicsSettingsDialog()
        template = dlg.getTemplate()
        maker = GHydraulicsModelMaker(template)
        self.iface.mainWindow().statusBar().showMessage(
            'Checking EPANET model')
        self.checkModel(maker)
        question = 'Overwrite the fields NODE1 and NODE2 in all line tables?'
        self.iface.mainWindow().statusBar().showMessage("Making EPANET model")
        autolength = dlg.getAutoLength()
        if autolength:
            question = 'Overwrite the fields NODE1, NODE2 and LENGTH in all line tables?'
        if self.explainOnce('makeModelExplanation', 'Make EPANET Model',
                            question):
            vcount = maker.make()
            if 0 < vcount:
                reply = QMessageBox.question(
                    self.iface.mainWindow(), GHydraulicsModelChecker.TITLE,
                    'Your model is missing ' + str(vcount) +
                    ' junctions. Would you like to add them now?',
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if QMessageBox.Yes == reply:
                    self.iface.mainWindow().statusBar().showMessage(
                        'Adding missing junctions to EPANET model')
                    maker.addMissingJunctions()
                    lyrJunctions = self.common.PegaQWaterLayer('JUNCTIONS')
                    lyrJunctions.triggerRepaint()
            #dlg = GHydraulicsSettingsDialog()
            if autolength:
                self.iface.mainWindow().statusBar().showMessage(
                    'Pipe length calculation')
                maker.calculateLength()
            maker.cleanup()
        self.iface.mainWindow().statusBar().showMessage('')

    # Prevent problems with unsaved data
    def checkForModifications(self, checker):
        modified = checker.getModifiedLayers()
        if 0 < len(modified):
            message = 'Some of your model layers have not been saved (' + ', '.join(
                modified) + ').<br/>Do you want to save them now?'
            reply = QMessageBox.question(self.iface.mainWindow(),
                                         GHydraulicsInpWriter.TITLE, message,
                                         QMessageBox.Yes | QMessageBox.No,
                                         QMessageBox.Yes)
            if QMessageBox.Yes == reply:
                checker.commitChanges()

    # Write out a file in EPANET INP format
    # returns True on success, False on failure
    def writeInpFile(self):
        # Modified layers may not be exprted correctly
        self.menuButton.setDefaultAction(
            self.writeInpAction)  #Change default toolbutton to writeInpAction
        checker = GHydraulicsModelChecker()
        self.checkForModifications(checker)
        # select a file
        prjfi = os.path.splitext(QgsProject.instance().fileName())[0] + '.inp'
        f, __ = QFileDialog.getSaveFileName(self.iface.mainWindow(),
                                            GHydraulicsInpWriter.TITLE, prjfi,
                                            'EPANET INP file (*.inp)')

        if 0 < len(f):
            dlg = self.dlg  #GHydraulicsSettingsDialog()
            template = dlg.getTemplate()
            try:
                writer = GHydraulicsInpWriter(template, self.iface)
                writeBackdrop = dlg.getWriteBackdrop()
                if writeBackdrop:
                    backdropfile = writer.getBackdropFromInp(str(f))
                    question = 'Overwrite ' + os.path.basename(
                        backdropfile) + '?'
                    if os.path.exists(backdropfile) and not self.explainOnce(
                            'overwriteBackdrop', GHydraulicsInpWriter.TITLE,
                            question):
                        writeBackdrop = False
                writer.write(f, writeBackdrop)
            except GHydraulicsException as e:
                self.warning('Saving an INP file failed: ' + str(e))
                return False
            return True
        return False

    # Open CMD sample project
    def openDwCmdSample(self):
        self.iface.addProject(
            os.path.dirname(__file__) + '/samples/d-w/cmd/ghydraulics.qgs')

    # Open LPS sample project
    def openDwLpsSample(self):
        self.iface.addProject(
            os.path.dirname(__file__) + '/samples/d-w/lps/qwater_lps.qgs')

    # Open Net1 sample project
    def openHwGpmSample(self):
        self.iface.addProject(
            os.path.dirname(__file__) + '/samples/h-w/gpm/Net1.qgs')

    # Display message
    def warning(self, message, nivel=Qgis.Warning):
        self.iface.messageBar().pushMessage(self.SETTINGS,
                                            message,
                                            level=nivel,
                                            duration=4)

    # Create a new project, save and configure layers
    def newProject(self):
        self.iface.newProject()
        project = QgsProject.instance()
        crs = project.crs()  #TODO: Solicitar crs ao usuario
        baseName = project.readPath("./")
        for name in EpanetModel.GIS_SECTIONS:
            lname = name.lower()
            #self.iface.mainWindow()
            f, __ = QFileDialog.getSaveFileName(
                caption='Save new ' + lname + ' layer',
                directory=baseName + '/' + lname + '.shp',
                filter='ESRI Shapefile (*.shp)')
            if 0 == len(f):
                continue
            baseName = os.path.split(f)[0]
            fields = QgsFields()
            for i in range(0, len(EpanetModel.COLUMNS[name])):
                field = EpanetModel.COLUMNS[name][i]
                fields.append(
                    QgsField(field, GHydraulicsModel.COLUMN_TYPES[field]))
            geometrytype = QgsWkbTypes.LineString if EpanetModel.PIPES == name else QgsWkbTypes.Point
            writer = QgsVectorFileWriter(f, 'System', fields, geometrytype,
                                         crs, 'ESRI Shapefile')
            if writer.hasError() != QgsVectorFileWriter.NoError:
                self.warning('Error creating shapefile: ' +
                             str(writer.hasError()))
                continue
            del writer
            layer = self.iface.addVectorLayer(f, lname, 'ogr')
            if not layer.isValid():
                self.warning('Failed to load layer!')
                continue
            if not crs:
                crs = layer.crs()
            layers = [lname]
            project.writeEntry(self.SETTINGS, name, lname)
        self.LoadStyles()
        self.showSettings()

    def runEpanet(self):
        lyrPipe = self.common.PegaQWaterLayer('PIPES')
        if not lyrPipe:
            return
        # Get a temporary file
        t = tempfile.mkstemp(suffix='.inp')
        os.close(t[0])
        dlg = self.dlg  #self.dlg #GHydraulicsSettingsDialog()
        template = dlg.getTemplate()
        try:
            writer = GHydraulicsInpWriter(template, self.iface)
            writer.write(t[1], False)
        except GHydraulicsException as e:
            self.warning('Saving an INP file failed :' + str(e))
            return
        try:
            runner = GHydraulicsModelRunner()
            output, report, steps = runner.run(t[1])
            dlg = GHydraulicsResultDialog(runner.setStep)
            dlg.ui.textOutput.setText(output)
            dlg.ui.textReport.setText(report)
            dlg.ui.comboStep.clear()
            dlg.ui.comboStep.addItems([str(x) for x in range(1, steps + 1)])
            dlg.show()
            result = dlg.exec_()
        except GHydraulicsException as e:
            self.warning('Running a simulation failed :' + str(e))
        os.unlink(t[1])
        lyrPipe.triggerRepaint()

    def carregaTabMats(self, tbMats):
        tableWidget = self.dlg.findChild(QTableWidget, 'tableWidget')
        tableWidget.setRowCount(0)
        tableWidget.setColumnCount(0)
        for i, tbMat in enumerate(tbMats):
            row = tableWidget.rowCount()
            tableWidget.insertRow(row)
            tableWidget.setColumnCount(len(tbMat))
            if row < 1:
                tableWidget.setHorizontalHeaderLabels(tbMat)
            else:
                for column, data in enumerate(tbMat):
                    if column == 0:
                        cell_widget = QWidget()
                        lay_out = QHBoxLayout(cell_widget)
                        chk_bx = QCheckBox()
                        if data in [1, '1', 't', 'True']:
                            chk_bx.setCheckState(QtCore.Qt.Checked)
                        else:
                            chk_bx.setCheckState(QtCore.Qt.Unchecked)
                        lay_out.addWidget(chk_bx)
                        lay_out.setAlignment(Qt.AlignCenter)
                        lay_out.setContentsMargins(0, 0, 0, 0)
                        cell_widget.setLayout(lay_out)
                        tableWidget.setCellWidget(row, 0, cell_widget)
                    else:
                        item = QTableWidgetItem("{}".format(data))  #:7.2f
                        item.setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
                        tableWidget.setItem(row, column, item)
        #tableWidget.setHorizontalHeaderLabels(['On','DN','Diameter','Roughness','Pressure','Headloss','Reference'])
        #for i in range(1,4):
        #    tableWidget.resizeColumnToContents(i)
        tableWidget.removeRow(0)
        tableWidget.resizeColumnsToContents()

    def tableToArray(self):
        table = self.dlg.findChild(QTableWidget, 'tableWidget')
        result = [self.LeCabecalho(table)]
        num_rows, num_cols = table.rowCount(), table.columnCount()
        for row in range(num_rows):
            rows = []
            for col in range(num_cols):
                if col == 0:
                    cell_widget = table.cellWidget(row, col).findChild(
                        type(QCheckBox()))
                    if cell_widget.isChecked(
                    ):  #QTableWidget.item(row,column).checkState()==QtCore.Qt.Checked:
                        rows.append(1)
                    else:
                        rows.append(0)
                else:
                    item = table.item(row, col)
                    rows.append(item.text())  #if item else ''
            result.append(rows)
        return result

    def LeCabecalho(self, tblWid):
        header = []
        for column in range(tblWid.columnCount()):
            header.append(tblWid.horizontalHeaderItem(column).text())
        return header

    def LoadStyles(self):
        self.menuButton.setDefaultAction(self.LoadStylesAction)
        proj = QgsProject.instance()
        qStyles = {
            'PIPES': 'pipe_headloss.qml',
            'JUNCTIONS': 'node_pressure.qml',
            'PUMPS': 'node_pump.qml',
            'RESERVOIRS': 'node_reserv.qml',
            'TANKS': 'node_tank.qml',
            'VALVES': 'node_valve.qml'
        }  #{tipo:estilo}
        rootID = QWaterPlugin.SETTINGS
        for tipo, estilo in qStyles.items():
            ProjVar = proj.readEntry(rootID, tipo)[0]
            if ProjVar != '':
                myLayer = proj.mapLayersByName(ProjVar)[0]
                self.CarregaEstilo(myLayer, estilo)

    def CarregaEstilo(self, vLayer, Estilo):
        basepath = os.path.dirname(__file__)  #os.path.realpath(
        FullPath = os.path.join(basepath, 'style/' + Estilo)
        vLayer.loadNamedStyle(FullPath)
        vLayer.triggerRepaint()

    def GetElevation(self):
        self.menuButton.setDefaultAction(
            self.GetElevationAction
        )  #Change default toolbutton to GetElevationAction
        dlg = QDialog()
        dlg.setWindowTitle('Select Elevation Raster')

        #Combobox
        ml = QgsMapLayerComboBox()
        ml.setFilters(QgsMapLayerProxyModel.RasterLayer)

        #ButtonBox
        bb = QDialogButtonBox()
        bb.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        #layout
        layOut = QVBoxLayout()
        layOut.addWidget(ml)
        layOut.addWidget(bb)
        dlg.setLayout(layOut)
        dlg.setMinimumWidth(300)

        # Signals answers
        def ok():
            dlg.close()
            self.RasterSampling(ml.currentLayer())
            #curlyr = ml.currentLayer()
        def cancel():
            print('cancelled')
            dlg.close()

        #connect to signals
        bb.accepted.connect(ok)
        bb.rejected.connect(cancel)

        dlg.show()

    def RasterSampling(self, Raster):
        nodeLyr = self.common.PegaQWaterLayer('JUNCTIONS')
        if not nodeLyr:
            iface.messageBar().pushMessage(self.SETTINGS,
                                           'No Junction layer defined!',
                                           level=Qgis.Warning,
                                           duration=5)
            return
        noElevPtos = []
        nodeLyr.startEditing()
        for pto in nodeLyr.getFeatures():
            if pto.geometry().isMultipart():
                point = pto.geometry().asMultiPoint()[0]
            else:
                point = pto.geometry().asPoint()

            rastSample = Raster.dataProvider().identify(
                point, QgsRaster.IdentifyFormatValue).results()
            #previousRastSample = rastSample
            #value, ok = Raster.dataProvider().sample(point, 1)
            value = rastSample[1]
            if value:
                pto['ELEVATION'] = value
                #print(pto['DC_ID'],'=',value)
                nodeLyr.updateFeature(pto)
            else:
                noElevPtos.append(pto.id())
        if noElevPtos:
            #print(noElevPtos)
            nodeLyr.selectByIds(noElevPtos)
            mapCanvas = iface.mapCanvas()
            mapCanvas.zoomToSelected(nodeLyr)
            iface.messageBar().pushMessage(
                self.SETTINGS,
                'Check Selected features with No Elevation data!',
                level=Qgis.Warning,
                duration=0)
        else:
            iface.messageBar().pushMessage(
                self.SETTINGS,
                'Get elevation from Raster success!',
                level=Qgis.Info,
                duration=5)
        nodeLyr.triggerRepaint()

    def update_DN(self):
        self.menuButton.setDefaultAction(self.updateDN_Action)
        #Check and get Pipes Layer
        pipeLyr = self.common.PegaQWaterLayer('PIPES')
        if not pipeLyr:
            return

        #Check and create field 'DN' #NPS (Nominal Pipe Size)
        field_index = pipeLyr.fields().indexFromName('DN')
        pipeLyr.startEditing()
        if field_index == -1:
            #if field does not exist create it
            DNfld = QgsField("DN", QVariant.Int)
            pipeLyr.addAttribute(DNfld)
            pipeLyr.updateFields()
            field_index = pipeLyr.fields().indexFromName('DN')
            editSet = QgsEditorWidgetSetup('TextEdit',
                                           {})  #{'IsMultiline': 'True'}
            pipeLyr.setEditorWidgetSetup(field_index, editSet)
        #Carrega Tubos
        proj = QgsProject.instance()
        tubosMat = proj.readEntry(self.SETTINGS, "TUBOS_MAT", "0")[0]
        if tubosMat == '0':
            raise GHydraulicsException(
                'ERROR: Please, Define Pipes on settings dialog First!')
            #tubos=QWaterModel.TUBOS_MAT
        else:
            tubos = eval(tubosMat)
            if not isinstance(tubos[0][0], str):
                raise GHydraulicsException(
                    'ERROR: Incorrect Pipes definition!. Please, Define Pipes on settings dialog First!'
                )

        cabecalho = tubos[0]
        diaIdx = cabecalho.index('Diameter')
        dnIdx = cabecalho.index('DN')
        indices = [diaIdx, dnIdx]
        diaXdn = {}
        for linha in range(1, len(tubos)):
            diam = eval(tubos[linha][diaIdx])
            diaXdn[diam] = eval(tubos[linha][dnIdx])

        #diaXdn= [[each_list[i] for i in indices] for each_list in tubos]
        noDNdef = []
        #Update DN field
        for f in pipeLyr.getFeatures():
            diam = f['DIAMETER']
            #Check if Diameter exists in Pipes Table Setting
            if diam not in diaXdn:
                noDNdef.append(f.id())
            else:
                f['DN'] = diaXdn[diam]
                pipeLyr.updateFeature(f)
        pipeLyr.triggerRepaint()
        if noDNdef:
            pipeLyr.selectByIds(noDNdef)
            mapCanvas = iface.mapCanvas()
            mapCanvas.zoomToSelected(pipeLyr)
            iface.messageBar().pushMessage(
                self.SETTINGS,
                'Check Selected features with Diameters not in Pipes Table Setting or use Calculate economic Diameters tool!',
                level=Qgis.Warning,
                duration=0)
        else:
            iface.messageBar().pushMessage(self.SETTINGS,
                                           'DN success updated!',
                                           level=Qgis.Info,
                                           duration=3)
Exemplo n.º 4
0
class QWeather:
    """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',
                                   'QWeather_{}.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)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&QWeather')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'QWeather')
        self.toolbar.setObjectName(u'QWeather')
        self.key1 = '9Q2gyTzBLVGVSTWdoJnM9Y29uc'

        self.toolButton = QToolButton()
        self.toolButton.setMenu(QMenu())
        self.toolButton.setPopupMode(QToolButton.MenuButtonPopup)
        self.toolbar.addWidget(self.toolButton)

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

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

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

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

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

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

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

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

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

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

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

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

        # Create the dialog (after translation) and keep reference

        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 _generate_signature(self, key, data):
        key_bytes = bytes(key, 'utf-8')
        data_bytes = bytes(data, 'utf-8')
        signature = hmac.new(key_bytes, data_bytes, hashlib.sha1).digest()
        return b64encode(signature).decode()

    def get_yahoo_weather(
            self,
            location,
            temp_type,
            app_id,
            consumer_key,
            consumer_secret,
            url='https://weather-ydn-yql.media.yahoo.com/forecastrss'):
        # Basic info
        method = 'GET'
        concat = '&'
        query = {'location': location, 'format': 'json', 'u': temp_type}
        oauth = {
            'oauth_consumer_key': consumer_key,
            'oauth_nonce': uuid.uuid4().hex,
            'oauth_signature_method': 'HMAC-SHA1',
            'oauth_timestamp': str(int(time.time())),
            'oauth_version': '1.0'
        }

        # Prepare signature string (merge all params and SORT them)
        merged_params = query.copy()
        merged_params.update(oauth)
        sorted_params = [
            k + '=' + urllib.parse.quote(merged_params[k], safe='')
            for k in sorted(merged_params.keys())
        ]
        signature_base_str = method + concat + urllib.parse.quote(
            url, safe='') + concat + urllib.parse.quote(
                concat.join(sorted_params), safe='')

        # Generate signature
        composite_key = urllib.parse.quote(consumer_secret, safe='') + concat
        oauth_signature = self._generate_signature(composite_key,
                                                   signature_base_str)

        # Prepare Authorization header
        oauth['oauth_signature'] = oauth_signature
        auth_header = (
            'OAuth ' +
            ', '.join(['{}="{}"'.format(k, v) for k, v in oauth.items()]))

        # Send request
        url = url + '?' + urllib.parse.urlencode(query)
        request = urllib.request.Request(url)
        request.add_header('Authorization', auth_header)
        request.add_header('X-Yahoo-App-Id', app_id)
        response = urllib.request.urlopen(request).read()
        return json.loads(response)

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        icon_path = ':/plugins/QWeather/weather.png'
        self.mainButton = QAction(QIcon(icon_path), "Weather Info",
                                  self.iface.mainWindow())
        self.mainButton.triggered.connect(self.run)

        icon_path = ':/plugins/QWeather/icons/reload.png'
        self.reloadButton = self.add_action(
            icon_path,
            text=self.tr(u'Reload QWeather layer'),
            callback=self.reloadWeather,
            parent=self.iface.mainWindow())

        self.style_temperature_btn = QAction(QIcon(''), "Temperature",
                                             self.iface.mainWindow())
        self.style_temperature_btn.setText("Temperature")
        self.style_temperature_btn.triggered.connect(self.style_temperature)

        self.style_direction_btn = QAction(QIcon(''), "Direction",
                                           self.iface.mainWindow())
        self.style_direction_btn.setText("Direction")
        self.style_direction_btn.triggered.connect(self.style_direction)

        self.style_humidity_btn = QAction(QIcon(''), "Humidity",
                                          self.iface.mainWindow())
        self.style_humidity_btn.setText("Humidity")
        self.style_humidity_btn.triggered.connect(self.style_humidity)

        menu = self.toolButton.menu()
        menu.addAction(self.mainButton)
        menu.addAction(self.style_temperature_btn)
        menu.addSeparator()
        menu.addAction(self.style_direction_btn)
        menu.addAction(self.style_humidity_btn)
        self.toolButton.setDefaultAction(self.mainButton)

        self.dlg = QWeatherDialog()
        #self.dlg.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint)
        self.key2 = 'VtZXJzZWNyZXQmc3Y9MCZ4PTZl'
        self.dlg.ok.clicked.connect(self.ok)
        self.dlg.closebutton.clicked.connect(self.close)
        self.dlg.toolButtonImport.clicked.connect(self.toolButtonImport)
        self.dlg.checkBox.clicked.connect(self.customBox)
        self.csvFile = None
        self.current = 'World Capitals'
        self.layerTemp = "QWeather"
        self.reload = False
        self.dlg.checkBox.setChecked(True)
        self.reloadButton.setEnabled(False)
        self.app_id = 'IyELbl3e'
        self.consumer_key = 'dj0yJmk' + self.key1 + '3' + self.key2
        self.consumer_secret = 'e9962f3287764230d163045f737f9ad81428cdcc'

    def style_humidity(self):
        try:
            self.QWeather.styleManager().setCurrentStyle('humidity')
        except:
            pass

    def style_temperature(self):
        try:
            self.QWeather.styleManager().setCurrentStyle('temperature')
        except:
            pass

    def style_direction(self):
        try:
            self.QWeather.styleManager().setCurrentStyle('direction')
        except:
            pass

    def reloadWeather(self):
        self.reload = True
        if self.csvFile is None:
            self.csvFile = os.path.join(self.plugin_dir, 'World Capitals.csv')
        self.dlg.imp.setText(self.csvFile)
        self.ok()

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&QWeather'), action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar

    def customBox(self):
        if self.dlg.checkBox.isChecked():
            self.dlg.comboBox.setEnabled(False)
            self.dlg.toolButtonImport.setEnabled(True)
            self.dlg.imp.setEnabled(True)
        else:
            if 'Countries.csv' in self.dlg.imp.text():
                self.csvFile = os.path.join(self.plugin_dir,
                                            'World Capitals.csv')
                self.dlg.imp.setText(self.csvFile)

            self.dlg.comboBox.setEnabled(True)
            self.dlg.toolButtonImport.setEnabled(False)
            self.dlg.imp.setEnabled(False)

    def run(self):
        self.dlg.ok.setEnabled(True)
        self.dlg.closebutton.setEnabled(True)
        self.dlg.toolButtonImport.setEnabled(True)
        if self.csvFile is None:
            self.csvFile = os.path.join(self.plugin_dir, 'World Capitals.csv')
        self.dlg.imp.setText(self.csvFile)
        self.dlg.Celsius.setChecked(True)
        self.dlg.progressBar.setValue(0)

        self.customBox()

        self.dlg.comboBox.clear()
        db_list = [
            'World Capitals', 'Afghanistan', 'Aland', 'Albania', 'Algeria',
            'American Samoa', 'Andorra', 'Angola', 'Antarctica',
            'Antigua and Barbuda', 'Argentina', 'Armenia', 'Aruba',
            'Australia', 'Austria', 'Azerbaijan', 'Bahrain', 'Bangladesh',
            'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda',
            'Bhutan', 'Bolivia', 'Bosnia and Herzegovina', 'Botswana',
            'Brazil', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burundi',
            'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Cayman Islands',
            'Central African Republic', 'Chad', 'Chile', 'China', 'Colombia',
            'Comoros', 'Congo (Brazzaville)', 'Congo (Kinshasa)',
            'Cook Islands', 'Costa Rica', 'Croatia', 'Cuba', 'Curacao',
            'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica',
            'Dominican Republic', 'East Timor', 'Ecuador', 'Egypt',
            'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia',
            'Ethiopia', 'Falkland Islands', 'Faroe Islands',
            'Federated States of Micronesia', 'Fiji', 'Finland', 'France',
            'French Polynesia', 'Gabon', 'Georgia', 'Germany', 'Ghana',
            'Gibraltar', 'Greece', 'Greenland', 'Grenada', 'Guam', 'Guatemala',
            'Guinea', 'Guinea Bissau', 'Guyana', 'Haiti', 'Honduras',
            'Hong Kong S.A.R.', 'Hungary', 'Iceland', 'India', 'Indonesia',
            'Iran', 'Iraq', 'Ireland', 'Isle of Man', 'Israel', 'Italy',
            'Ivory Coast', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya',
            'Kiribati', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia',
            'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Liechtenstein',
            'Lithuania', 'Luxembourg', 'Macau S.A.R', 'Macedonia',
            'Madagascar', 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta',
            'Marshall Islands', 'Mauritania', 'Mauritius', 'Mexico', 'Moldova',
            'Monaco', 'Mongolia', 'Montenegro', 'Morocco', 'Mozambique',
            'Myanmar', 'Namibia', 'Nepal', 'Netherlands', 'New Caledonia',
            'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'North Korea',
            'Northern Mariana Islands', 'Norway', 'Oman', 'Pakistan', 'Palau',
            'Palestine', 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru',
            'Philippines', 'Poland', 'Portugal', 'Puerto Rico', 'Qatar',
            'Romania', 'Russia', 'Rwanda', 'Saint Kitts and Nevis',
            'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa',
            'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal',
            'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovakia',
            'Slovenia', 'Solomon Islands', 'Somalia', 'Somaliland',
            'South Africa', 'South Georgia and the Islands', 'South Korea',
            'South Sudan', 'Spain', 'Sri Lanka', 'Sudan', 'Suriname',
            'Svalbard and Jan Mayen Islands', 'Swaziland', 'Sweden',
            'Switzerland', 'Syria', 'Taiwan', 'Tajikistan', 'Tanzania',
            'Thailand', 'The Bahamas', 'The Gambia', 'Togo', 'Tonga',
            'Trinidad and Tobago', 'Tunisia', 'Turkey', 'Turkmenistan',
            'Turks and Caicos Islands', 'Tuvalu', 'Uganda', 'Ukraine',
            'United Arab Emirates', 'United Kingdom',
            'United States Virgin Islands', 'USA', 'Uruguay', 'Uzbekistan',
            'Vanuatu', 'Vatican (Holy Sea)', 'Venezuela', 'Vietnam',
            'Western Sahara', 'Yemen', 'Zambia', 'Zimbabwe'
        ]

        self.dlg.comboBox.addItems(db_list)
        self.dlg.comboBox.setCurrentText(self.current)
        if self.dlg.isVisible():
            self.dlg.close()
            self.dlg.show()
        else:
            self.dlg.show()

    def close(self):
        self.dlg.close()

    def toolButtonImport(self):
        self.csvFile = QFileDialog.getOpenFileName(
            None, "Choose the file",
            os.path.join(os.path.join(os.path.expanduser('~')), 'Desktop'),
            "(*.csv)")
        if self.csvFile[0] == "":
            self.csvFile = os.path.join(self.plugin_dir, 'World Capitals.csv')
            self.dlg.imp.setText(self.csvFile)
            return

        self.csvFile = self.csvFile[0]
        self.dlg.imp.setText(self.csvFile)

    def selectOutp(self):
        msgBox = QMessageBox()
        msgBox.setIcon(QMessageBox.Warning)
        msgBox.setWindowTitle('Warning')
        msgBox.setText('Please define a csv file with locations.')
        msgBox.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint
                              | Qt.WindowCloseButtonHint)
        msgBox.exec_()
        return True

    def call_import_temps_task(self):
        self.taskWeather = QgsTask.fromFunction(u'QWeather',
                                                self.import_temps_task,
                                                on_finished=self.completed,
                                                wait_time=4)
        QgsApplication.taskManager().addTask(self.taskWeather)

    def import_temps_task(self, task, wait_time):
        for i, location in enumerate(self.all_cities):
            try:
                time.sleep(.1)
                perc = (i / len(self.all_cities)) * 100
                self.taskWeather.setProgress(perc)
                self.dlg.progressBar.setValue(perc)
                data = self.get_yahoo_weather(
                    location.replace("'", ""),
                    self.unit,
                    self.app_id,
                    self.consumer_key,
                    self.consumer_secret,
                    url='https://weather-ydn-yql.media.yahoo.com/forecastrss')

                if data['location'] == {}:
                    continue
                fields = {}
                fieldnames = [
                    'country', 'city', 'region', 'temperature',
                    'temperature_unit', 'date', 'direction', 'direction_unit',
                    'speed', 'speed_unit', 'humidity', 'humidity_unit',
                    'pressure', 'pressure_unit', 'visibility',
                    'visibility_unit', 'sunrise', 'sunset', 'icon', 'lat',
                    'lon'
                ]
                for field_init in fieldnames:
                    fields[field_init] = []
                try:
                    fields['city'] = data['location']['city']
                    fields['temperature'] = str(data['current_observation']
                                                ['condition']['temperature'])
                    if not fields['temperature'].isnumeric():
                        continue
                    fields['country'] = data['location']['country'].replace(
                        'ô', 'o').replace('´', '')
                    fields['region'] = data['location']['region'].replace(
                        '´', '')
                    fields['direction'] = str(
                        data['current_observation']['wind']['direction'])
                    fields['direction_unit'] = self.unitDirection
                    fields['speed'] = str(
                        data['current_observation']['wind']['speed'])
                    fields['speed_unit'] = self.unitSpeed
                    fields['humidity'] = str(
                        data['current_observation']['atmosphere']['humidity'])
                    fields['humidity_unit'] = self.unitHumidity
                    fields['pressure'] = str(
                        data['current_observation']['atmosphere']['pressure'])
                    fields['pressure_unit'] = self.unitPressure
                    fields['visibility'] = str(data['current_observation']
                                               ['atmosphere']['visibility'])
                    fields['visibility_unit'] = self.unitVisibility
                    fields['sunrise'] = str(
                        data['current_observation']['astronomy']['sunrise'])
                    fields['sunset'] = str(
                        data['current_observation']['astronomy']['sunset'])
                    Lon = data['location']['long']
                    Lat = data['location']['lat']
                    fields['lon'] = str(Lon)
                    fields['lat'] = str(Lat)
                    fields['date'] = time.ctime(
                        int(str(data['current_observation']['pubDate'])))
                    try:
                        fields['icon'] = data['current_observation'][
                            'condition']['text']
                    except:
                        fields['icon'] = ' '
                except:
                    pass

                fields['temperature_unit'] = self.unit
                geo_info = {
                    "type": "Feature",
                    "properties": fields,
                    "geometry": {
                        "coordinates": [Lon, Lat],
                        "type": "Point"
                    }
                }
                self.geoinfo.append(geo_info)

                if self.taskWeather.isCanceled():
                    self.stopped(self.taskWeather)
                    self.taskWeather.destroyed()
                    return None
            except:
                pass
        return True

    def stopped(self, task):
        QgsMessageLog.logMessage(
            'Task "{name}" was canceled'.format(name=task.description()),
            'QWeather', Qgis.Info)

    def completed(self, exception, result=None):
        geojson = {
            "type": "FeatureCollection",
            "name": self.layerTemp,
            "crs": {
                "type": "name",
                "properties": {
                    "name": "crs:OGC:1.3:CRS84"
                }
            },
            "features": self.geoinfo
        }

        with open(self.outQWeatherGeoJson, 'w') as geofile:
            json.dump(geojson, geofile)

        if len(QgsProject.instance().mapLayersByName(self.layerTemp)) == 0:
            self.addQWeatherLayer()
        else:
            for x in self.iface.mapCanvas().layers():
                if x.name() == self.layerTemp:
                    self.QWeather = x
                    QgsProject.instance().removeMapLayer(self.QWeather.id())
                    self.addQWeatherLayer()
        try:
            self.QWeather.selectAll()
            self.iface.mapCanvas().zoomToSelected()
            self.QWeather.removeSelection()
        except:
            pass

        ###########################################

        self.dlg.ok.setEnabled(True)
        self.dlg.closebutton.setEnabled(True)
        if not self.dlg.checkBox.isChecked():
            self.dlg.toolButtonImport.setEnabled(False)
        else:
            self.dlg.toolButtonImport.setEnabled(True)

        self.reloadButton.setEnabled(True)
        self.dlg.progressBar.setValue(100)
        self.dlg.close()

    def addQWeatherLayer(self):
        # load qml to current style
        self.QWeather = self.iface.addVectorLayer(self.outQWeatherGeoJson,
                                                  self.layerTemp, "ogr")
        style_manager = self.QWeather.styleManager()
        # read valid style from layer
        style = QgsMapLayerStyle()
        style.readFromLayer(self.QWeather)
        self.QWeather.loadNamedStyle(
            os.path.join(self.plugin_dir, "icons", self.style2 + ".qml"))
        style_manager.renameStyle("default", "direction")

        style_name = "humidity"
        # add style with new name
        style_manager.addStyle(style_name, style)
        # set new style as current
        style_manager.setCurrentStyle(style_name)
        self.QWeather.loadNamedStyle(
            os.path.join(self.plugin_dir, "icons", "humidity.qml"))
        style_manager.renameStyle(style_name, style_name)

        style = QgsMapLayerStyle()
        style.readFromLayer(self.QWeather)
        style_name = self.style
        # add style with new name
        style_manager.addStyle(style_name, style)
        # set new style as current
        style_manager.setCurrentStyle(style_name)
        self.QWeather.loadNamedStyle(
            os.path.join(self.plugin_dir, "icons", self.style + ".qml"))
        style_manager.renameStyle(self.style, "temperature")

    def ok(self):
        if not self.reload:
            if self.dlg.imp.text() == '':
                if self.selectOutp():
                    return
            elif not os.path.isabs(self.dlg.imp.text()):
                if self.selectOutp():
                    return
        else:
            self.reload = False

        self.csvFile = self.dlg.imp.text()
        status = False
        if not self.dlg.checkBox.isChecked():
            self.current = self.dlg.comboBox.currentText()
            status = self.current.upper() == 'WORLD CAPITALS'
            if status:
                self.csvFile = os.path.join(self.plugin_dir,
                                            'World Capitals.csv')

        if not self.dlg.checkBox.isChecked() and not status:
            self.csvFile = os.path.join(self.plugin_dir, 'Countries.csv')
            with open(self.csvFile, 'r') as f_all:
                self.all_cities = []
                for line in f_all:
                    mm = line.rstrip(', ').upper()
                    if self.current.upper() in mm:
                        self.all_cities.append(mm[:-1])
        else:
            try:
                with open(self.csvFile, 'r') as f:
                    self.all_cities = [line.rstrip('\n').upper() for line in f]
            except:
                msgBox = QMessageBox()
                msgBox.setIcon(QMessageBox.Warning)
                msgBox.setWindowTitle('QWeather')
                msgBox.setText('Please define a csv file path.')
                msgBox.setWindowFlags(Qt.CustomizeWindowHint
                                      | Qt.WindowStaysOnTopHint
                                      | Qt.WindowCloseButtonHint)
                msgBox.exec_()
                return

        self.outQWeatherGeoJson = os.path.join(self.plugin_dir,
                                               'QWeather.geojson')
        basename = os.path.basename(self.outQWeatherGeoJson)
        self.layerTemp = basename[:-8]

        try:
            f = open(self.outQWeatherGeoJson, "w")
            f.close()
        except:
            self.selectOutp()

        self.dlg.ok.setEnabled(False)
        self.dlg.closebutton.setEnabled(False)
        self.dlg.toolButtonImport.setEnabled(False)

        if not self.iface.actionSelectRectangle().isChecked():
            self.iface.actionSelectRectangle().trigger()
        if not self.iface.actionMapTips().isChecked():
            self.iface.actionMapTips().trigger()

        if len(self.all_cities) > 1000:
            msgBox = QMessageBox()
            msgBox.setIcon(QMessageBox.Warning)
            msgBox.setWindowTitle('Warning')
            msgBox.setText('Maximum locations must be below from 1000.')
            msgBox.setWindowFlags(Qt.CustomizeWindowHint
                                  | Qt.WindowStaysOnTopHint
                                  | Qt.WindowCloseButtonHint)
            msgBox.exec_()
            ###########################################
            self.dlg.progressBar.setValue(100)
            self.dlg.progressBar.setValue(0)
            self.dlg.ok.setEnabled(True)
            self.dlg.closebutton.setEnabled(True)
            self.dlg.toolButtonImport.setEnabled(True)
            return

        # do stuff
        if self.dlg.Celsius.isChecked():
            self.unit = 'C'
            self.unitDirection = "degrees"
            self.unitSpeed = "km/h"
            self.unitHumidity = "%"
            self.unitVisibility = "km"
            self.unitPressure = "hPa"
            self.style = 'weather_c'
            self.style2 = 'direction_c'

        else:
            self.unit = 'F'
            self.unitDirection = "degrees"
            self.unitSpeed = "mph"
            self.unitHumidity = "%"
            self.unitVisibility = "mi"
            self.unitPressure = "psi"
            self.style = 'weather_f'
            self.style2 = 'direction_f'

        self.geoinfo = []
        self.call_import_temps_task()
Exemplo n.º 5
0
class UnderMap:
    """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 = dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = join(
            self.plugin_dir,
            'i18n',
            'UnderMap_{}.qm'.format(locale))

        if 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 = UnderMapDialog()
        self.addop = AjouterOperateurDialog()
        self.addpdf = DialogAddPDF()
        self.splitpdf = DialogSplitPDF()
        self.importpoints = DialogImportPoint()
        self.zoomto = DialogZoomToFeature()

        # Initialise buttton
        self.init_button = QToolButton()
        self.init_button.setMenu(QMenu())
        self.init_button.setPopupMode(QToolButton.MenuButtonPopup)

        # toolBar
        self.toolbar = self.iface.addToolBar('UnderMap')
        self.toolbar.setObjectName('UnderMap')

        # actions
        self.initialisePDFAction = None
        self.reportAction = None
        self.addOperatorAction = None
        self.initialiseFDPAction = None
        self.initialiseEmpriseAction = None
        self.addPDFAction = None
        self.splitPDFAction = None
        self.importPointsAction = None
        self.mergeFeaturesAction = None
        self.manageBufferAction = None
        self.saveAsGeoJsonAndTfwAction = None
        self.controlAction = None
        self.zoomToAction = None

        QgsSettings().setValue("qgis/digitizing/reuseLastValues", True)
        # For enable/disable the addpdf editor icon
        self.iface.currentLayerChanged.connect(self.layer_changed)

        # For load layer on qgis
        self.iface.projectRead.connect(self.load_layer)

    @staticmethod
    def tr(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('UnderMap', message)

    # noinspection PyPep8Naming
    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        # the actions
        self.initialisePDFAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'initialpdf.png')),
            'Initialiser PDF',
            self.iface.mainWindow())

        self.addOperatorAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'ajouterOperateur.png')),
            'Ajouter un exploitant',
            self.iface.mainWindow())

        self.reportAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'report.png')),
            'Générer le rapport',
            self.iface.mainWindow())

        self.initialiseFDPAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'fdp.png')),
            'Initialiser un FDP',
            self.iface.mainWindow())

        self.initialiseEmpriseAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'icon.png')),
            'Initialiser une emprise',
            self.iface.mainWindow())

        self.addPDFAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'add_pdf.png')),
            'Ajouter pdf',
            self.iface.mainWindow())

        self.splitPDFAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'add_pdf.png')),
            'Découper un PDF',
            self.iface.mainWindow())

        self.importPointsAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'point.png')),
            'Importer les points de calage',
            self.iface.mainWindow())

        self.mergeFeaturesAction = QAction(
            QIcon(join(dirname(__file__), 'resources', '')),
            'Fusionner les entités',
            self.iface.mainWindow())

        self.manageBufferAction = QAction(
            QIcon(join(dirname(__file__), 'resources', '')),
            'Génerer les buffers',
            self.iface.mainWindow())

        self.saveAsGeoJsonAndTfwAction = QAction(
            QIcon(join(dirname(__file__), 'resources', '')),
            'Exporter les GeoJSON et les tfw',
            self.iface.mainWindow())

        self.controlAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'opacity.png')),
            'Contrôler',
            self.iface.mainWindow())

        self.zoomToAction = QAction(
            QIcon(join(dirname(__file__), 'resources', 'zoom-in.png')),
            'Zoom',
            self.iface.mainWindow())

        # actions dialogs
        self.initialisePDFAction.triggered.connect(self.initialise_PDF)
        self.addOperatorAction.triggered.connect(self.add_operator)
        self.initialiseFDPAction.triggered.connect(self.initialise_FDP)
        self.initialiseEmpriseAction.triggered.connect(self.initialise_emprise)
        self.reportAction.triggered.connect(self.export_report)
        self.addPDFAction.triggered.connect(self.add_pdf)
        self.splitPDFAction.triggered.connect(self.split_pdf)
        self.importPointsAction.triggered.connect(self.import_points)
        self.mergeFeaturesAction.triggered.connect(self.merge_features_layer)
        self.manageBufferAction.triggered.connect(self.manage_buffer)
        self.saveAsGeoJsonAndTfwAction.triggered.connect(self.save_geojson_tfw)
        self.controlAction.triggered.connect(self.control)
        self.zoomToAction.triggered.connect(self.zoom_to_feature)

        # add actions on menu
        self.init_button.menu().addAction(self.initialisePDFAction)
        self.init_button.menu().addAction(self.addOperatorAction)
        self.init_button.setDefaultAction(self.initialisePDFAction)
        # add separator

        # self.initialiseFDPAction.insertSeparator(self.initialisePDFAction)
        self.init_button.menu().addAction(self.initialiseFDPAction)
        self.init_button.menu().addAction(self.initialiseEmpriseAction)
        self.init_button.menu().addAction(self.splitPDFAction)
        self.init_button.menu().addAction(self.mergeFeaturesAction)
        self.init_button.menu().addAction(self.manageBufferAction)
        self.init_button.menu().addAction(self.saveAsGeoJsonAndTfwAction)

        # add actions and menu in toolbar
        self.toolbar.addWidget(self.init_button)
        self.toolbar.addAction(self.reportAction)
        self.toolbar.addAction(self.addPDFAction)
        self.toolbar.addAction(self.importPointsAction)
        self.toolbar.addAction(self.controlAction)
        self.toolbar.addAction(self.zoomToAction)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        self.iface.mainWindow().removeToolBar(self.toolbar)
        self.iface.currentLayerChanged.disconnect(self.layer_changed)

    def layer_changed(self, layer):

        try:
            layers = get_layers_in_group("RSX")
        except AttributeError:
            return
        if not hasattr(layer, 'name'):
            enable_addpdf = False

        elif layer.name() not in layers:
            enable_addpdf = False

        elif not hasattr(layer, 'providerType'):
            enable_addpdf = False
        elif layer.providerType() == 'wms':
            enable_addpdf = False
        elif not layer.geometryType() == 1:
            enable_addpdf = False
        else:
            enable_addpdf = True
        self.addPDFAction.setEnabled(enable_addpdf)

    def run(self):
        """Run method that performs all the real work"""
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            # Do something useful here - delete the line containing pass and
            # substitute with your code.
            pass

    def add_operator(self):
        self.addop.exec_()

    def add_pdf(self):
        self.addpdf.exec_()

    def split_pdf(self):
        self.splitpdf.exec_()

    def import_points(self):
        self.importpoints.exec_()

    def zoom_to_feature(self):
        self.zoomto.exec_()

    def manage_buffer(self):
        project_path = get_project_path()
        manage_buffer(project_path)
        self.iface.messageBar().pushInfo('Undermap', "La génération des buffers a bien reussi."
                                                            )

    def control(self):

        transparency_raster()

    def initialise_PDF(self):
        project_path = get_project_path()
        if project_path == './':
            QMessageBox.warning(None,"Avertisment","Veulliez ouvrir un projet qgis")
            return
        else:
            dir_selected = QFileDialog.getExistingDirectory(None, "Sélectionner un dossier", project_path,  QFileDialog.ShowDirsOnly)
            if dir_selected == '':
                self.iface.messageBar().pushWarning('Undermap', "Aucun dossier séléctionné")
                return
            else:
                initialise_pdf(dir_selected)
                QgsProject.instance().write()

    def initialise_FDP(self):
        project_path = get_project_path()
        if project_path == './':
            QMessageBox.warning(None, "Avertisment", "Veulliez ouvrir un projet qgis")
            return
        else:
            fileSelected = QFileDialog.getOpenFileName(None, "Sélectionnez un fichier", project_path, "*.dxf")
            if fileSelected == ('', ''):
                self.iface.messageBar().pushWarning('Undermap', "Aucun fichier dxf séléctionné")
                return
            else:
                initialise_fdp(fileSelected)

    def initialise_emprise(self):
        project_path = get_project_path()
        if project_path == './':
            QMessageBox.warning(None, "Avertissement", "Veuillez ouvrir un projet QGIS et l’enregistrer")
            return
        else:
            filter = "DXF(*.dxf);;KML(*.kml);;SHAPE(*.shp)"
            fileSelected = QFileDialog.getOpenFileName(None, "Sélectionnez un fichier", project_path, filter)
            if fileSelected == ('', ''):
                self.iface.messageBar().pushWarning('Undermap', "Aucun fichier séléctionné")
                return
            else:
                initialise_emprise(fileSelected)

    def export_report(self):
        project_path = get_project_path()
        if project_path == './':
            QMessageBox.warning(None, "Avertisment", "Veuillez ouvrir un projet qgis")
            return
        else:
            if export_xlsx_report(project_path):
                self.iface.messageBar().pushInfo('Undermap', "La génération du rapport a bien reussi."
                                                            )
                os.startfile(join(project_path, QgsProject.instance().baseName()+'.xlsx'))
            else:
                QMessageBox.warning(None, 'Undermap', "QGIS ne peut pas écrire "
                                                         "le rapport car le fichier"
                                                             " {} est ouvert "
                                                         "dans une autre application"
                                                        .format(join(project_path, QgsProject.instance()
                                                        .baseName()+'.xlsx')))

    def save_geojson_tfw(self):
        project_path = get_project_path()
        if project_path == './':
            QMessageBox.warning(None, "Avertisment", "Veuillez ouvrir un projet qgis")
            return
        else:
            if export_as_geojson(project_path):
                 if export_tfw(project_path):
                    self.iface.messageBar().pushInfo('Undermap', "l'export de GeoJSON et les fichiers"
                                                                 " tfw est bien reussi"
                                                     )
            delete_unused_folder(project_path)

    def merge_features_layer(self):

        from matplotlib import pyplot as plt
        project_path = get_project_path()
        if project_path == './':
            QMessageBox.warning(None, "Avertisment", "Veuillez ouvrir un projet qgis")
            return
        else:
            merge_features_connected_layers(project_path)
            plt.pause(5)
            overwrite_layers_merged(project_path)
            delete_unused_folder(project_path)

    def load_layer(self):
        project_path = get_project_path()
        load_unloaded_data(project_path)
Exemplo n.º 6
0
class WaysCalc:
    """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',
            'WaysCalc_{}.qm'.format(locale))

        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'&WaysCalc')
        # TODO: We are going to let the user set this up in a future iteration
        # self.toolbar = self.iface.addToolBar(u'WaysCalc')
        # self.toolbar.setObjectName(u'WaysCalc')

        #print "** INITIALIZING WaysCalc"

        self.pluginIsActive = False
        self.dockwidget_inters_ways = None
        self.dockwidget_inters_allways = None
        # self.settings = None

        self.IW = None #IntersectionWays
        self.IAW = None #IntersectionAllWays


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


    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        # выпадающая кнопка для пересекающихся маршрутов
        self.toolButton = QToolButton()
        self.toolButton.setMenu(QMenu())
        # setPopupMode: DelayedPopup, MenuButtonPopup, InstantPopup
        self.toolButton.setPopupMode(QToolButton.InstantPopup)
        self.toolButton.setAutoRaise(True)
        self.toolButton_action = self.iface.addToolBarWidget(self.toolButton)

        self.action_intersection = QAction(
                QIcon(":/plugins/_Ways_calc/icon.png"),
                u'Поиск пересечений для линейного объекта',
                self.iface.mainWindow())
        self.action_initLayerWays = QAction(
                u"Выбор слоя для поиска пересечений",
                self.iface.mainWindow())
        self.action_allintersection = QAction(
                QIcon(":/plugins/_Ways_calc/icon.png"),
                u'Поиск пересечений всех линейных объектов',
                self.iface.mainWindow())

        self.iface.addPluginToMenu(u"WaysCalc", self.action_intersection)
        self.iface.addPluginToMenu(u"WaysCalc", self.action_initLayerWays)
        self.iface.addPluginToMenu(u"WaysCalc", self.action_allintersection)
        # self.iface.addToolBarIcon(self.action_intersection)
        m = self.toolButton.menu()
        m.addAction(self.action_intersection)
        m.addAction(self.action_initLayerWays)
        m.addSeparator()
        m.addAction(self.action_allintersection)
        self.toolButton.setDefaultAction(self.action_intersection)

        self.action_intersection.triggered.connect(self.run_intersection) # пересекающиеся маршруты
        self.action_allintersection.triggered.connect(self.run_allintersection) # пересекающиеся все маршруты
        self.action_initLayerWays.triggered.connect(self.run_initLayerWays) # выбор слоя сравнения

        self.pointEmitterIntersection = QgsMapToolEmitPoint(self.iface.mapCanvas())
        self.pointEmitterIntersection.setAction(self.action_intersection)
        self.pointEmitterIntersection.canvasClicked.connect(self.pointEmitterIntersectioncanvasClicked)
        self.iface.mapCanvas().currentLayerChanged.connect(self.onCurrentLayerChanged)

    #--------------------------------------------------------------------------

    def onClosePlugin(self):
        """Cleanup necessary items here when plugin dockwidget is closed"""
        # disconnects
        try:
            self.dockwidget_inters_ways.closingPlugin.disconnect(self.onClosePlugin)
        except:
            pass
        try:
            self.dockwidget_inters_allways.closingPlugin.disconnect(self.onClosePlugin)
        except:
            pass
        self.pluginIsActive = False


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        self.iface.removePluginMenu(u"WaysCalc", self.action_intersection)
        self.iface.removePluginMenu(u"WaysCalc", self.action_allintersection)
        self.iface.removePluginMenu(u"WaysCalc", self.action_initLayerWays)
        self.iface.removeToolBarIcon(self.action_intersection)
        self.iface.removeToolBarIcon(self.action_intersection)
        self.iface.removeToolBarIcon(self.toolButton_action)

        self.action_intersection.triggered.disconnect(self.run_intersection) # пересекающиеся маршруты
        self.action_allintersection.triggered.disconnect(self.run_allintersection) # пересекающиеся все маршруты
        self.action_initLayerWays.triggered.disconnect(self.run_initLayerWays) # выбор слоя сравнения
        self.pointEmitterIntersection.canvasClicked.connect(self.pointEmitterIntersectioncanvasClicked)
        self.iface.mapCanvas().currentLayerChanged.disconnect(self.onCurrentLayerChanged)

        if self.IW is not None:
            self.IW.onUnLoadModule()


    def init_dock_inters_ways(self, dock):
        """Run method that loads and starts the plugin"""

        # if not self.pluginIsActive:
        self.pluginIsActive = True
        if self.dockwidget_inters_ways == None:
            self.dockwidget_inters_ways = WaysCalcDockWidget()
            self.dockwidget_inters_ways.closingPlugin.connect(self.onClosePlugin)

            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget_inters_ways)
            self.dockwidget_inters_ways.hide()
            self.dockwidget_inters_ways.setWindowTitle(u'WaysCalc: Поиск пересечений для линейного объекта')


    def init_dock_inters_allways(self, dock):
        """Run method that loads and starts the plugin"""

        # if not self.pluginIsActive:
        self.pluginIsActive = True
        if self.dockwidget_inters_allways == None:
            self.dockwidget_inters_allways = WaysCalcDockWidget()
            self.dockwidget_inters_allways.closingPlugin.connect(self.onClosePlugin)

            self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget_inters_allways)
            self.dockwidget_inters_allways.hide()
            self.dockwidget_inters_allways.setWindowTitle(u'WaysCalc: Поиск пересечений всех линейных объектов')



    def onCurrentLayerChanged(self):
        self.iface.mapCanvas().unsetMapTool(self.pointEmitterIntersection)


    #--------------------------------------------------------------------------

    # def loadSettings(self):
    #     with open(os.path.join(self.plugin_dir, "settings.json"), "r") as read_file:
    #         self.settings = json.load(read_file)


    #--------INTERSECTION WAYS-------------------------------------------------
    def run_initLayerWays(self):
        if self.IW is None:
            self.init_IW()
        self.IW.initLayerWays()     

    def run_intersection(self):
        self.toolButton.setDefaultAction(self.action_intersection)
        self.init_dock_inters_ways(self.dockwidget_inters_ways)
        if self.IW is None:
            self.init_IW()
        if self.IW.checkLayers():    
            self.iface.mapCanvas().setMapTool(self.pointEmitterIntersection)


    def pointEmitterIntersectioncanvasClicked(self, point, button):
        self.IW.insersection_take_way(point)


    def init_IW(self):
        self.IW = IntersectionWays(self.iface, self.dockwidget_inters_ways)

    #-------- END INTERSECTION WAYS---------------------------------------------


    def init_IAW(self):
        self.IAW = IntersectionAllWays(self.iface, self.dockwidget_inters_allways)

    def run_allintersection(self):
        self.init_dock_inters_allways(self.dockwidget_inters_allways)
        if self.IAW is None:
            self.init_IAW()
        self.IAW.showClickedFeaturesList()
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 = os.path.dirname(__file__)

        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.runIcon = QIcon(
            os.path.join(self.plugin_dir, 'icon_add_service.svg'))

        self.run_action = QAction(self.runIcon, "PDOK Services plugin",
                                  self.iface.mainWindow())

        self.run_button = QToolButton()
        self.run_button.setMenu(QMenu())
        self.run_button.setPopupMode(QToolButton.MenuButtonPopup)
        self.run_button.setDefaultAction(self.run_action)

        self.servicesLoaded = False
        # connect the action to the run method
        self.run_action.triggered.connect(self.run)
        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.toolbar.addWidget(self.run_button)

        #self.run_button.menu().addSection('Favorieten')

        self.favourite_1_action = QAction('Favoriet 1',
                                          self.iface.mainWindow())
        self.favourite_1_action.setIcon(self.runIcon)
        self.favourite_1_action.triggered.connect(
            lambda: self.load_favourite(1))
        self.set_favourite_action(self.favourite_1_action, 1)
        self.run_button.menu().addAction(self.favourite_1_action)

        self.favourite_2_action = QAction('Favoriet 2',
                                          self.iface.mainWindow())
        self.favourite_2_action.setIcon(self.runIcon)
        self.favourite_2_action.triggered.connect(
            lambda: self.load_favourite(2))
        self.set_favourite_action(self.favourite_2_action, 2)
        self.run_button.menu().addAction(self.favourite_2_action)

        # TODO :-)
        #self.run_button.menu().addSection('Meest Recent')
        #self.run_button.menu().addSeparator()

        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.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()

    # 2021-02 hiding the check JSON: to much hassle
    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(os.path.join(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 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 += f' [{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 set_favourite_action(self, action, favourite_number):
        if QSettings().contains(
                f'/pdokservicesplugin/favourite_{favourite_number}'):
            layer = QSettings().value(
                f'/pdokservicesplugin/favourite_{favourite_number}', None)
            if layer:
                action.setToolTip(layer['title'].capitalize())
                title = layer['title'].capitalize()
                if 'style' in layer:
                    style = layer['style']
                    title += f' [{style}]'
                if 'type' in layer:
                    stype = layer['type'].upper()
                    title += f' ({stype})'
                action.setText(title)
                action.setIcon(self.runIcon)

    def load_favourite(self, favourite_number):
        if QSettings().contains(
                f'/pdokservicesplugin/favourite_{favourite_number}'):
            layer = QSettings().value(
                f'/pdokservicesplugin/favourite_{favourite_number}', None)
            if layer and layer in self.pdok['services']:
                self.currentLayer = layer
                self.loadService()
                return
        QMessageBox.warning(self.iface.mainWindow(), "Geen Favoriet aanwezig (of verouderd)...", ( \
            "Maak een Favoriet aan door in de dialoog met services en lagen\n via het context menu (rechter muisknop) een Favoriet te kiezen..."
            ), QMessageBox.Ok, QMessageBox.Ok)
        self.run()

    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
        # RD: 20200820: lijkt of het quoten van de query problemen geeft bij WFS, is/was dit nodig???
        #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 += f' [{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 + "&identifier=" + layers + "&url=" + url
            #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(self.plugin_dir, "pdok.json")
            with open(pdokjson, 'r', encoding='utf-8') as f:
                self.pdok = json.load(f)
                print(f'self.pdok type = {type(self.pdok)}')

            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):
                    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)

            self.dlg.servicesView.setContextMenuPolicy(Qt.CustomContextMenu)
            self.dlg.servicesView.customContextMenuRequested.connect(
                self.make_favourite)

            # 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 make_favourite(self, position):
        menu = QMenu()
        create_fav1_action = menu.addAction("Maak Deze Laag Favoriet 1")
        create_fav2_action = menu.addAction("Maak Deze Laag Favoriet 2")
        action = menu.exec_(self.dlg.servicesView.mapToGlobal(position))
        if action == create_fav1_action:
            QSettings().setValue("/pdokservicesplugin/favourite_1",
                                 self.currentLayer)
            self.set_favourite_action(self.favourite_1_action, 1)
        elif action == create_fav2_action:
            QSettings().setValue("/pdokservicesplugin/favourite_2",
                                 self.currentLayer)
            self.set_favourite_action(self.favourite_2_action, 2)

    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 and self.pointer.scene() is not None:
            self.iface.mapCanvas().scene().removeItem(self.pointer)
            self.pointer = None
            self.clean_action.setEnabled(False)

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin',
                                 Qgis.Info)
Exemplo n.º 8
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_()