class QgepPlugin(object): """ A plugin for wastewater management http://www.github.com/qgep/QGEP """ # The networkAnalyzer will manage the networklayers and pathfinding network_analyzer = None # Remember not to reopen the dock if there's already one opened profile_dock = None # Wizard wizarddock = None # The layer ids the plugin will need edgeLayer = None nodeLayer = None specialStructureLayer = None networkElementLayer = None profile = None def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() self.nodes = None self.edges = None self.initLogger() setup_i18n() def tr(self, source_text): """ This does not inherit from QObject but for the translation to work (in particular to have translatable strings picked up) we need a tr method. :rtype : unicode :param source_text: The text to translate :return: The translated text """ return QApplication.translate('QgepPlugin', source_text) def initLogger(self): """ Initializes the logger """ self.logger = logging.getLogger(__package__) settings = QSettings() loglevel = settings.value("/QGEP/LogLevel", 'Warning') logfile = settings.value("/QGEP/LogFile", None) if hasattr(self.logger, 'qgepFileHandler'): self.logger.removeHandler(self.logger.qgepFileHandler) del self.logger.qgepFileHandler current_handlers = [h.__class__.__name__ for h in self.logger.handlers] if self.__class__.__name__ not in current_handlers: self.logger.addHandler(QgepQgsLogHandler()) if logfile: log_handler = logging.FileHandler(logfile) fmt = logging.Formatter(LOGFORMAT) log_handler.setFormatter(fmt) self.logger.addHandler(log_handler) self.logger.fileHandler = log_handler if 'Debug' == loglevel: self.logger.setLevel(logging.DEBUG) elif 'Info' == loglevel: self.logger.setLevel(logging.INFO) elif 'Warning' == loglevel: self.logger.setLevel(logging.WARNING) elif 'Error' == loglevel: self.logger.setLevel(logging.ERROR) fp = os.path.join(os.path.abspath(os.path.dirname(__file__)), "metadata.txt") ini_text = QSettings(fp, QSettings.IniFormat) verno = ini_text.value("version") self.logger.info('QGEP plugin version ' + verno + ' started') def initGui(self): """ Called to setup the plugin GUI """ self.network_layer_notifier = QgepLayerNotifier( self.iface.mainWindow(), ['vw_network_node', 'vw_network_segment']) self.wastewater_networkelement_layer_notifier = QgepLayerNotifier( self.iface.mainWindow(), ['vw_wastewater_node', 'vw_qgep_reach']) self.toolbarButtons = [] # Create toolbar button self.profileAction = QAction( QIcon( os.path.join(plugin_root_path(), "icons/wastewater-profile.svg")), self.tr("Profile"), self.iface.mainWindow()) self.profileAction.setWhatsThis(self.tr("Reach trace")) self.profileAction.setEnabled(False) self.profileAction.setCheckable(True) self.profileAction.triggered.connect(self.profileToolClicked) self.downstreamAction = QAction( QIcon( os.path.join(plugin_root_path(), "icons/wastewater-downstream.svg")), self.tr("Downstream"), self.iface.mainWindow()) self.downstreamAction.setWhatsThis(self.tr("Downstream reaches")) self.downstreamAction.setEnabled(False) self.downstreamAction.setCheckable(True) self.downstreamAction.triggered.connect(self.downstreamToolClicked) self.upstreamAction = QAction( QIcon( os.path.join(plugin_root_path(), "icons/wastewater-upstream.svg")), self.tr("Upstream"), self.iface.mainWindow()) self.upstreamAction.setWhatsThis(self.tr("Upstream reaches")) self.upstreamAction.setEnabled(False) self.upstreamAction.setCheckable(True) self.upstreamAction.triggered.connect(self.upstreamToolClicked) self.wizardAction = QAction( QIcon(os.path.join(plugin_root_path(), "icons/wizard.svg")), "Wizard", self.iface.mainWindow()) self.wizardAction.setWhatsThis( self.tr("Create new manholes and reaches")) self.wizardAction.setEnabled(False) self.wizardAction.setCheckable(True) self.wizardAction.triggered.connect(self.wizard) self.connectNetworkElementsAction = QAction( QIcon( os.path.join(plugin_root_path(), "icons/link-wastewater-networkelement.svg")), QApplication.translate('qgepplugin', 'Connect wastewater networkelements'), self.iface.mainWindow()) self.connectNetworkElementsAction.setEnabled(False) self.connectNetworkElementsAction.setCheckable(True) self.connectNetworkElementsAction.triggered.connect( self.connectNetworkElements) self.refreshNetworkTopologyAction = QAction( QIcon(os.path.join(plugin_root_path(), "icons/refresh-network.svg")), "Refresh network topology", self.iface.mainWindow()) self.refreshNetworkTopologyAction.setWhatsThis( self.tr("Refresh network topology")) self.refreshNetworkTopologyAction.setEnabled(False) self.refreshNetworkTopologyAction.setCheckable(False) self.refreshNetworkTopologyAction.triggered.connect( self.refreshNetworkTopologyActionClicked) self.aboutAction = QAction(self.tr('About'), self.iface.mainWindow()) self.aboutAction.triggered.connect(self.about) self.settingsAction = QAction(self.tr('Settings'), self.iface.mainWindow()) self.settingsAction.triggered.connect(self.showSettings) # Add toolbar button and menu item self.toolbar = QToolBar(QApplication.translate('qgepplugin', 'QGEP')) self.toolbar.addAction(self.profileAction) self.toolbar.addAction(self.upstreamAction) self.toolbar.addAction(self.downstreamAction) self.toolbar.addAction(self.wizardAction) self.toolbar.addAction(self.refreshNetworkTopologyAction) self.toolbar.addAction(self.connectNetworkElementsAction) self.iface.addPluginToMenu("&QGEP", self.profileAction) self.iface.addPluginToMenu("&QGEP", self.settingsAction) self.iface.addPluginToMenu("&QGEP", self.aboutAction) self.iface.addToolBar(self.toolbar) # Local array of buttons to enable / disable based on context self.toolbarButtons.append(self.profileAction) self.toolbarButtons.append(self.upstreamAction) self.toolbarButtons.append(self.downstreamAction) self.toolbarButtons.append(self.wizardAction) self.toolbarButtons.append(self.refreshNetworkTopologyAction) self.network_layer_notifier.layersAvailable.connect( self.onLayersAvailable) self.network_layer_notifier.layersUnavailable.connect( self.onLayersUnavailable) # Init the object maintaining the network self.network_analyzer = QgepGraphManager() self.network_analyzer.message_emitted.connect( self.iface.messageBar().pushMessage) # Create the map tool for profile selection self.profile_tool = QgepProfileMapTool(self.iface, self.profileAction, self.network_analyzer) self.profile_tool.profileChanged.connect(self.onProfileChanged) self.upstream_tree_tool = QgepTreeMapTool(self.iface, self.upstreamAction, self.network_analyzer) self.upstream_tree_tool.setDirection("upstream") self.upstream_tree_tool.treeChanged.connect(self.onTreeChanged) self.downstream_tree_tool = QgepTreeMapTool(self.iface, self.downstreamAction, self.network_analyzer) self.downstream_tree_tool.setDirection("downstream") self.downstream_tree_tool.treeChanged.connect(self.onTreeChanged) self.maptool_connect_networkelements = QgepMapToolConnectNetworkElements( self.iface, self.connectNetworkElementsAction) self.wastewater_networkelement_layer_notifier.layersAvailableChanged.connect( self.connectNetworkElementsAction.setEnabled) self.processing_provider = QgepProcessingProvider() QgsApplication.processingRegistry().addProvider( self.processing_provider) self.network_layer_notifier.layersAdded([]) def unload(self): """ Called when unloading """ self.toolbar.removeAction(self.profileAction) self.toolbar.removeAction(self.upstreamAction) self.toolbar.removeAction(self.downstreamAction) self.toolbar.removeAction(self.wizardAction) self.toolbar.removeAction(self.refreshNetworkTopologyAction) self.toolbar.removeAction(self.connectNetworkElementsAction) self.toolbar.deleteLater() self.iface.removePluginMenu("&QGEP", self.profileAction) self.iface.removePluginMenu("&QGEP", self.aboutAction) QgsApplication.processingRegistry().removeProvider( self.processing_provider) def onLayersAvailable(self, layers): for b in self.toolbarButtons: b.setEnabled(True) self.network_analyzer.setReachLayer(layers['vw_network_segment']) self.network_analyzer.setNodeLayer(layers['vw_network_node']) def onLayersUnavailable(self): for b in self.toolbarButtons: b.setEnabled(False) def profileToolClicked(self): """ Is executed when the profile button is clicked """ self.openDock() # Set the profile map tool self.profile_tool.setActive() def upstreamToolClicked(self): """ Is executed when the user clicks the upstream search tool """ self.openDock() self.upstream_tree_tool.setActive() def downstreamToolClicked(self): """ Is executed when the user clicks the downstream search tool """ self.openDock() self.downstream_tree_tool.setActive() def refreshNetworkTopologyActionClicked(self): """ Is executed when the user clicks the refreshNetworkTopologyAction tool """ self.network_analyzer.refresh() def wizard(self): """ """ if not self.wizarddock: self.wizarddock = QgepWizard(self.iface.mainWindow(), self.iface) self.logger.debug('Opening Wizard') self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.wizarddock) self.wizarddock.show() def connectNetworkElements(self, checked): self.iface.mapCanvas().setMapTool(self.maptool_connect_networkelements) def openDock(self): """ Opens the dock """ if self.profile_dock is None: self.logger.debug('Open dock') self.profile_dock = QgepProfileDockWidget(self.iface.mainWindow(), self.iface.mapCanvas(), self.iface.addDockWidget) self.profile_dock.closed.connect(self.onDockClosed) self.profile_dock.showIt() self.plotWidget = QgepPlotSVGWidget(self.profile_dock, self.network_analyzer) self.plotWidget.specialStructureMouseOver.connect( self.highlightProfileElement) self.plotWidget.specialStructureMouseOut.connect( self.unhighlightProfileElement) self.plotWidget.reachMouseOver.connect( self.highlightProfileElement) self.plotWidget.reachMouseOut.connect( self.unhighlightProfileElement) self.profile_dock.addPlotWidget(self.plotWidget) self.profile_dock.setTree(self.nodes, self.edges) def onDockClosed(self): # used when Dock dialog is closed """ Gets called when the dock is closed All the cleanup of the dock has to be done here """ self.profile_dock = None def onProfileChanged(self, profile): """ The profile changed: update the plot @param profile: The profile to plot """ self.profile = profile.copy() if self.plotWidget: self.plotWidget.setProfile(profile) def onTreeChanged(self, nodes, edges): if self.profile_dock: self.profile_dock.setTree(nodes, edges) self.nodes = nodes self.edges = edges def highlightProfileElement(self, obj_id): if self.profile is not None: self.profile.highlight(str(obj_id)) def unhighlightProfileElement(self): if self.profile is not None: self.profile.highlight(None) def about(self): from .gui.dlgabout import DlgAbout DlgAbout(self.iface.mainWindow()).exec_() def showSettings(self): settings_dlg = QgepSettingsDialog(self.iface.mainWindow()) settings_dlg.exec_()
class CartographyToolsPlugin: """QGIS Plugin Implementation.""" def __init__(self, iface: QgisInterface): """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 """ super().__init__() # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QgsApplication.locale() locale_path = os.path.join(self.plugin_dir, 'i18n', '{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # processing framework self.provider = CartographyToolsProvider() self.toolbar = None self.actions = [] self.tools = {} self.active_tool = None self.layout_hooks = LayoutDesignerHooks() @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('CartographyTools', message) def initProcessing(self): """Create the Processing provider""" QgsApplication.processingRegistry().addProvider(self.provider) def initGui(self): """Creates application GUI widgets""" self.initProcessing() self.toolbar = QToolBar(self.tr('Cartography Tools')) self.toolbar.setObjectName('cartographyTools') self.iface.addToolBar(self.toolbar) self.create_tools() self.iface.currentLayerChanged.connect(self.current_layer_changed) self.iface.actionToggleEditing().toggled.connect(self.editing_toggled) self.layout_hooks.init_gui(self.iface) def get_map_tool_action_group(self): try: return self.iface.mapToolActionGroup() except AttributeError: return \ [o for o in self.iface.mainWindow().findChildren(QActionGroup) if self.iface.actionPan() in o.actions()][0] def create_tools(self): """ Creates all map tools ands add them to the QGIS interface """ action_single_point_templated_marker = QAction( GuiUtils.get_icon('single_point_templated_marker.svg'), self.tr('Single Point Templated Marker')) action_single_point_templated_marker.setCheckable(True) self.tools[SinglePointTemplatedMarkerTool. ID] = SinglePointTemplatedMarkerTool( self.iface.mapCanvas(), self.iface.cadDockWidget(), self.iface, action_single_point_templated_marker) self.tools[SinglePointTemplatedMarkerTool.ID].setAction( action_single_point_templated_marker) action_single_point_templated_marker.triggered.connect( partial(self.switch_tool, SinglePointTemplatedMarkerTool.ID)) action_single_point_templated_marker.setData( SinglePointTemplatedMarkerTool.ID) self.toolbar.addAction(action_single_point_templated_marker) self.actions.append(action_single_point_templated_marker) self.get_map_tool_action_group().addAction( action_single_point_templated_marker) # single point at center of line tool action_single_point_at_center_of_line = QAction( GuiUtils.get_icon('marker_at_center_of_line.svg'), self.tr('Single Point Templated Marker Via Two Points')) action_single_point_at_center_of_line.setCheckable(True) self.tools[ TwoPointTemplatedMarkerTool.ID] = TwoPointTemplatedMarkerTool( self.iface.mapCanvas(), self.iface.cadDockWidget(), self.iface, action_single_point_at_center_of_line) self.tools[TwoPointTemplatedMarkerTool.ID].setAction( action_single_point_at_center_of_line) action_single_point_at_center_of_line.triggered.connect( partial(self.switch_tool, TwoPointTemplatedMarkerTool.ID)) action_single_point_at_center_of_line.setData( TwoPointTemplatedMarkerTool.ID) self.toolbar.addAction(action_single_point_at_center_of_line) self.actions.append(action_single_point_at_center_of_line) self.get_map_tool_action_group().addAction( action_single_point_at_center_of_line) # multi point tool action_multi_point_templated_marker = QAction( GuiUtils.get_icon('multi_point_templated_marker.svg'), self.tr('Multiple Point Templated Marker Along LineString')) action_multi_point_templated_marker.setCheckable(True) self.tools[ MultiPointTemplatedMarkerTool.ID] = MultiPointTemplatedMarkerTool( self.iface.mapCanvas(), self.iface.cadDockWidget(), self.iface, action_multi_point_templated_marker) self.tools[MultiPointTemplatedMarkerTool.ID].setAction( action_multi_point_templated_marker) action_multi_point_templated_marker.triggered.connect( partial(self.switch_tool, MultiPointTemplatedMarkerTool.ID)) action_multi_point_templated_marker.setData( MultiPointTemplatedMarkerTool.ID) self.toolbar.addAction(action_multi_point_templated_marker) self.actions.append(action_multi_point_templated_marker) self.get_map_tool_action_group().addAction( action_single_point_templated_marker) # multi at center of segment point tool action_multi_point_center_segment_templated_marker = QAction( GuiUtils.get_icon('multi_point_templated_marker_at_center.svg'), self.tr('Multiple Point Templated Marker At Center Of Segments')) action_multi_point_center_segment_templated_marker.setCheckable(True) self.tools[MultiPointSegmentCenterTemplatedMarkerTool. ID] = MultiPointSegmentCenterTemplatedMarkerTool( self.iface.mapCanvas(), self.iface.cadDockWidget(), self.iface, action_multi_point_center_segment_templated_marker) self.tools[MultiPointSegmentCenterTemplatedMarkerTool.ID].setAction( action_multi_point_center_segment_templated_marker) action_multi_point_center_segment_templated_marker.triggered.connect( partial(self.switch_tool, MultiPointSegmentCenterTemplatedMarkerTool.ID)) action_multi_point_center_segment_templated_marker.setData( MultiPointSegmentCenterTemplatedMarkerTool.ID) self.toolbar.addAction( action_multi_point_center_segment_templated_marker) self.actions.append(action_multi_point_center_segment_templated_marker) self.get_map_tool_action_group().addAction( action_single_point_templated_marker) self.enable_actions_for_layer(self.iface.activeLayer()) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" QgsApplication.processingRegistry().removeProvider(self.provider) if self.toolbar is not None: self.toolbar.deleteLater() for action in self.actions: if action is not None: action.deleteLater() self.iface.currentLayerChanged.disconnect(self.current_layer_changed) self.layout_hooks.unload(self.iface) def switch_tool(self, tool_id: str): """ Switches to the tool with the specified tool_id """ tool = self.tools[tool_id] if self.iface.mapCanvas().mapTool() == tool: return self.iface.mapCanvas().setMapTool(tool) self.active_tool = tool self.active_tool.set_layer(self.iface.activeLayer()) def current_layer_changed(self, layer: QgsMapLayer): """ Called when the current layer changes """ self.enable_actions_for_layer(layer) if self.active_tool: self.active_tool.set_layer(layer) def editing_toggled(self, enabled: bool): """ Called when editing mode is toggled """ QTimer.singleShot( 0, partial(self.enable_actions_for_layer, self.iface.activeLayer(), enabled)) def enable_actions_for_layer(self, layer: QgsMapLayer, forced_edit_state=None): """ Toggles whether actions should be enabled for the specified layer """ is_editable = forced_edit_state if is_editable is None: if isinstance(layer, QgsVectorLayer): is_editable = layer.isEditable() else: is_editable = False for action in self.actions: if sip.isdeleted(action): continue if self.tools.get(action.data()): tool = self.tools[action.data()] action.setEnabled( tool.is_compatible_with_layer(layer, is_editable)) if tool == self.active_tool and not action.isEnabled(): self.iface.mapCanvas().unsetMapTool(tool) self.iface.actionPan().trigger()
class VertexComparePlugin(QObject): """QGIS Plugin Implementation.""" def __init__(self, iface: QgisInterface): """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 """ super().__init__() # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QgsApplication.locale() locale_path = os.path.join(self.plugin_dir, 'i18n', '{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) self.toolbar = None self.layer_combo = None self.actions = [] self.dock = None self.vertex_highlighter = VertexHighlighterManager() self.selection_handler = SelectionHandler(self) self.show_vertices_action = None self.show_topology_action = None self.show_dock_action = None @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('VertexCompare', message) def initProcessing(self): """Create the Processing provider""" def initGui(self): """Creates application GUI widgets""" self.initProcessing() self.dock = VertexDockWidget(self.iface.mapCanvas()) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.dock.setUserVisible(False) self.toolbar = QToolBar(self.tr('Vertex Compare Toolbar')) self.toolbar.setObjectName('vertexCompareToolbar') self.iface.addToolBar(self.toolbar) self.layer_combo = QgsMapLayerComboBox() self.layer_combo.setAllowEmptyLayer(True, self.tr('Disabled')) self.layer_combo.setFilters(QgsMapLayerProxyModel.PolygonLayer | QgsMapLayerProxyModel.LineLayer) self.layer_combo.setMinimumWidth( QFontMetrics(self.layer_combo.font()).width('x') * 40) self.layer_combo.setCurrentIndex(0) self.layer_combo.layerChanged.connect(self._set_layer) self.toolbar.addWidget(self.layer_combo) self.show_vertices_action = QAction(self.tr("Show Vertex Numbers"), self) self.show_vertices_action.setIcon( GuiUtils.get_icon('show_vertex_numbers.svg')) self.show_vertices_action.setCheckable(True) self.show_vertices_action.setEnabled(False) self.actions.append(self.show_vertices_action) self.toolbar.addAction(self.show_vertices_action) self.show_vertices_action.toggled.connect( self.vertex_highlighter.set_visible) self.show_topology_action = QAction(self.tr("Compare Vertices"), self) self.show_topology_action.setIcon(GuiUtils.get_icon('topology.svg')) self.show_topology_action.setCheckable(True) self.actions.append(self.show_topology_action) self.toolbar.addAction(self.show_topology_action) self.show_topology_action.toggled.connect( self.vertex_highlighter.set_topological) self.show_dock_action = QAction(self.tr('Show Vertices'), parent=self.toolbar) self.show_dock_action.setIcon(GuiUtils.get_icon('vertex_table.svg')) self.toolbar.addAction(self.show_dock_action) self.actions.append(self.show_dock_action) self.dock.setToggleVisibilityAction(self.show_dock_action) self.selection_handler.selection_changed.connect( self._selection_changed) self.dock.label_filter_changed.connect(self.vertex_highlighter.redraw) self.dock.vertex_symbol_changed.connect(self.vertex_highlighter.redraw) self.dock.vertex_text_format_changed.connect( self.vertex_highlighter.redraw) self.dock.selected_vertex_changed.connect( self.vertex_highlighter.set_selected_vertex) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for a in self.actions: a.deleteLater() self.actions = [] if self.toolbar is not None: self.toolbar.deleteLater() self.toolbar = None if self.dock is not None: self.dock.deleteLater() self.dock = None def _set_layer(self, layer: Optional[QgsVectorLayer]): """ Triggered when the selected layer is changed """ self.selection_handler.set_layer(layer) self.vertex_highlighter.set_layer(layer) self.show_vertices_action.setEnabled(layer is not None) if not self.show_vertices_action.isEnabled(): self.show_vertices_action.setChecked(False) else: self.show_vertices_action.setChecked(True) self.dock.set_selection( layer, layer.selectedFeatureIds() if layer is not None else []) def _selection_changed(self, layer: Optional[QgsVectorLayer], selection: List[int]): """ Triggered when the watched layer's selection is changed """ self.dock.set_selection(layer, selection)