class AttributeEditorSample(QgsMapTool): def start(self): self.layer = self.iface.activeLayer() features = self.layer.selectedFeatures() if len(features) == 0: return self.layer.startEditing() # レイヤを編集状態にする # 選択しているフューチャーの属性フォーム表示 self.attdlg = self.iface.getFeatureForm(self.layer, features[0]) self.attdlg.setMode(QgsAttributeEditorContext.SingleEditMode) self.attdlg.finished.connect(self.commitEdit) self.attdlg.show() def commitEdit(self, result): if result == 1: self.layer.commitChanges() else: self.layer.rollBack() self.attdlg.finished.disconnect(self.commitEdit) def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = '属性編集ダイアログサンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = False # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, AttributeEditorSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class ProductionFrame(QFrame, FORM_CLASS): def __init__(self, dockwidget, parent=None): """Constructor.""" super(ProductionFrame, self).__init__(parent) self.setupUi(self) self.dockwidget = dockwidget self.layer_registry = LayerRegistry() self.db = db self.db.connect() self.building_layer = QgsVectorLayer() self.add_outlines() # Set up edit dialog self.edit_dialog = EditDialog(self) self.change_instance = None self.cb_production.setChecked(True) # set up signals and slots self.btn_exit.clicked.connect(self.exit_clicked) self.cb_production.clicked.connect(self.cb_production_clicked) QgsProject.instance().layerWillBeRemoved.connect(self.layers_removed) self.setup_toolbar() def setup_toolbar(self): if "Add Outline" not in ( action.text() for action in iface.building_toolbar.actions()): image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "plus.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.add_action = QAction(icon, "Add Outline", iface.building_toolbar) iface.registerMainWindowAction(self.add_action, "Ctrl+1") self.add_action.triggered.connect(self.canvas_add_outline) iface.building_toolbar.addAction(self.add_action) if "Edit Geometry" not in ( action.text() for action in iface.building_toolbar.actions()): image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "edit_geometry.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.edit_geom_action = QAction(icon, "Edit Geometry", iface.building_toolbar) iface.registerMainWindowAction(self.edit_geom_action, "Ctrl+2") self.edit_geom_action.triggered.connect(self.canvas_edit_geometry) iface.building_toolbar.addAction(self.edit_geom_action) if "Edit Attributes" not in ( action.text() for action in iface.building_toolbar.actions()): image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "edit_attributes.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.edit_attrs_action = QAction(icon, "Edit Attributes", iface.building_toolbar) iface.registerMainWindowAction(self.edit_attrs_action, "Ctrl+3") self.edit_attrs_action.triggered.connect( self.canvas_edit_attribute) iface.building_toolbar.addAction(self.edit_attrs_action) iface.building_toolbar.show() def add_outlines(self): """ Add building outlines to canvas """ path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "styles/") self.layer_registry.remove_layer(self.building_layer) self.building_historic = self.layer_registry.add_postgres_layer( "historic_outlines", "building_outlines", "shape", "buildings", "", "end_lifespan is not NULL") self.building_historic.loadNamedStyle(path + "building_historic.qml") self.building_layer = None self.building_layer = self.layer_registry.add_postgres_layer( "building_outlines", "building_outlines", "shape", "buildings", "", "end_lifespan is NULL") self.building_layer.loadNamedStyle(path + "building_blue.qml") iface.setActiveLayer(self.building_layer) @pyqtSlot(bool) def cb_production_clicked(self, checked): group = QgsProject.instance().layerTreeRoot().findGroup( "Building Tool Layers") if checked: group.setItemVisibilityCheckedRecursive(True) else: group.setItemVisibilityCheckedRecursive(False) def canvas_add_outline(self): """ When add outline radio button toggled """ self.edit_dialog.show() self.edit_dialog.add_outline() self.change_instance = self.edit_dialog.get_change_instance() self.circle_tool = None self.polyline = None # setup circle button image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "circle.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.circle_action = QAction(icon, "Draw Circle", iface.building_toolbar) iface.registerMainWindowAction(self.circle_action, "Ctrl+0") self.circle_action.triggered.connect(self.circle_tool_clicked) self.circle_action.setCheckable(True) iface.building_toolbar.addAction(self.circle_action) def circle_tool_clicked(self): if self.circle_action.isChecked(): circle_tool.setup_circle(self) else: iface.actionAddFeature().trigger() def canvas_edit_attribute(self): """ When edit outline radio button toggled """ self.edit_dialog.show() self.edit_dialog.edit_attribute() self.change_instance = self.edit_dialog.get_change_instance() def canvas_edit_geometry(self): """ When edit geometry radio button toggled """ self.edit_dialog.edit_geometry() self.edit_dialog.show() self.change_instance = self.edit_dialog.get_change_instance() @pyqtSlot() def exit_clicked(self): """ Called when edit production exit button clicked. """ self.close_frame() self.dockwidget.lst_sub_menu.clearSelection() def close_frame(self): """ Clean up and remove the edit production frame. """ if self.change_instance is not None: self.edit_dialog.close() iface.actionCancelEdits().trigger() QgsProject.instance().layerWillBeRemoved.disconnect( self.layers_removed) self.layer_registry.remove_layer(self.building_layer) self.layer_registry.remove_layer(self.building_historic) # reset toolbar for action in iface.building_toolbar.actions(): if action.objectName() not in ["mActionPan"]: iface.building_toolbar.removeAction(action) iface.building_toolbar.hide() from buildings.gui.menu_frame import MenuFrame dw = self.dockwidget dw.stk_options.removeWidget(dw.stk_options.currentWidget()) dw.new_widget(MenuFrame(dw)) @pyqtSlot() def edit_cancel_clicked(self): if len(QgsProject.instance().mapLayersByName("building_outlines")) > 0: if isinstance(self.change_instance, production_changes.EditAttribute): try: self.building_layer.selectionChanged.disconnect( self.change_instance.selection_changed) except TypeError: pass elif isinstance(self.change_instance, production_changes.EditGeometry): try: self.building_layer.geometryChanged.disconnect() except TypeError: pass elif isinstance(self.change_instance, production_changes.AddProduction): try: self.building_layer.featureAdded.disconnect() except TypeError: pass try: self.building_layer.featureDeleted.disconnect() except TypeError: pass try: self.building_layer.geometryChanged.disconnect() except TypeError: pass if self.polyline: self.polyline.reset() if isinstance(self.circle_tool, PointTool): self.circle_tool.canvas_clicked.disconnect() self.circle_tool.mouse_moved.disconnect() self.circle_tool.deactivate() iface.actionPan().trigger() iface.actionCancelEdits().trigger() self.setup_toolbar() self.change_instance = None @pyqtSlot(str) def layers_removed(self, layerids): self.layer_registry.update_layers() for layer in ["building_outlines", "historic_outlines"]: if layer in layerids: self.cb_production.setDisabled(1) iface.messageBar().pushMessage( "ERROR", "Required layer Removed! Please reload the buildings plugin or the current frame before continuing", level=Qgis.Critical, duration=5, ) return
class ProcessingPlugin: def __init__(self, iface): self.iface = iface self.options_factory = ProcessingOptionsFactory() self.options_factory.setTitle(self.tr('Processing')) iface.registerOptionsWidgetFactory(self.options_factory) self.drop_handler = ProcessingDropHandler() iface.registerCustomDropHandler(self.drop_handler) self.item_provider = ProcessingDataItemProvider() QgsApplication.dataItemProviderRegistry().addProvider( self.item_provider) self.locator_filter = AlgorithmLocatorFilter() iface.registerLocatorFilter(self.locator_filter) # Invalidate the locator filter for in-place when active layer changes iface.currentLayerChanged.connect( lambda _: self.iface.invalidateLocatorResults()) self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter() iface.registerLocatorFilter(self.edit_features_locator_filter) Processing.initialize() def initGui(self): self.toolbox = ProcessingToolbox() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.toolbox) self.toolbox.hide() self.toolbox.visibilityChanged.connect(self.toolboxVisibilityChanged) self.resultsDock = ResultsDock() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.resultsDock) self.resultsDock.hide() self.menu = QMenu(self.iface.mainWindow().menuBar()) self.menu.setObjectName('processing') self.menu.setTitle(self.tr('Pro&cessing')) self.toolboxAction = QAction(self.tr('&Toolbox'), self.iface.mainWindow()) self.toolboxAction.setCheckable(True) self.toolboxAction.setObjectName('toolboxAction') self.toolboxAction.setIcon( QgsApplication.getThemeIcon("/processingAlgorithm.svg")) self.iface.registerMainWindowAction( self.toolboxAction, QKeySequence('Ctrl+Alt+T').toString(QKeySequence.NativeText)) self.toolboxAction.toggled.connect(self.openToolbox) self.iface.attributesToolBar().insertAction( self.iface.actionOpenStatisticalSummary(), self.toolboxAction) self.menu.addAction(self.toolboxAction) self.modelerAction = QAction( QgsApplication.getThemeIcon("/processingModel.svg"), QCoreApplication.translate('ProcessingPlugin', 'Graphical &Modeler…'), self.iface.mainWindow()) self.modelerAction.setObjectName('modelerAction') self.modelerAction.triggered.connect(self.openModeler) self.iface.registerMainWindowAction( self.modelerAction, QKeySequence('Ctrl+Alt+M').toString(QKeySequence.NativeText)) self.menu.addAction(self.modelerAction) self.historyAction = QAction( QgsApplication.getThemeIcon("/mIconHistory.svg"), QCoreApplication.translate('ProcessingPlugin', '&History…'), self.iface.mainWindow()) self.historyAction.setObjectName('historyAction') self.historyAction.triggered.connect(self.openHistory) self.iface.registerMainWindowAction( self.historyAction, QKeySequence('Ctrl+Alt+H').toString(QKeySequence.NativeText)) self.menu.addAction(self.historyAction) self.toolbox.processingToolbar.addAction(self.historyAction) self.resultsAction = QAction( QgsApplication.getThemeIcon("/processingResult.svg"), self.tr('&Results Viewer'), self.iface.mainWindow()) self.resultsAction.setCheckable(True) self.iface.registerMainWindowAction( self.resultsAction, QKeySequence('Ctrl+Alt+R').toString(QKeySequence.NativeText)) self.menu.addAction(self.resultsAction) self.toolbox.processingToolbar.addAction(self.resultsAction) self.resultsDock.visibilityChanged.connect( self.resultsAction.setChecked) self.resultsAction.toggled.connect(self.resultsDock.setUserVisible) self.toolbox.processingToolbar.addSeparator() self.editInPlaceAction = QAction( QgsApplication.getThemeIcon("/mActionProcessSelected.svg"), self.tr('Edit Features In-Place'), self.iface.mainWindow()) self.editInPlaceAction.setObjectName('editInPlaceFeatures') self.editInPlaceAction.setCheckable(True) self.editInPlaceAction.toggled.connect(self.editSelected) self.toolbox.processingToolbar.addAction(self.editInPlaceAction) self.toolbox.processingToolbar.addSeparator() self.optionsAction = QAction( QgsApplication.getThemeIcon("/mActionOptions.svg"), self.tr('Options'), self.iface.mainWindow()) self.optionsAction.setObjectName('optionsAction') self.optionsAction.triggered.connect(self.openProcessingOptions) self.toolbox.processingToolbar.addAction(self.optionsAction) menuBar = self.iface.mainWindow().menuBar() menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(), self.menu) self.menu.addSeparator() initializeMenus() createMenus() # In-place editing button state sync self.iface.currentLayerChanged.connect(self.sync_in_place_button_state) self.iface.mapCanvas().selectionChanged.connect( self.sync_in_place_button_state) self.iface.actionToggleEditing().triggered.connect( partial(self.sync_in_place_button_state, None)) self.sync_in_place_button_state() def sync_in_place_button_state(self, layer=None): """Synchronise the button state with layer state""" if layer is None: layer = self.iface.activeLayer() old_enabled_state = self.editInPlaceAction.isEnabled() new_enabled_state = layer is not None and layer.type( ) == QgsMapLayer.VectorLayer self.editInPlaceAction.setEnabled(new_enabled_state) if new_enabled_state != old_enabled_state: self.toolbox.set_in_place_edit_mode( new_enabled_state and self.editInPlaceAction.isChecked()) def openProcessingOptions(self): self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions') def unload(self): self.toolbox.setVisible(False) self.iface.removeDockWidget(self.toolbox) self.iface.attributesToolBar().removeAction(self.toolboxAction) self.resultsDock.setVisible(False) self.iface.removeDockWidget(self.resultsDock) self.toolbox.deleteLater() self.menu.deleteLater() # delete temporary output files folder = QgsProcessingUtils.tempFolder() if QDir(folder).exists(): shutil.rmtree(folder, True) # also delete temporary help files folder = tempHelpFolder() if QDir(folder).exists(): shutil.rmtree(folder, True) self.iface.unregisterMainWindowAction(self.toolboxAction) self.iface.unregisterMainWindowAction(self.modelerAction) self.iface.unregisterMainWindowAction(self.historyAction) self.iface.unregisterMainWindowAction(self.resultsAction) self.iface.unregisterOptionsWidgetFactory(self.options_factory) self.iface.deregisterLocatorFilter(self.locator_filter) self.iface.deregisterLocatorFilter(self.edit_features_locator_filter) self.iface.unregisterCustomDropHandler(self.drop_handler) QgsApplication.dataItemProviderRegistry().removeProvider( self.item_provider) removeMenus() Processing.deinitialize() def openToolbox(self, show): self.toolbox.setUserVisible(show) def toolboxVisibilityChanged(self, visible): self.toolboxAction.setChecked(visible) def openModeler(self): dlg = ModelerDialog() dlg.update_model.connect(self.updateModel) dlg.show() def updateModel(self): model_provider = QgsApplication.processingRegistry().providerById( 'model') model_provider.refreshAlgorithms() def openResults(self): if self.resultsDock.isVisible(): self.resultsDock.hide() else: self.resultsDock.show() def openHistory(self): dlg = HistoryDialog() dlg.exec_() def tr(self, message): return QCoreApplication.translate('ProcessingPlugin', message) def editSelected(self, enabled): self.toolbox.set_in_place_edit_mode(enabled)
class WebGisPlugin(object): dialog = None project = None ws = None def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value("locale/userLocale")[0:2] localePath = os.path.join(self.plugin_dir, 'i18n', 'gisquick_{}.qm'.format(locale)) if os.path.exists(localePath): self.translator = QTranslator() self.translator.load(localePath) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) def initGui(self): # Create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/gisquick2/img/icon.svg"), u"Publish in Gisquick", self.iface.mainWindow()) self.action.setCheckable(True) # connect the action to the run method self.action.triggered.connect(self.toggle_tool) self.settings_action = QAction( QIcon(":/plugins/gisquick2/img/settings.svg"), u"Configure", self.iface.mainWindow()) # connect the action to the run method self.settings_action.triggered.connect(self.show_settings) # Add toolbar button and menu item # self.iface.addToolBarIcon(self.action) self.iface.addWebToolBarIcon(self.action) self.iface.addPluginToWebMenu(u"&Gisquick2", self.action) self.iface.addPluginToWebMenu(u"&Gisquick2", self.settings_action) def unload(self): if self.ws: gisquick_ws.stop() self.ws = None # Remove the plugin menu item and icon self.iface.removePluginWebMenu(u"&Gisquick2", self.action) self.iface.removePluginWebMenu(u"&Gisquick2", self.settings_action) self.iface.removeWebToolBarIcon(self.action) def is_overlay_layer_for_publish(self, layer): """Checks whether layer can be published as an overlay layer. Args: layer (qgis.core.QgsMapLayer): project layer Returns: bool: True if a layer can be published as an overlay layer """ return (layer.type() == QgsMapLayer.VectorLayer or (layer.type() == QgsMapLayer.RasterLayer and layer.providerType() != "wms")) def is_base_layer_for_publish(self, layer): """Checks whether layer could be published as a base layer. Args: layer (qgis.core.QgsMapLayer): project layer Returns: bool: True if a layer can be published as a base layer """ return layer.type() == QgsMapLayer.RasterLayer and layer.providerType( ) == "wms" def map_units(self): """Returns units name of the project (map). Returns: str: map units name ('meters', 'feet', 'degrees', 'miles' or 'unknown') """ return { 0: 'meters', 1: 'feet', 2: 'degrees', 3: 'unknown', 7: 'miles' }[self.iface.mapCanvas().mapUnits()] def scales_to_resolutions(self, scales): """Converts map scales to tile resolutions (with fixed DPI=96). Args: scales (List[int]): array of map scales Returns: List[Decimal]: array of computed tile resolutions """ return scales_to_resolutions(scales, self.map_units()) def resolutions_to_scales(self, resolutions): """Converts tile resolutions to map scales (with fixed DPI=96). Args: resolutions (List[Decimal]): array of tile resolutions Returns: List[int]: array of computed map scales """ return resolutions_to_scales(resolutions, self.map_units()) def filter_visible_resolutions(self, resolutions, layer): """Filters given tile resolutions by layer's visibility settings. Args: resolutions (List[Decimal]): array of tile resolutions layer (qgis.core.QgsMapLayer): map layer Returns: List[Decimal]: array of visible tile resolutions """ if layer.hasScaleBasedVisibility(): max_scale_exclusive = layer.maximumScale() min_scale_inclusive = layer.minimumScale() max_res_exclusive, min_res_inclusive = self.scales_to_resolutions( [max_scale_exclusive, min_scale_inclusive]) return [ res for res in resolutions if res >= min_res_inclusive and res < max_res_exclusive ] return resolutions def wmsc_layer_resolutions(self, layer): """Returns visible resolutions of given WMSC layer. Args: layer (qgis.core.QgsRasterLayer): raster layer (WMSC) Returns: List[Decimal]: array of layer's visible tile resolutions """ layer_resolutions = layer.dataProvider().property('resolutions') if layer_resolutions: layer_resolutions = to_decimal_array(layer_resolutions) if layer.hasScaleBasedVisibility(): layer_resolutions = self.filter_visible_resolutions( layer_resolutions, layer) if layer_resolutions: return sorted(layer_resolutions, reverse=True) return [] return None def project_layers_resolutions(self): """Returns list of possible tile resolutions for current project. Returns: List[Decimal]: project tile resolutions """ # compute resolutions as an union of resolutions calculated from project's # map scales and resolutions of all WMSC layers. project_tile_resolutions = set() # collect set of all resolutions from WMSC base layers base_layers = { layer.id(): layer for layer in QgsProject.instance().mapLayers().values() if self.is_base_layer_for_publish(layer) } for layer in list(base_layers.values()): layer_resolutions = self.wmsc_layer_resolutions(layer) if layer_resolutions: project_tile_resolutions.update(layer_resolutions) wmsc_layers_scales = self.resolutions_to_scales( project_tile_resolutions) scales, ok = self.project.readListEntry("Scales", "/ScalesList") if ok and scales: scales = [int(scale.split(":")[-1]) for scale in scales] # filter duplicit scales scales = [ scale for scale in scales if scale not in wmsc_layers_scales ] project_tile_resolutions.update( self.scales_to_resolutions(sorted(scales, reverse=True))) project_tile_resolutions = sorted(project_tile_resolutions, reverse=True) return project_tile_resolutions def layers_list(self): """Returns array of all project's layers. Returns: List[qgis.core.QgsMapLayer]: project's layers """ # legend_iface = self.iface.legendInterface().layers() return [ tree_layer.layer() for tree_layer in QgsProject.instance().layerTreeRoot().findLayers() ] def get_layer_attributes(self, layer): fields = layer.fields() attributes_data = [] excluded_attributes = layer.excludeAttributesWfs() conversion_types = { 'BIGINT': 'INTEGER', 'INTEGER64': 'INTEGER', 'REAL': 'DOUBLE', 'STRING': 'TEXT', 'INT2': 'INTEGER', 'INT4': 'INTEGER', 'INT8': 'INTEGER', 'NUMERIC': 'DOUBLE', 'FLOAT8': 'DOUBLE', 'VARCHAR': 'TEXT', 'CHARACTER': 'TEXT' } for field in fields: if field.name() in excluded_attributes: continue field_type = field.typeName().upper() if field_type in conversion_types: field_type = conversion_types[field_type] attribute_data = { 'name': field.name(), 'type': field_type, #'length': field.length(), #'precision': field.precision() } if field.comment(): attribute_data['comment'] = field.comment() alias = layer.attributeAlias(fields.indexFromName(field.name())) if alias: attribute_data['alias'] = alias attributes_data.append(attribute_data) return attributes_data def get_project_layers(self, skip_layers_with_error=False): dbname_pattern = re.compile("dbname='([^']+)'") project = QgsProject.instance() project_dir = project.absolutePath() + os.path.sep non_identifiable_layers = project.readListEntry( "Identify", "/disabledLayers")[0] or [] wfs_layers = project.readListEntry("WFSLayers", "/")[0] or [] map_canvas = self.iface.mapCanvas() map_settings = map_canvas.mapSettings() if project.layerTreeRoot().hasCustomLayerOrder(): layers_order = project.layerTreeRoot().customLayerOrder() else: layers_order = self.layers_list() def visit_node(tree_node): if isinstance(tree_node, QgsLayerTreeLayer): layer = tree_node.layer() layer_type = { 0: "vector", 1: "raster", # 2: PluginLayer # 3: MeshLayer }[layer.type()] source = layer.source() provider_type = layer.providerType() uri = "" if provider_type == "wms": source_params = parse_qs(source) uri = source_params["url"][0] elif provider_type == "postgres": dp = layer.dataProvider() uri = "postgresql://%s:%s" % (dp.uri().host(), dp.uri().port()) elif provider_type in ("ogr", "gdal"): uri = "file://%s" % source.split("|")[0] elif provider_type == "spatialite": match = dbname_pattern.search(source) if match: uri = "file://%s" % match.group(1) else: uri = source extent = layer.extent() if not extent.isEmpty(): extent = map_settings.layerExtentToOutputExtent( layer, layer.extent()).toRectF().getCoords() else: extent = None info = { "id": layer.id(), "name": layer.name(), "serverName": layer.shortName() if hasattr(layer, "shortName") else layer.name(), "wfs": layer.id() in wfs_layers, "provider_type": provider_type, "projection": layer.crs().authid(), "type": layer_type, "source": uri, "extent": extent, "visible": project.layerTreeRoot().findLayer(layer.id()).isVisible(), "metadata": { "title": layer.title(), "abstract": layer.abstract(), "keyword_list": layer.keywordList() } } legend_url = layer.legendUrl() if legend_url: info["legend_url"] = legend_url # if layer.isSpatial() if layer_type == "vector": info["geom_type"] = ('POINT', 'LINE', 'POLYGON', None, None)[layer.geometryType()] info["wkb_type"] = QgsWkbTypes.displayString( layer.wkbType()) info["labels"] = layer.labelsEnabled() info["attributes"] = self.get_layer_attributes(layer) info["queryable"] = bool(info["attributes"]) and layer.id( ) not in non_identifiable_layers and layer.id( ) in wfs_layers if info["attributes"]: fields = layer.fields() info["pk_attributes"] = [ fields.at(index).name() for index in layer.dataProvider().pkAttributeIndexes() ] if provider_type == "wms": info["url"] = source_params["url"][0] img_format = source_params.get("format", [None])[0] if not img_format: img_format = os.path.splitext(info["url"])[1].replace( ".", "image/") info["format"] = img_format info["dpi"] = layer.dataProvider().dpi() if "layers" in source_params: info["wms_layers"] = source_params["layers"] if layer in layers_order: info["drawing_order"] = layers_order.index(layer) if layer.attribution(): info["attribution"] = { "title": layer.attribution(), "url": layer.attributionUrl() } return info else: children = [] for child_tree_node in tree_node.children(): try: info = visit_node(child_tree_node) if info: children.append(info) except Exception as e: if not skip_layers_with_error: msg = "Failed to gather info from layer: '%s'" % child_tree_node.name( ) raise WsError(msg, 405) from e return {"name": tree_node.name(), "layers": children} root_node = self.iface.layerTreeView().layerTreeModel().rootGroup() return visit_node(root_node)["layers"] def get_print_templates(self): composer_templates = [] project_layout_manager = QgsProject.instance().layoutManager() for layout in project_layout_manager.layouts(): map = layout.referenceMap() units_conversion = map.mapUnitsToLayoutUnits() composer_data = { 'name': layout.name(), 'width': layout.layoutBounds().width(), 'height': layout.layoutBounds().height(), 'map': { 'name': 'map0', 'x': map.pagePos().x(), 'y': map.pagePos().y(), 'width': map.extent().width() * units_conversion, 'height': map.extent().height() * units_conversion }, 'labels': [ item.id() for item in list(layout.items()) if isinstance(item, QgsLayoutItemLabel) and item.id() ] } grid = map.grid() if grid.enabled(): composer_data['map']['grid'] = { 'intervalX': grid.intervalX(), 'intervalY': grid.intervalY(), } composer_templates.append(composer_data) return composer_templates def get_project_info(self, skip_layers_with_error=False): project = QgsProject.instance() project_crs = project.crs() map_canvas = self.iface.mapCanvas() # scales, _ = project.readListEntry("Scales", "/ScalesList") # scales = [int(s.split(":")[1]) for s in scales] view_settings = project.viewSettings() scales = view_settings.mapScales() projections = {} crs_list = [project_crs ] + [l.crs() for l in project.mapLayers().values()] for crs in crs_list: if crs.authid() not in projections: projections[crs.authid()] = { "is_geographic": crs.isGeographic(), "proj4": crs.toProj4() } data = { "file": project.absoluteFilePath(), "directory": project.absolutePath(), "title": project.title() or project.readEntry("WMSServiceTitle", "/")[0], "layers": self.get_project_layers(skip_layers_with_error), "composer_templates": self.get_print_templates(), "projection": { "code": project_crs.authid(), "is_geographic": project_crs.isGeographic(), "proj4": project_crs.toProj4() }, "units": self.map_units(), "scales": scales, "position_precision": { "automatic": project.readBoolEntry("PositionPrecision", "/Automatic")[0], "decimal_places": project.readNumEntry("PositionPrecision", "/DecimalPlaces")[0] }, "extent": map_canvas.fullExtent().toRectF().getCoords(), # "default_view_extent": view_settings.defaultViewExtent(), "server": { "wms_add_geometry": project.readBoolEntry("WMSAddWktGeometry", "")[0] }, "projections": projections } return data def get_settings(self): return QSettings(QSettings.IniFormat, QSettings.UserScope, "Gisquick", "gisquick2") def show_settings(self): settings = self.get_settings() dialog_filename = os.path.join(self.plugin_dir, "ui", "settings.ui") dialog = PyQt5.uic.loadUi(dialog_filename) dialog.server_url.setText(settings.value("server_url", "")) dialog.username.setText(settings.value("username", "")) dialog.password.setText(settings.value("password", "")) dialog.show() res = dialog.exec_() if res == 1: settings.setValue("server_url", dialog.server_url.text().rstrip("/")) settings.setValue("username", dialog.username.text()) settings.setValue("password", dialog.password.text()) def on_project_change(self, *args): gisquick_ws.send("ProjectChanged") def on_project_closed(self, *args): def debounced(): # filter events caused by switching between projects if not QgsProject.instance().absoluteFilePath(): gisquick_ws.send("ProjectChanged") QTimer.singleShot(300, debounced) def toggle_tool(self, active): """Display dialog window for publishing current project. During a configuration process (wizard setup), plugin will hold actual metadata object in 'WebGisPlugin.metadata' property. If metadata from previous publishing still exist, they will be loaded and stored in 'WebGisPlugin.last_metadata' property. """ def callback(msg): msg_type = msg["type"] data = msg.get("data") if msg_type == "ProjectInfo": if QgsProject.instance().absolutePath(): if data: skip_layers_with_error = data.get( "skip_layers_with_error", False) return self.get_project_info( skip_layers_with_error=skip_layers_with_error) raise WsError("Project is not opened", 404) elif msg_type == "ProjectDirectory": dir_path = QgsProject.instance().absolutePath() if dir_path: return dir_path raise WsError("Project is not opened", 404) else: raise ValueError("Unknown message type: %s" % msg_type) def on_connection_estabilished(): # self.iface.messageBar().pushMessage("Gisquick", "plugin is connected to server: %s" % server_url, level=Qgis.Success) def open_browser(): import webbrowser webbrowser.open(urljoin(server_url, '/user/')) widget = self.iface.messageBar().createMessage( "Gisquick", "successfully connected to server: %s" % server_url) button = QPushButton(widget) button.setText("Open Browser") button.pressed.connect(open_browser) widget.layout().addWidget(button) self.iface.messageBar().pushWidget(widget, Qgis.Success) self.active_notification_widget = widget project = QgsProject.instance() if active: self.active_notification_widget = None settings = self.get_settings() server_url = settings.value("server_url") username = settings.value("username") password = settings.value("password") if not server_url or not username or not password: self.show_settings() server_url = settings.value("server_url") username = settings.value("username") password = settings.value("password") plugin_ver = __metadata__["general"].get("version") client_info = "GisquickPlugin/%s (%s %s; QGIS %s)" % ( plugin_ver, platform.system(), platform.machine(), Qgis.QGIS_VERSION) class WebsocketServer(QThread): finished = QtCore.pyqtSignal(int) success = QtCore.pyqtSignal() def run(self): # print("Starting WS", "server:", server_url, "user:", username) def on_success(): self.success.emit() res = gisquick_ws.start(server_url, username, password, client_info, callback, on_success) self.finished.emit(res) def on_finished(res): self.ws = None if self.action.isChecked(): self.action.setChecked(False) if res != 0: QMessageBox.warning(None, 'Warning', 'Failed to connect!') else: if self.iface.messageBar().currentItem( ) == self.active_notification_widget: self.iface.messageBar().popWidget( self.active_notification_widget) self.active_notification_widget = None self.ws = WebsocketServer() self.ws.finished.connect(on_finished) self.ws.success.connect(on_connection_estabilished) r = self.ws.start() # project.isDirtyChanged.connect(self.on_project_change) project.readProject.connect(self.on_project_change) project.projectSaved.connect(self.on_project_change) project.cleared.connect(self.on_project_closed) else: gisquick_ws.stop() project.readProject.disconnect(self.on_project_change) project.projectSaved.disconnect(self.on_project_change) project.cleared.disconnect(self.on_project_closed)
class proposalsPanel(RestrictionTypeUtilsMixin): def __init__(self, iface, TOMsToolBar): #def __init__(self, iface, TOMsMenu, proposalsManager): # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() self.TOMsToolBar = TOMsToolBar self.actionProposalsPanel = QAction( QIcon(":/plugins/TOMs/resources/TOMsStart.png"), QCoreApplication.translate("MyPlugin", "Start TOMs"), self.iface.mainWindow()) self.actionProposalsPanel.setCheckable(True) self.TOMsToolBar.addAction(self.actionProposalsPanel) self.actionProposalsPanel.triggered.connect(self.onInitProposalsPanel) self.newProposalRequired = False self.proposalsManager = TOMsProposalsManager(self.iface) self.tableNames = self.proposalsManager.tableNames # Now set up the toolbar self.RestrictionTools = manageRestrictionDetails( self.iface, self.TOMsToolBar, self.proposalsManager) self.RestrictionTools.disableTOMsToolbarItems() self.searchBar = searchBar(self.iface, self.TOMsToolBar, self.proposalsManager) self.searchBar.disableSearchBar() TOMsMessageLog.logMessage("Finished proposalsPanel init ...", level=Qgis.Warning) def onInitProposalsPanel(self): """Filter main layer based on date and state options""" TOMsMessageLog.logMessage("In onInitProposalsPanel", level=Qgis.Info) #print "** STARTING ProposalPanel" # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) # self.TOMSLayers.TOMsStartupFailure.connect(self.setCloseTOMsFlag) #self.RestrictionTypeUtilsMixin.tableNames.TOMsStartupFailure.connect(self.closeTOMsTools) if self.actionProposalsPanel.isChecked(): TOMsMessageLog.logMessage( "In onInitProposalsPanel. Activating ...", level=Qgis.Info) self.openTOMsTools() else: TOMsMessageLog.logMessage( "In onInitProposalsPanel. Deactivating ...", level=Qgis.Info) self.closeTOMsTools() pass def openTOMsTools(self): # actions when the Proposals Panel is closed or the toolbar "start" is toggled TOMsMessageLog.logMessage("In openTOMsTools. Activating ...", level=Qgis.Info) self.closeTOMs = False # Check that tables are present TOMsMessageLog.logMessage("In onInitProposalsPanel. Checking tables", level=Qgis.Info) self.tableNames.TOMsLayersNotFound.connect(self.setCloseTOMsFlag) self.tableNames.getLayers() if self.closeTOMs: QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Unable to start TOMs ...")) self.actionProposalsPanel.setChecked(False) return # QMessageBox.information(self.iface.mainWindow(), "ERROR", ("TOMsActivated about to emit")) self.proposalsManager.TOMsActivated.emit() self.dock = ProposalPanelDockWidget() self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock) # set up tabbing for Panels self.setupPanelTabs(self.iface, self.dock) self.proposalsManager.dateChanged.connect(self.onDateChanged) self.dock.filterDate.setDisplayFormat("dd-MM-yyyy") self.dock.filterDate.setDate(QDate.currentDate()) self.Proposals = self.tableNames.setLayer("Proposals") # Set up field details for table ** what about errors here ** idxProposalID = self.Proposals.fields().indexFromName("ProposalID") self.idxProposalTitle = self.Proposals.fields().indexFromName( "ProposalTitle") self.idxCreateDate = self.Proposals.fields().indexFromName( "ProposalCreateDate") self.idxOpenDate = self.Proposals.fields().indexFromName( "ProposalOpenDate") self.idxProposalStatusID = self.Proposals.fields().indexFromName( "ProposalStatusID") self.createProposalcb() # set CurrentProposal to be 0 #self.proposalsManager.setCurrentProposal(0) # set up action for when the date is changed from the user interface self.dock.filterDate.dateChanged.connect( lambda: self.proposalsManager.setDate(self.dock.filterDate.date())) # set up action for "New Proposal" self.dock.btn_NewProposal.clicked.connect(self.onNewProposal) # set up action for "View Proposal" self.dock.btn_ViewProposal.clicked.connect(self.onProposalDetails) self.proposalsManager.newProposalCreated.connect( self.onNewProposalCreated) # Create a transaction object for the Proposals self.proposalTransaction = TOMsTransaction(self.iface, self.proposalsManager) self.RestrictionTools.enableTOMsToolbarItems(self.proposalTransaction) self.searchBar.enableSearchBar() # setup use of "Escape" key to deactive map tools - https://gis.stackexchange.com/questions/133228/how-to-deactivate-my-custom-tool-by-pressing-the-escape-key-using-pyqgis """shortcutEsc = QShortcut(QKeySequence(Qt.Key_Escape), self.iface.mainWindow()) shortcutEsc.setContext(Qt.ApplicationShortcut) shortcutEsc.activated.connect(self.iface.mapCanvas().unsetMapTool(self.mapTool))""" self.proposalsManager.setCurrentProposal(0) # TODO: Deal with the change of project ... More work required on this # self.TOMsProject = QgsProject.instance() # self.TOMsProject.cleared.connect(self.closeTOMsTools) def setCloseTOMsFlag(self): self.closeTOMs = True def closeTOMsTools(self): # actions when the Proposals Panel is closed or the toolbar "start" is toggled TOMsMessageLog.logMessage("In closeTOMsTools. Deactivating ...", level=Qgis.Info) # TODO: Delete any objects that are no longer needed self.proposalTransaction.rollBackTransactionGroup() del self.proposalTransaction # There is another call to this function from the dock.close() # Now disable the items from the Toolbar self.RestrictionTools.disableTOMsToolbarItems() self.searchBar.disableSearchBar() self.actionProposalsPanel.setChecked(False) # Now close the proposals panel self.dock.close() # Now clear the filters self.proposalsManager.clearRestrictionFilters() pass def createProposalcb(self): TOMsMessageLog.logMessage("In createProposalcb", level=Qgis.Info) # set up a "NULL" field for "No proposals to be shown" #self.dock.cb_ProposalsList.currentIndexChanged.connect(self.onProposalListIndexChanged) #self.dock.cb_ProposalsList.currentIndexChanged.disconnect(self.onProposalListIndexChanged) self.dock.cb_ProposalsList.clear() currProposalID = 0 currProposalTitle = "0 - No proposal shown" TOMsMessageLog.logMessage("In createProposalcb: Adding 0", level=Qgis.Info) self.dock.cb_ProposalsList.addItem(currProposalTitle, currProposalID) for (currProposalID, currProposalTitle, currProposalStatusID, currProposalOpenDate, currProposal) in sorted( self.proposalsManager.getProposalsListWithStatus( ProposalStatus.IN_PREPARATION), key=lambda f: f[1]): TOMsMessageLog.logMessage("In createProposalcb: proposalID: " + str(currProposalID) + ":" + currProposalTitle, level=Qgis.Info) self.dock.cb_ProposalsList.addItem(currProposalTitle, currProposalID) # set up action for when the proposal is changed self.dock.cb_ProposalsList.currentIndexChanged.connect( self.onProposalListIndexChanged) def onChangeProposal(self): TOMsMessageLog.logMessage("In onChangeProposal", level=Qgis.Info) # https://gis.stackexchange.com/questions/94135/how-to-populate-a-combobox-with-layers-in-toc newProposal_cbIndex = self.dock.cb_ProposalsList.currentIndex() newProposalID = self.dock.cb_ProposalsList.itemData( newProposal_cbIndex) newProposalTitle = self.dock.cb_ProposalsList.currentText() self.setCurrentProposal(newProposalID) TOMsMessageLog.logMessage("In onChangeProposal. newProposalID: " + str(newProposalID) + " newProposalTitle: " + str(newProposalTitle), level=Qgis.Info) # Set the project variable reply = QMessageBox.information(self.iface.mainWindow(), "Information", "All changes will be rolled back", QMessageBox.Ok) def onNewProposal(self): TOMsMessageLog.logMessage("In onNewProposal", level=Qgis.Info) # set up a transaction self.proposalTransaction.startTransactionGroup() # create a new Proposal """self.newProposal = QgsFeature(self.Proposals.fields()) #newProposal.setGeometry(QgsGeometry()) self.newProposal[self.idxProposalTitle] = '' #str(uuid.uuid4()) self.newProposal[self.idxCreateDate] = self.proposalsManager.date() self.newProposal[self.idxOpenDate] = self.proposalsManager.date() self.newProposal[self.idxProposalStatusID] = ProposalStatus.IN_PREPARATION self.newProposal.setGeometry(QgsGeometry()) self.Proposals.addFeature(self.newProposal) # TH (added for v3)""" self.newProposalObject = self.proposalsManager.currentProposalObject( ).initialiseProposal() self.newProposal = self.proposalsManager.currentProposalObject( ).getProposalRecord() self.proposalDialog = self.iface.getFeatureForm( self.Proposals, self.newProposal) #self.proposalDialog.attributeForm().disconnectButtonBox() self.button_box = self.proposalDialog.findChild( QDialogButtonBox, "button_box") if self.button_box is None: TOMsMessageLog.logMessage("In onNewProposal. button box not found", level=Qgis.Info) #self.button_box.accepted.disconnect() self.button_box.accepted.connect( functools.partial(self.onSaveProposalFormDetails, self.newProposal, self.newProposalObject, self.Proposals, self.proposalDialog, self.proposalTransaction)) #self.button_box.rejected.disconnect() self.button_box.rejected.connect(self.onRejectProposalDetailsFromForm) self.proposalDialog.attributeForm().attributeChanged.connect( functools.partial(self.onAttributeChangedClass2, self.newProposal, self.Proposals)) self.proposalDialog.show() #self.iface.openFeatureForm(self.Proposals, newProposal, False, True) #self.createProposalcb() pass def onNewProposalCreated(self, proposal): TOMsMessageLog.logMessage("In onNewProposalCreated. New proposal = " + str(proposal), level=Qgis.Info) self.createProposalcb() # change the list to show the new proposal for currIndex in range(self.dock.cb_ProposalsList.count()): currProposalID = self.dock.cb_ProposalsList.itemData(currIndex) #TOMsMessageLog.logMessage("In onNewProposalSaved. checking index = " + str(currIndex), level=Qgis.Info) if currProposalID == proposal: TOMsMessageLog.logMessage( "In onNewProposalCreated. index found as " + str(currIndex), level=Qgis.Info) self.dock.cb_ProposalsList.setCurrentIndex(currIndex) return return #def onSaveProposalDetailsFromForm(self): #self.onSaveProposalFormDetails(self.newProposal, self.Proposals, self.proposalDialog, self.currTransaction) def onRejectProposalDetailsFromForm(self): self.Proposals.destroyEditCommand() self.proposalDialog.reject() #self.rollbackCurrentEdits() self.proposalTransaction.rollBackTransactionGroup() pass def onProposalDetails(self): TOMsMessageLog.logMessage("In onProposalDetails", level=Qgis.Info) # set up transaction self.proposalTransaction.startTransactionGroup() # https://gis.stackexchange.com/questions/94135/how-to-populate-a-combobox-with-layers-in-toc currProposal_cbIndex = self.dock.cb_ProposalsList.currentIndex() if currProposal_cbIndex == 0: return # there is nothing to see currProposalID = self.dock.cb_ProposalsList.itemData( currProposal_cbIndex) # self.currProposal = self.getProposal(currProposalID) self.currProposalObject = self.proposalsManager.currentProposalObject() self.currProposal = self.proposalsManager.currentProposalObject( ).getProposalRecord() self.proposalDialog = self.iface.getFeatureForm( self.Proposals, self.currProposal) #self.proposalDialog.attributeForm().disconnectButtonBox() self.button_box = self.proposalDialog.findChild( QDialogButtonBox, "button_box") if self.button_box is None: TOMsMessageLog.logMessage("In onNewProposal. button box not found", level=Qgis.Info) self.button_box.accepted.disconnect() self.button_box.accepted.connect( functools.partial(self.onSaveProposalFormDetails, self.currProposal, self.currProposalObject, self.Proposals, self.proposalDialog, self.proposalTransaction)) self.button_box.rejected.disconnect() self.button_box.rejected.connect(self.onRejectProposalDetailsFromForm) self.proposalDialog.attributeForm().attributeChanged.connect( functools.partial(self.onAttributeChangedClass2, self.currProposal, self.Proposals)) self.proposalDialog.show() pass def onProposalListIndexChanged(self): TOMsMessageLog.logMessage("In onProposalListIndexChanged.", level=Qgis.Info) #currProposal = self.proposalsManager.currentProposal() #currProposalIdx = self.dock.cb_ProposalsList.findData(currProposal) #self.dock.cb_ProposalsList.setCurrentIndex(currProposalIdx) currProposal_cbIndex = self.dock.cb_ProposalsList.currentIndex() TOMsMessageLog.logMessage( "In onProposalListIndexChanged. Current Index = " + str(currProposal_cbIndex), level=Qgis.Info) currProposalID = self.dock.cb_ProposalsList.itemData( currProposal_cbIndex) self.proposalsManager.setCurrentProposal(currProposalID) TOMsMessageLog.logMessage("In onProposalChanged. Zoom to extents", level=Qgis.Info) """if self.proposalsManager.getProposalBoundingBox(): TOMsMessageLog.logMessage("In onProposalChanged. Bounding box found", level=Qgis.Info) self.iface.mapCanvas().setExtent(self.proposalsManager.getProposalBoundingBox()) self.iface.mapCanvas().refresh()""" def updateCurrentProposal(self): TOMsMessageLog.logMessage("In updateCurrentProposal.", level=Qgis.Info) """Will be called whenever a new entry is selected in the combobox""" # Can we check to see if there are any outstanding edits?!! """reply = QMessageBox.information(self.iface.mainWindow(), "Information", "All changes will be rolled back", QMessageBox.Ok) if reply: self.iface.actionRollbackAllEdits().trigger() self.iface.actionCancelAllEdits().trigger() pass""" currProposal_cbIndex = self.dock.cb_ProposalsList.currentIndex() currProposalID = self.dock.cb_ProposalsList.itemData( currProposal_cbIndex) self.proposalsManager.setCurrentProposal(currProposalID) def onDateChanged(self): TOMsMessageLog.logMessage("In onDateChanged.", level=Qgis.Info) date = self.proposalsManager.date() self.dock.filterDate.setDate(date) """ onChangeProposalStatus(self): TOMsMessageLog.logMessage("In onChangeProposalStatus. Proposed status: " + str(self.Proposals.fields().indexFromName("ProposalStatusID")), level=Qgis.Info) # check to see if the proposal is "Accepted" acceptProposal = False newProposalStatus = int(self.Proposals.fields().indexFromName("ProposalStatusID")) if newProposalStatus == 1: # should be 2 but with list ... # if so, check to see if this was intended reply = QMessageBox.question(self.iface.mainWindow(), 'Confirm changes to Proposal', 'Are you you want to accept this proposal?. Accepting will make all the proposed changes permanent.', QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: # make the changes permanent acceptProposal = True # bring the Proposals dislog back to the front self.dlg.activateWindow() return acceptProposal""" """def getRestrictionLayerTableID(self, currRestLayer): TOMsMessageLog.logMessage("In getRestrictionLayerTableID.", level=Qgis.Info) # find the ID for the layer within the table " RestrictionsLayers = QgsMapLayerRegistry.instance().mapLayersByName("RestrictionLayers2")[0] layersTableID = 0 # not sure if there is better way to search for something, .e.g., using SQL ?? for layer in RestrictionsLayers.getFeatures(): if layer.attribute("RestrictionLayerName") == str(currRestLayer.name()): layersTableID = layer.attribute("id") TOMsMessageLog.logMessage("In getRestrictionLayerTableID. layersTableID: " + str(layersTableID), level=Qgis.Info) return layersTableID""" def getProposal(self, proposalID): TOMsMessageLog.logMessage("In getProposal.", level=Qgis.Info) # proposalsLayer = QgsMapLayerRegistry.instance().mapLayersByName("Proposals")[0] -- v2 proposalsLayer = QgsProject.instance().mapLayersByName("Proposals")[0] # not sure if there is better way to search for something, .e.g., using SQL ?? for currProposal in proposalsLayer.getFeatures(): if currProposal.attribute("ProposalID") == proposalID: return currProposal return None pass
class LayerTreeViewSample(QgsMapTool): def changeLayer(self, layer): if (layer == None): # レイヤウィンドウに何も無い状態 self.currentlayer = None self.cleared.emit() return if self.currentlayer != None: print(self.currentlayer.name() + 'が非アクティブになりました。') print(layer.name() + 'がアクティブになりました。') self.currentlayer = layer def start(self): self.currentlayer = self.iface.layerTreeView().currentLayer() self.iface.layerTreeView().currentLayerChanged.connect( self.changeLayer) maptool = self # 場合によって書き換えて self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect( self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 def finish(self): self.iface.layerTreeView().currentLayerChanged.disconnect( self.changeLayer) self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'ダイアログ無し雛形' # プラグイン名 self.menu_pos = '雛形' # プラグインの登録場所(このサンプルの場合、メニューの「プラグイン/雛形/ダイアログ無し雛形」) self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, LayerTreeViewSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class captureGPSFeatures(FieldRestrictionTypeUtilsMixin): def __init__(self, iface, featuresWithGPSToolbar): TOMsMessageLog.logMessage("In captureGPSFeatures::init", level=Qgis.Info) FieldRestrictionTypeUtilsMixin.__init__(self, iface) # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() self.featuresWithGPSToolbar = featuresWithGPSToolbar self.gpsMapTool = False self.marker = None # This will set up the items on the toolbar # Create actions self.gnssToolGroup = QActionGroup(featuresWithGPSToolbar) self.actionCreateRestriction = QAction(QIcon(":/plugins/featureswithgps/resources/mActionAddTrack.svg"), QCoreApplication.translate("MyPlugin", "Create Restriction"), self.iface.mainWindow()) self.actionCreateRestriction.setCheckable(True) self.actionAddGPSLocation = QAction(QIcon(":/plugins/featureswithgps/resources/greendot3.png"), QCoreApplication.translate("MyPlugin", "Add vertex from gnss"), self.iface.mainWindow()) #self.actionAddGPSLocation.setCheckable(True) self.actionRemoveRestriction = QAction(QIcon(":plugins/featureswithgps/resources/mActionDeleteTrack.svg"), QCoreApplication.translate("MyPlugin", "Remove Restriction"), self.iface.mainWindow()) self.actionRemoveRestriction.setCheckable(True) self.actionRestrictionDetails = QAction(QIcon(":/plugins/featureswithgps/resources/mActionGetInfo.svg"), QCoreApplication.translate("MyPlugin", "Get Restriction Details"), self.iface.mainWindow()) self.actionRestrictionDetails.setCheckable(True) self.gnssToolGroup.addAction(self.actionRestrictionDetails) self.actionCreateSign = QAction(QIcon(":/plugins/featureswithgps/resources/mActionSetEndPoint.svg"), QCoreApplication.translate("MyPlugin", "Create sign from gnss"), self.iface.mainWindow()) self.actionCreateSign.setCheckable(True) self.actionCreateMTR = QAction(QIcon(":/plugins/featureswithgps/resources/UK_traffic_sign_606F.svg"), QCoreApplication.translate("MyPlugin", "Create moving traffic restriction"), self.iface.mainWindow()) self.actionCreateMTR.setCheckable(True) self.actionMoveFeatureToDifferentLayer = QAction(QIcon(""), QCoreApplication.translate("MyPlugin", "Move feature to different layer"), self.iface.mainWindow()) self.actionMoveFeatureToDifferentLayer.setCheckable(True) self.gnssToolGroup.addAction(self.actionMoveFeatureToDifferentLayer) # Add actions to the toolbar self.featuresWithGPSToolbar.addAction(self.actionCreateRestriction) self.featuresWithGPSToolbar.addAction(self.actionAddGPSLocation) self.featuresWithGPSToolbar.addAction(self.actionRestrictionDetails) #self.featuresWithGPSToolbar.addAction(self.actionRemoveRestriction) self.featuresWithGPSToolbar.addAction(self.actionCreateSign) #self.featuresWithGPSToolbar.addAction(self.actionCreateMTR) self.featuresWithGPSToolbar.addAction(self.actionMoveFeatureToDifferentLayer) self.gnssToolGroup.addAction(self.actionCreateRestriction) #self.gnssToolGroup.addAction(self.actionAddGPSLocation) #self.gnssToolGroup.addAction(self.actionRemoveRestriction) self.gnssToolGroup.addAction(self.actionRestrictionDetails) #self.gnssToolGroup.addAction(self.actionCreateSign) #self.gnssToolGroup.addAction(self.actionCreateMTR) self.gnssToolGroup.addAction(self.actionMoveFeatureToDifferentLayer) self.gnssToolGroup.setExclusive(True) self.gnssToolGroup.triggered.connect(self.onGroupTriggered) # Connect action signals to slots self.actionCreateRestriction.triggered.connect(self.doCreateRestriction) self.actionAddGPSLocation.triggered.connect(self.doAddGPSLocation) self.actionRestrictionDetails.triggered.connect(self.doRestrictionDetails) #self.actionRemoveRestriction.triggered.connect(self.doRemoveRestriction) self.actionCreateSign.triggered.connect(self.doCreateSign) #self.actionCreateMTR.triggered.connect(self.doCreateMTR) self.actionMoveFeatureToDifferentLayer.triggered.connect(self.doMoveFeatureToDifferentLayer) self.actionCreateRestriction.setEnabled(False) self.actionAddGPSLocation.setEnabled(False) self.actionRestrictionDetails.setEnabled(False) #self.actionRemoveRestriction.setEnabled(False) self.actionCreateSign.setEnabled(False) #self.actionCreateMTR.setEnabled(False) self.actionMoveFeatureToDifferentLayer.setEnabled(False) self.searchBar = searchBar(self.iface, self.featuresWithGPSToolbar) self.searchBar.disableSearchBar() self.mapTool = None self.currGnssAction = None self.gpsConnection = None self.createMapToolDict = {} def enableFeaturesWithGPSToolbarItems(self): TOMsMessageLog.logMessage("In enablefeaturesWithGPSToolbarItems", level=Qgis.Warning) self.gpsAvailable = False self.closeTOMs = False self.tableNames = TOMsLayers(self.iface) self.params = gpsParams() self.tableNames.TOMsLayersNotFound.connect(self.setCloseTOMsFlag) #self.tableNames.gpsLayersNotFound.connect(self.setCloseCaptureGPSFeaturesFlag) self.params.TOMsParamsNotFound.connect(self.setCloseCaptureGPSFeaturesFlag) self.TOMsConfigFileObject = TOMsConfigFile() self.TOMsConfigFileObject.TOMsConfigFileNotFound.connect(self.setCloseTOMsFlag) self.TOMsConfigFileObject.initialiseTOMsConfigFile() self.tableNames.getLayers(self.TOMsConfigFileObject) self.prj = QgsProject().instance() self.dest_crs = self.prj.crs() TOMsMessageLog.logMessage("In captureGPSFeatures::init project CRS is " + self.dest_crs.description(), level=Qgis.Warning) self.transformation = QgsCoordinateTransform(QgsCoordinateReferenceSystem("EPSG:4326"), self.dest_crs, self.prj) self.params.getParams() if self.closeTOMs: QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Unable to start editing tool ...")) #self.actionProposalsPanel.setChecked(False) return # TODO: allow function to continue without GPS enabled ... # Now check to see if the port is set. If not assume that just normal tools gpsPort = self.params.setParam("gpsPort") TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems: GPS port is: {}".format(gpsPort), level=Qgis.Warning) self.gpsConnection = None if gpsPort: self.gpsAvailable = True if self.gpsAvailable == True: self.curr_gps_location = None self.curr_gps_info = None TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems - GPS port is specified ", level=Qgis.Info) self.gps_thread = GPS_Thread(self.dest_crs, gpsPort) thread = QThread() self.gps_thread.moveToThread(thread) self.gps_thread.gpsActivated.connect(self.gpsStarted) self.gps_thread.gpsPosition.connect(self.gpsPositionProvided) self.gps_thread.gpsDeactivated.connect(functools.partial(self.gpsStopped)) self.gps_thread.gpsError.connect(self.gpsErrorEncountered) #self.gps_thread.progress.connect(progressBar.setValue) thread.started.connect(self.gps_thread.startGPS) #thread.finished.connect(functools.partial(self.gpsStopped, thread)) thread.start() self.thread = thread TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems - attempting connection ", level=Qgis.Info) time.sleep(1.0) try: self.roamDistance = float(self.params.setParam("roamDistance")) except Exception as e: TOMsMessageLog.logMessage("In enableFeaturesWithGPSToolbarItems:init: roamDistance issue: {}".format(e), level=Qgis.Warning) self.roamDistance = 5.0 self.enableToolbarItems() self.createMapToolDict = {} def enableToolbarItems(self): TOMsMessageLog.logMessage("In enableToolbarItems", level=Qgis.Warning) self.actionCreateRestriction.setEnabled(True) self.actionRestrictionDetails.setEnabled(True) #self.actionRemoveRestriction.setEnabled(True) #self.actionCreateSign.setEnabled(True) #self.actionCreateMTR.setEnabled(True) self.actionMoveFeatureToDifferentLayer.setEnabled(True) self.searchBar.enableSearchBar() self.currMapTool = None self.theCurrentMapTool = None self.iface.currentLayerChanged.connect(self.changeCurrLayer2) self.canvas.mapToolSet.connect(self.changeMapTool2) self.canvas.extentsChanged.connect(self.changeExtents) # transaction for move ... self.localTransaction = MoveLayerTransaction(self.iface) def enableGnssToolbarItem(self): if self.gpsConnection: self.actionAddGPSLocation.setEnabled(True) self.actionCreateSign.setEnabled(True) self.lastCentre = QgsPointXY(0,0) def disableGnssToolbarItem(self): self.actionAddGPSLocation.setEnabled(False) self.actionCreateSign.setEnabled(False) def disableToolbarItems(self): self.actionCreateRestriction.setEnabled(False) self.actionRestrictionDetails.setEnabled(False) self.actionRemoveRestriction.setEnabled(False) self.actionCreateSign.setEnabled(False) #self.actionCreateMTR.setEnabled(False) self.actionMoveFeatureToDifferentLayer.setEnabled(False) self.searchBar.disableSearchBar() """if self.gpsConnection: self.actionAddGPSLocation.setEnabled(False)""" def setCloseTOMsFlag(self): self.closeTOMs = True QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Now closing TOMs ...")) def disableFeaturesWithGPSToolbarItems(self): TOMsMessageLog.logMessage("In disablefeaturesWithGPSToolbarItems", level=Qgis.Warning) if self.gpsConnection and not self.closeTOMs: self.gps_thread.endGPS() self.disableToolbarItems() # TODO: Need to delete any tools ... for layer, mapTool in self.createMapToolDict.items (): try: status = layer.rollBack() except Exception as e: None """reply = QMessageBox.information(None, "Information", "Problem rolling back changes" + str(self.currLayer.commitErrors()), QMessageBox.Ok)""" del mapTool self.createMapToolDict = {} try: self.iface.currentLayerChanged.disconnect(self.changeCurrLayer2) except Exception as e: TOMsMessageLog.logMessage( "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for currentLayerChanged {}".format(e), level=Qgis.Warning) try: self.canvas.mapToolSet.disconnect(self.changeMapTool2) except Exception as e: TOMsMessageLog.logMessage( "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for mapToolSet {}".format( e), level=Qgis.Warning) try: self.canvas.extentsChanged.disconnect(self.changeExtents) except Exception as e: TOMsMessageLog.logMessage( "In disableFeaturesWithGPSToolbarItems. Issue with disconnects for extentsChanged {}".format( e), level=Qgis.Warning) self.tableNames.removePathFromLayerForms() def setCloseCaptureGPSFeaturesFlag(self): self.closeCaptureGPSFeatures = True self.gpsAvailable = True def onGroupTriggered(self, action): # hold the current action self.currGnssAction = action TOMsMessageLog.logMessage("In onGroupTriggered: curr action is {}".format(action.text()), level=Qgis.Info) """ Using signals for ChangeTool and ChangeLayer to manage the tools - with the following functions """ def isGnssTool(self, mapTool): if (isinstance(mapTool, CreateRestrictionTool) or isinstance(mapTool, GeometryInfoMapTool) or isinstance(mapTool, RemoveRestrictionTool)): return True return False def changeMapTool2(self): TOMsMessageLog.logMessage( "In changeMapTool2 ...", level=Qgis.Info) currMapTool = self.iface.mapCanvas().mapTool() if not self.isGnssTool(currMapTool): TOMsMessageLog.logMessage( "In changeMapTool2. Unchecking action ...", level=Qgis.Info) if self.currGnssAction: self.currGnssAction.setChecked(False) else: TOMsMessageLog.logMessage( "In changeMapTool2. No action for gnssTools.", level=Qgis.Info) TOMsMessageLog.logMessage( "In changeMapTool2. finished.", level=Qgis.Info) #print('tool unset') def changeCurrLayer2(self): TOMsMessageLog.logMessage("In changeLayer2 ... ", level=Qgis.Info) try: currMapTool = self.iface.mapCanvas().mapTool() self.currGnssAction.setChecked(False) except Exception as e: None """if self.isGnssTool(currMapTool): TOMsMessageLog.logMessage("In changeLayer2. Action triggered ... ", level=Qgis.Info) self.currGnssAction.trigger() # assumption is that there is an action associated with the tool else: TOMsMessageLog.logMessage( "In changeLayer2. No action for currentMapTool.", level=Qgis.Info)""" TOMsMessageLog.logMessage( "In changeLayer2. finished.", level=Qgis.Info) print('layer changed') def doCreateRestriction(self): TOMsMessageLog.logMessage("In doCreateRestriction", level=Qgis.Info) self.currLayer = self.iface.activeLayer() if not self.currLayer: reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...", QMessageBox.Ok) return # TODO: Check that this is a restriction layer if self.actionCreateRestriction.isChecked(): TOMsMessageLog.logMessage("In doCreateRestriction - tool activated", level=Qgis.Info) TOMsMessageLog.logMessage( "In doCreateRestriction: current map tool {}".format(type(self.iface.mapCanvas().mapTool()).__name__), level=Qgis.Info) self.createRestrictionMapTool = self.createMapToolDict.get(self.currLayer) if not self.createRestrictionMapTool: TOMsMessageLog.logMessage("In doCreateRestriction. creating new map tool", level=Qgis.Info) self.createRestrictionMapTool = CreateRestrictionTool(self.iface, self.currLayer) self.createMapToolDict[self.currLayer] = self.createRestrictionMapTool TOMsMessageLog.logMessage("In doCreateRestriction. Here 1", level=Qgis.Info) self.iface.mapCanvas().setMapTool(self.createRestrictionMapTool) TOMsMessageLog.logMessage("In doCreateRestriction. Here 2", level=Qgis.Info) if not self.createRestrictionMapTool.isCapturing(): if self.currLayer.isEditable() == True: if self.currLayer.commitChanges() == False: reply = QMessageBox.information(None, "Information", "Problem committing changes" + str(self.currLayer.commitErrors()), QMessageBox.Ok) else: TOMsMessageLog.logMessage("In doCreateRestriction: changes committed", level=Qgis.Info) if self.currLayer.readOnly() == True: TOMsMessageLog.logMessage("In doCreateRestriction - Not able to start transaction ...", level=Qgis.Info) else: if self.currLayer.startEditing() == False: reply = QMessageBox.information(None, "Information", "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok) return TOMsMessageLog.logMessage("In doCreateRestriction. Here 3", level=Qgis.Info) else: TOMsMessageLog.logMessage("In doCreateRestriction - tool deactivated", level=Qgis.Info) if self.createRestrictionMapTool: self.iface.mapCanvas().unsetMapTool(self.createRestrictionMapTool) self.currMapTool = None self.currentlySelectedLayer = None self.actionCreateRestriction.setChecked(False) # TODO: stop editting on layers?? TOMsMessageLog.logMessage("In doCreateRestriction. Here 4", level=Qgis.Info) # -- end of tools for signals def changeExtents(self): TOMsMessageLog.logMessage("In changeExtents ... ", level=Qgis.Info) def doAddGPSLocation(self): # need to have a addPointFromGPS function within each tool TOMsMessageLog.logMessage("In doAddGPSLocation", level=Qgis.Info) if self.gpsConnection: if self.curr_gps_location: try: status = self.createRestrictionMapTool.addPointFromGPS(self.curr_gps_location, self.curr_gps_info) except Exception as e: TOMsMessageLog.logMessage("In doAddGPSLocation: Problem adding gnss location: {}".format(e), level=Qgis.Warning) reply = QMessageBox.information(self.iface.mainWindow(), "Error", "Problem adding gnss location ... ", QMessageBox.Ok) else: reply = QMessageBox.information(self.iface.mainWindow(), "Information", "No position found ...", QMessageBox.Ok) else: reply = QMessageBox.information(self.iface.mainWindow(), "Information", "You need to activate the tool first ...", QMessageBox.Ok) def doRestrictionDetails(self): """ Select point and then display details. Assume that there is only one of these map tools in existence at any one time ?? """ TOMsMessageLog.logMessage("In doRestrictionDetails", level=Qgis.Info) # TODO: Check whether or not there is a create maptool available. If so, stop this and finish using that/those tools if not self.iface.activeLayer(): reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...", QMessageBox.Ok) return if self.actionRestrictionDetails.isChecked(): TOMsMessageLog.logMessage("In doRestrictionDetails - tool activated", level=Qgis.Warning) self.showRestrictionMapTool = GeometryInfoMapTool(self.iface) self.iface.mapCanvas().setMapTool(self.showRestrictionMapTool) self.showRestrictionMapTool.notifyFeatureFound.connect(self.showRestrictionDetails) else: TOMsMessageLog.logMessage("In doRestrictionDetails - tool deactivated", level=Qgis.Warning) if self.showRestrictionMapTool: self.iface.mapCanvas().unsetMapTool(self.showRestrictionMapTool) self.actionRestrictionDetails.setChecked(False) #@pyqtSlot(str) def showRestrictionDetails(self, closestLayer, closestFeature): TOMsMessageLog.logMessage( "In showRestrictionDetails ... Layer: " + str(closestLayer.name()), level=Qgis.Info) self.showRestrictionMapTool.notifyFeatureFound.disconnect(self.showRestrictionDetails) # TODO: could improve ... basically check to see if transaction in progress ... if closestLayer.isEditable() == True: reply = QMessageBox.question(None, "Information", "There is a transaction in progress on this layer. This action will rollback back any changes. Do you want to continue?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.No: return if closestLayer.commitChanges() == False: reply = QMessageBox.information(None, "Information", "Problem committing changes" + str(closestLayer.commitErrors()), QMessageBox.Ok) else: TOMsMessageLog.logMessage("In showRestrictionDetails: changes committed", level=Qgis.Info) """if self.iface.activeLayer().readOnly() == True: TOMsMessageLog.logMessage("In showSignDetails - Not able to start transaction ...", level=Qgis.Info) else: if self.iface.activeLayer().startEditing() == False: reply = QMessageBox.information(None, "Information", "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok) return""" self.dialog = self.iface.getFeatureForm(closestLayer, closestFeature) #self.TOMsUtils.setupRestrictionDialog(self.dialog, closestLayer, closestFeature) self.setupFieldRestrictionDialog(self.dialog, closestLayer, closestFeature) self.dialog.show() """ Decided that it is best to use the QGIS select/delete tools to manage removals. So these functions are not used """ def doRemoveRestriction(self): TOMsMessageLog.logMessage("In doRemoveRestriction", level=Qgis.Info) self.currLayer = self.iface.activeLayer() if not self.currLayer: reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...", QMessageBox.Ok) return if self.currLayer.readOnly() == True: """reply = QMessageBox.information(None, "Information", "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok)""" TOMsMessageLog.logMessage("In doRemoveRestriction - Not able to start transaction ...", level=Qgis.Info) self.actionRemoveRestriction.setChecked(False) return if self.actionRemoveRestriction.isChecked(): TOMsMessageLog.logMessage("In doRemoveRestriction - tool activated", level=Qgis.Warning) """self.mapTool = self.deleteMapToolDict.get(self.currLayer) if not self.mapTool: self.mapTool = RemoveRestrictionTool(self.iface) self.deleteMapToolDict[self.currLayer] = self.mapTool""" self.mapTool = RemoveRestrictionTool(self.iface) #self.removeRestrictionMapTool.setAction(self.actionRemoveRestriction) self.iface.mapCanvas().setMapTool(self.removeRestrictionMapTool) #self.gpsMapTool = True #self.removeRestrictionMapTool.deactivated.connect(functools.partial(self.deactivateAction, self.actionRemoveRestriction)) #self.iface.currentLayerChanged.connect(self.changeCurrLayer) #self.canvas.mapToolSet.connect(self.changeMapTool) self.removeRestrictionMapTool.notifyFeatureFound.connect(self.removeRestriction) else: TOMsMessageLog.logMessage("In doRemoveRestriction - tool deactivated", level=Qgis.Warning) self.removeRestrictionMapTool.notifyFeatureFound.disconnect(self.removeRestriction) #self.canvas.mapToolSet.disconnect(self.changeMapTool) #self.iface.currentLayerChanged.disconnect(self.changeCurrLayer) self.iface.mapCanvas().unsetMapTool(self.removeRestrictionMapTool) #self.removeRestrictionMapTool.deactivate() #self.mapTool = None self.actionRemoveRestriction.setChecked(False) #@pyqtSlot(str) def removeRestriction(self, closestLayer, closestFeature): TOMsMessageLog.logMessage( "In removeRestriction ... Layer: " + str(closestLayer.name()), level=Qgis.Info) if closestLayer.isEditable() == True: if closestLayer.commitChanges() == False: reply = QMessageBox.information(None, "Information", "Problem committing changes" + str(closestLayer.commitErrors()), QMessageBox.Ok) else: TOMsMessageLog.logMessage("In removeRestriction: changes committed", level=Qgis.Info) if self.currLayer.startEditing() == False: reply = QMessageBox.information(None, "Information", "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok) return # TODO: Sort out this for UPDATE # self.setDefaultRestrictionDetails(closestFeature, closestLayer) closestLayer.deleteFeature(closestFeature.id()) if closestLayer.commitChanges() == False: reply = QMessageBox.information(None, "Information", "Problem committing changes" + str(closestLayer.commitErrors()), QMessageBox.Ok) else: TOMsMessageLog.logMessage("In removeRestriction: changes committed", level=Qgis.Info) """ This is a tool for adding a point feature. currently only used for signs, but could be used for any point """ def doCreateSign(self): TOMsMessageLog.logMessage("In doCreateSign", level=Qgis.Info) if self.actionCreateSign.isChecked(): self.currMapTool = self.canvas.mapTool() self.currentlySelectedLayer = self.iface.activeLayer() self.signsLayer = self.tableNames.setLayer("Signs") self.iface.setActiveLayer(self.signsLayer) self.createPointMapTool = CreatePointTool(self.iface, self.signsLayer) TOMsMessageLog.logMessage("In doCreateSign - tool activated", level=Qgis.Info) self.signsLayer.editingStopped.connect(self.reinstateMapTool) self.actionCreateSign.setChecked(False) self.iface.mapCanvas().setMapTool(self.createPointMapTool) """ add the point from the gnss """ try: status = self.canvas.mapTool().addPointFromGPS(self.curr_gps_location, self.curr_gps_info) except Exception as e: TOMsMessageLog.logMessage("In doCreateSign: Problem adding gnss location: {}".format(e), level=Qgis.Warning) reply = QMessageBox.information(self.iface.mainWindow(), "Error", "Problem adding gnss location ... ", QMessageBox.Ok) """ Not currently used, but want to develop ... """ def doCreateMTR(self): TOMsMessageLog.logMessage("In doCreateMTR", level=Qgis.Info) if self.actionCreateMTR.isChecked(): TOMsMessageLog.logMessage("In doCreateMTR - tool activated", level=Qgis.Info) # Open MTR form ... try: self.thisMtrForm except AttributeError: self.thisMtrForm = mtrForm(self.iface) #res = mtrFormFactory.prepareForm(self.iface, self.dbConn, self.dialog) #self.mtrTypeCB = self.dialog.findChild(QComboBox, "cmb_MTR_list") #self.mtrTypeCB.activated[str].connect(self.onLocalChanged) #self.currDialog.findChild(QComboBox, "cmb_MTR_list").activated[str].connect(self.onChanged) """ Need to setup dialog: a. create drop down b. link structure of form to different options from drop down, e.g., Access Restriction needs ?? attributes and one point, Turn Restriction needs ?? attributes and two points c. link getPoint actions to buttons """ status = self.thisMtrForm.show() # Run the dialog event loop result = self.thisMtrForm.exec_() # else: TOMsMessageLog.logMessage("In doCreateMTR - tool deactivated", level=Qgis.Info) #self.iface.mapCanvas().unsetMapTool(self.mapTool) #self.mapTool = None self.actionCreateMTR.setChecked(False) self.gpsMapTool = False def onLocalChanged(self, text): TOMsMessageLog.logMessage( "In generateFirstStageForm::selectionchange. " + text, level=Qgis.Info) res = mtrFormFactory.prepareForm(self.iface, self.dbConn, self.dialog, text) """ Used with the createSign tool to reinstate the last used maptool, i.e., to allow the interupt of feature creation """ def reinstateMapTool(self): TOMsMessageLog.logMessage("In reinstateMapTool ... ", level=Qgis.Info) self.iface.activeLayer().editingStopped.disconnect(self.reinstateMapTool) if self.currMapTool: TOMsMessageLog.logMessage( "In reinstateMapTool. layer to be reinstated {} using tool {}".format(self.currentlySelectedLayer.name(), self.currMapTool.toolName()), level=Qgis.Warning) # now reinstate if self.currentlySelectedLayer: self.iface.setActiveLayer(self.currentlySelectedLayer) self.iface.mapCanvas().setMapTool(self.currMapTool) def doMoveFeatureToDifferentLayer(self): """ Select point and then display details. Assume that there is only one of these map tools in existence at any one time ?? """ TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer", level=Qgis.Info) # TODO: Check whether or not there is a create maptool available. If so, stop this and finish using that/those tools if not self.iface.activeLayer(): reply = QMessageBox.information(self.iface.mainWindow(), "Information", "Please choose a layer ...", QMessageBox.Ok) return if self.actionMoveFeatureToDifferentLayer.isChecked(): TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer - tool activated", level=Qgis.Warning) self.moveFeatureToDifferentLayerMapTool = ChangeLayerMapTool(self.iface, self.localTransaction) self.iface.mapCanvas().setMapTool(self.moveFeatureToDifferentLayerMapTool) #self.showRestrictionMapTool.notifyFeatureFound.connect(self.showRestrictionDetails) else: TOMsMessageLog.logMessage("In doMoveFeatureToDifferentLayer - tool deactivated", level=Qgis.Warning) if self.moveFeatureToDifferentLayerMapTool: self.iface.mapCanvas().unsetMapTool(self.moveFeatureToDifferentLayerMapTool) self.actionMoveFeatureToDifferentLayer.setChecked(False) #@pyqtSlot(QgsGpsConnection) def gpsStarted(self, connection): TOMsMessageLog.logMessage("In enableTools - GPS connection found ", level=Qgis.Info) self.gpsConnection = connection # marker self.marker = QgsVertexMarker(self.canvas) self.marker.setColor(QColor(255, 0, 0)) # (R,G,B) self.marker.setIconSize(10) self.marker.setIconType(QgsVertexMarker.ICON_CIRCLE) self.marker.setPenWidth(3) self.enableGnssToolbarItem() reply = QMessageBox.information(None, "Information", "Connection found", QMessageBox.Ok) #@pyqtSlot() def gpsStopped(self): TOMsMessageLog.logMessage("In enableTools - GPS connection stopped ", level=Qgis.Warning) self.gps_thread.deleteLater() self.thread.quit() self.thread.wait() self.thread.deleteLater() if self.gpsConnection: if self.canvas is not None: self.marker.hide() self.canvas.scene().removeItem(self.marker) self.gpsConnection = None self.disableGnssToolbarItem() #@pyqtSlot() def gpsPositionProvided(self, mapPointXY, gpsInfo): """reply = QMessageBox.information(None, "Information", "Position provided", QMessageBox.Ok)""" TOMsMessageLog.logMessage("In enableTools - ******** initial GPS location provided " + mapPointXY.asWkt(), level=Qgis.Info) self.curr_gps_location = mapPointXY self.curr_gps_info = gpsInfo wgs84_pointXY = QgsPointXY(gpsInfo.longitude, gpsInfo.latitude) wgs84_point = QgsPoint(wgs84_pointXY) wgs84_point.transform(self.transformation) x = wgs84_point.x() y = wgs84_point.y() new_mapPointXY = QgsPointXY(x, y) TOMsMessageLog.logMessage("In enableTools - ******** transformed GPS location provided " + str(gpsInfo.longitude) + ":" + str(gpsInfo.latitude) + "; " + new_mapPointXY.asWkt(), level=Qgis.Info) if gpsInfo.pdop >= 1: # gps ok self.marker.setColor(QColor(0, 200, 0)) else: self.marker.setColor(QColor(255, 0, 0)) self.marker.setCenter(mapPointXY) self.marker.show() #self.canvas.setCenter(mapPointXY) """TOMsMessageLog.logMessage("In enableTools: distance from last fix: {}".format(self.lastCentre.distance(mapPointXY)), level=Qgis.Info)""" if self.lastCentre.distance(mapPointXY) > self.roamDistance: self.lastCentre = mapPointXY self.canvas.setCenter(mapPointXY) TOMsMessageLog.logMessage( "In enableTools: distance from last fix: {}".format(self.lastCentre.distance(mapPointXY)), level=Qgis.Warning) self.canvas.refresh() # TODO: populate message bar with details about satellites, etc #@pyqtSlot(Exception, str) def gpsErrorEncountered(self, e): TOMsMessageLog.logMessage("In enableTools - GPS connection has error {}".format(e), level=Qgis.Warning) """self.actionCreateRestriction.setEnabled(False) self.actionAddGPSLocation.setEnabled(False)""" self.disableGnssToolbarItem()
class MultiObjectEditSample(QgsMapTool): def selectedFeature(self, feature): self.maptool.setFeature(feature) def start(self): self.maptool = MultiObjectEditClass(self.iface, self.canvas, 'move') # 移動の場合 self.maptool.setLayer(self.iface.activeLayer()) self.maptool.featureIdentified.connect(self.selectedFeature) self.canvas.setMapTool(self.maptool) self.canvas.mapToolSet.connect(self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'マルチオブジェクト編集サンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所(このサンプルの場合、メニューの「プラグイン/雛形/ダイアログ無し雛形」) self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, MultiObjectEditSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__)+'/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect(self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable(self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class GraphSample(QgsMapTool): # lineLLを垂直に横断する点列を作成する def addOdansen(self, lineLL, key): def angle(a, b): return math.atan2(b.y() - a.y(), b.x() - a.x()) # startからrad方向にn進んだ位置を返す def destination(start, rad, n): return QgsPointXY(n * math.cos(rad) + start.x(), n * math.sin(rad) + start.y()) def transformCRS(obj, src, dst): newobj = QgsGeometry(obj) srcCrs = QgsCoordinateReferenceSystem(src) dstCrs = QgsCoordinateReferenceSystem(dst) tr = QgsCoordinateTransform(srcCrs, dstCrs, QgsProject.instance()) newobj.transform(tr) return newobj # startpnt、endpntが成す線分の、startpntからlength分進んだ位置を中心に、線分を横断する線を作成する。 # cntは番号付けのために使っている。 def odansen(startpnt, endpnt, length, cnt): center = destination(startpnt, angle(startpnt, endpnt), length) rad = angle(startpnt, endpnt) + (-90 * math.pi / 180) for i in range(-self._odanlinelength, self._odanlinelength + self._odanpointspan, self._odanpointspan): xypnt = QgsGeometry().fromPointXY(destination(center, rad, i)) llpnt = transformCRS(xypnt, self._xycrs, self._llcrs) elev = self.gr.getValueInterpolation(llpnt.asPoint()) self.addFeature(self.hol, llpnt, [key, cnt, i, elev]) lineXY = transformCRS(lineLL, self._llcrs, self._xycrs) # 描画したラインは緯度経度の座標なので、平面直角座標に変換する judanLen = lineXY.length() pnts = [pnt for pnt in lineXY.asPolyline()] # 縦断線の始点を横断する線 odansen(pnts[0], pnts[1], 0, 0) cnt = 1 nextpos = self._odanlinespan * cnt while judanLen > nextpos: for i in range(1, len(pnts)): nodelength = pnts[i-1].distance(pnts[i]) # この線分上に横断線引ける? # 引けない if (nextpos - nodelength) > 0: nextpos -= nodelength # 引ける else: odansen(pnts[i - 1], pnts[i], nextpos, cnt) cnt += 1 nextpos = self._odanlinespan * cnt break # 縦断線の終点を横断する線 odansen(pnts[-2], pnts[-1], pnts[-1].distance(pnts[-2]), cnt) def setFeature(self, geom): def getNumber(feature): return feature['pointcount'] key = datetime.datetime.now().strftime('%Y%m%d%H%M%S') # 縦断線と横断線を紐付けるキー self.addFeature(self.ver, geom, [key]) # 縦断線レイヤに、描画したラインを追加 self.addOdansen(geom, key) # 描画したラインを横断する点列を横断戦レイヤに追加 # グラフ作成 features = list(self.hol.getFeatures(QgsFeatureRequest().setFilterExpression('"key"='+'\'' + key + '\''))) linenumbers = sorted(set([f['linecount'] for f in features])) for linenumber in linenumbers: linenode = sorted([f for f in features if f['linecount'] == linenumber], key=getNumber) # 'pointcount'の値順に並び変える fig, ax = plt.subplots() y = np.array([l['elev'] for l in linenode]) x = np.array([l['pointcount'] for l in linenode]) ax.set_title(str(linenode[0]['key']) + '_' + str(linenumber)) ax.plot(x, y, '-') plt.savefig(self._savedir + str(linenode[0]['key']) + '_' + str(linenumber) + '.png') # 一時レイヤ作成 def createTemporaryLayer(self, layername, type, fieldsstr): epsg = self.iface.mapCanvas().mapSettings().destinationCrs().authid() layer = QgsVectorLayer(type + '?&crs='+epsg+fieldsstr, layername, 'memory') QgsProject.instance().addMapLayer(layer) return layer # レイヤにレコード追加 def addFeature(self, layer, geometry, attrs): qf = QgsFields() for field in layer.fields(): qf.append(QgsField(str(field.name()), typeName=field.typeName())) record = QgsFeature(qf) # 地物をセットする record.setGeometry(geometry) # 属性をセットする record.setAttributes(attrs) # 作成したレコードをレイヤに追加 layer.dataProvider().addFeatures([record]) layer.updateExtents() # これが無いと『レイヤの領域にズーム』した時に、レイヤの最初のオブジェクト部分しかズームされない self.canvas.refreshAllLayers() def start(self): # このプログラム使うときはこの辺を調整してください self._llcrs = 4326 self._xycrs = 2451 # 千葉県のDEMでテストしたので9系になってます。 self._savedir = 'c:\\users\\〇〇\\desktop\\pic\\' # 横断図の保存先 self._odanlinespan = 100 # 横断線の間隔 self._odanlinelength = 200 # 横断線の片側の長さ self._odanpointspan = 10 # 横断線上のサンプリング間隔 layer = self.iface.activeLayer() if type(layer) != qgis.core.QgsRasterLayer: QMessageBox.about(None, 'エラー', 'ラスタレイヤを選択してから実行してください。') self.action.setChecked(False) self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す return self.gr = GetRasterPixelValue(layer) maptool = RubberBand(self.iface, self.canvas, QgsWkbTypes.LineGeometry) maptool.getObject.connect(self.setFeature) if len(QgsProject.instance().mapLayersByName('縦断線')) == 0: self.ver = self.createTemporaryLayer('縦断線', 'LineString', '&field=key:string') else: self.ver = QgsProject.instance().mapLayersByName('縦断線')[0] if len(QgsProject.instance().mapLayersByName('横断線')) == 0: self.hol = self.createTemporaryLayer('横断線', 'Point', '&field=key:string&field=linecount:integer&field=pointcount:integer&field=elev:double') else: self.hol = QgsProject.instance().mapLayersByName('横断線')[0] self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect(self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 def finish(self): self.ver = None self.hol = None self.gr = None self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'グラフサンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所(このサンプルの場合、メニューの「プラグイン/雛形/ダイアログ無し雛形」) self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, GraphSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__)+'/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect(self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable(self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class featuresWithGPS: """QGIS Plugin Implementation.""" def __init__(self, iface): QgsMessageLog.logMessage("Starting featuresWithGPS ... ", tag="TOMs panel") """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__) self.actions = [] # ?? check - assume it initialises array of actions self.closeGPSToolsFlag = False # Set up log file and collect any relevant messages logFilePath = os.environ.get('QGIS_LOGFILE_PATH') if logFilePath: QgsMessageLog.logMessage("LogFilePath: " + str(logFilePath), tag="TOMs panel") logfile = 'qgis_' + datetime.date.today().strftime( "%Y%m%d") + '.log' self.filename = os.path.join(logFilePath, logfile) QgsMessageLog.logMessage("Sorting out log file" + self.filename, tag="TOMs panel") QgsApplication.instance().messageLog().messageReceived.connect( self.write_log_message) # Set up local logging #loggingUtils = TOMsMessageLog() #loggingUtils.setLogFile() QgsMessageLog.logMessage("Finished init", tag="TOMs panel") #self.toolbar = self.iface.addToolBar(u'Test5Class') #self.toolbar.setObjectName(u'Test5Class') def write_log_message(self, message, tag, level): #filename = os.path.join('C:\Users\Tim\Documents\MHTC', 'qgis.log') with open(self.filename, 'a') as logfile: logfile.write('{dateDetails}:: {message}\n'.format( dateDetails=time.strftime("%Y%m%d:%H%M%S"), message=message)) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" QgsMessageLog.logMessage("Registering expression functions ... ", tag="TOMs panel") #self.hideMenusToolbars() # set up menu. Is there a generic way to do this? from an xml file? QgsMessageLog.logMessage("Adding toolbar", tag="TOMs panel") # Add toolbar self.featuresWithGPSToolbar = self.iface.addToolBar( "featuresWithGPS Toolbar") self.featuresWithGPSToolbar.setObjectName( "featuresWithGPSToolbar Toolbar") self.actionGPSToolbar = QAction( QIcon(":/plugins/featureswithgps/resources/GPS.png"), QCoreApplication.translate("MyPlugin", "Start GPS Tools"), self.iface.mainWindow()) self.actionGPSToolbar.setCheckable(True) self.featuresWithGPSToolbar.addAction(self.actionGPSToolbar) self.actionGPSToolbar.triggered.connect(self.onInitGPSTools) #self.currGPSManager = gpsManager(self.iface) #self.tableNames = self.gpsManager.tableNames # Now set up the toolbar self.gpsTools = captureGPSFeatures(self.iface, self.featuresWithGPSToolbar) #self.gpsTools.disableFeaturesWithGPSToolbarItems() def onInitGPSTools(self): QgsMessageLog.logMessage("In onInitGPSTools", tag="TOMs panel") if self.actionGPSToolbar.isChecked(): QgsMessageLog.logMessage("In onInitGPSTools. Activating ...", tag="TOMs panel") self.openGPSTools() else: QgsMessageLog.logMessage("In onInitGPSTools. Deactivating ...", tag="TOMs panel") self.closeGPSTools() def openGPSTools(self): # actions when the Proposals Panel is closed or the toolbar "start" is toggled QgsMessageLog.logMessage("In openGPSTools. Activating ...", tag="TOMs panel") if self.closeGPSToolsFlag: QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Unable to start GPSTools ...")) self.actionGPSToolbar.setChecked(False) return self.gpsTools.enableFeaturesWithGPSToolbarItems() # TODO: connect close project signal to closeGPSTools def setCloseGPSToolsFlag(self): self.closeGPSToolsFlag = True def closeGPSTools(self): # actions when the Proposals Panel is closed or the toolbar "start" is toggled QgsMessageLog.logMessage("In closeGPSTools. Deactivating ...", tag="TOMs panel") # TODO: Delete any objects that are no longer needed #self.proposalTransaction.rollBackTransactionGroup() #del self.proposalTransaction # There is another call to this function from the dock.close() # Now disable the items from the Toolbar self.gpsTools.disableFeaturesWithGPSToolbarItems() def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" # remove the toolbar QgsMessageLog.logMessage("Clearing toolbar ... ", tag="TOMs panel") self.featuresWithGPSToolbar.clear() QgsMessageLog.logMessage("Deleting toolbar ... ", tag="TOMs panel") del self.featuresWithGPSToolbar #self.restoreMenusToolbars() QgsMessageLog.logMessage("Unload comnpleted ... ", tag="TOMs panel")
class RubberbandSample(QgsMapTool): def printGeometry(self, geom): print(geom) def start(self): maptool = RubberBandClass(self.iface, self.canvas, self.objtype) maptool.getObject.connect(self.printGeometry) self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect( self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.objtype = QgsWkbTypes.LineGeometry # QgsWkbTypes.PointGeometry, QgsWkbTypes.LineGeometry, QgsWkbTypes.PolygonGeometry self.plugin_name = 'ラバーバンドサンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, RubberbandSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class MainPlugin(object): def __init__(self, iface): self.name = "groupLayers" self.iface = iface self.project = QgsProject.instance() self.treeBeforeSave = None def initGui(self): self.action = QAction( QIcon(os.path.dirname(os.path.realpath(__file__)) + "/icon.png"), u"Group Layers by similar type (keep visibility)", self.iface.mainWindow() ) self.action.setObjectName("groupAction") self.action.setWhatsThis("Group/ungroup layers by type") self.action.setStatusTip("Group/ungroup layers by type") self.action.setCheckable(True) self.action.triggered.connect(self.run) self.resetAction = QAction("Group and make all layers visible") self.resetAction.triggered.connect(self.run_reset_visibility) # the icon pressed status could be used, but it is already # changed when run method is called, so this is ambiguous # therefore a dedicated boolean status is used self.grouped = False self.groupAdditionalTypes = False self.defSelection = groupHierarchies.keys().__iter__().__next__() self.hierarchyDefinition = groupHierarchies[self.defSelection] # add toolbar button and menu item layersDock = self.iface.mainWindow().findChild(QDockWidget, "Layers") self.layersToolBar = layersDock.widget().layout().itemAt(0).widget() assert isinstance(self.layersToolBar, QToolBar) self.layersToolBar.addAction(self.action) self.menuButton = [btn for btn in self.layersToolBar.children() if isinstance(btn, QToolButton) if self.action in btn.actions()][0] self.buttonMenu = QMenu() self.menuButton.setMenu(self.buttonMenu) self.menuButton.setPopupMode(QToolButton.MenuButtonPopup) self.buttonMenu.addAction(self.action) self.buttonMenu.addAction(self.resetAction) # self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Group Layers", self.action) self.defSelector = QAction( u"Select hierarchy definitions", self.iface.mainWindow() ) self.defSelector.setObjectName("defSelector") self.defSelector.triggered.connect(self.selectDefs) self.iface.addPluginToMenu("&Group Layers", self.defSelector) # connect hook to reset the plugin state # when a new or existing project is opened self.project.cleared.connect(self.reset_state) self.project.writeProject.connect(self.write) self.project.projectSaved.connect(self.saved) def unload(self): # remove the plugin menu item and icon self.iface.removePluginMenu("&Group Layers", self.action) self.iface.removePluginMenu("&Group Layers", self.defSelector) self.layersToolBar.removeAction(self.action) self.project.cleared.disconnect(self.reset_state) self.project.writeProject.disconnect(self.write) self.project.projectSaved.disconnect(self.saved) try: self.project.layerWasAdded.disconnect(self.add_layer_sync) except Exception: print('could not disconnect add_layer_sync in unload') try: self.project.layerRemoved.disconnect(self.remove_layer_sync) except Exception: print('could not disconnect remove_layer_sync in unload') # self.iface.removeToolBarIcon(self.action) def selectDefs(self): dialog = DefSelectDialog(self.defSelection, self.groupAdditionalTypes) if dialog.exec_(): self.defSelection = dialog.comboBox.currentText() self.hierarchyDefinition = groupHierarchies[self.defSelection] self.groupAdditionalTypes = dialog.checkBox.isChecked() def run(self, checked=False, reset=False): try: if self.grouped: try: self.project.layerWasAdded.disconnect(self.add_layer_sync) except Exception: print('could not disconnect add_layer_sync') try: self.project.layerRemoved.disconnect(self.remove_layer_sync) except Exception: print('could not disconnect remove_layer_sync') self.groupToTree(reset_initial_visibility=reset) self.resetAction.setText("Group and make all layers visible") else: self.treeToGroup(all_visible=reset) self.resetAction.setText("Ungroup and restore initial (ungrouped) visibility") self.project.layerWasAdded.connect(self.add_layer_sync) self.project.layerRemoved.connect(self.remove_layer_sync) except Exception as e: raise(e) finally: # synchronize plugin state with button state in case of exceptions self.grouped = checked def run_reset_visibility(self): self.action.toggle() self.run(checked=self.action.isChecked(), reset=True) def reset_state(self): self.action.setChecked(False) self.grouped = False def write(self): if self.grouped: answer = QMessageBox.question(self.iface.mainWindow(), "Save ungrouped state", "The layers are currently grouped by the " "groupLayers plugin\n\n" "Would you like to save the initial (ungrouped) state?\n" "(save current (grouped) layer tree if answer = NO)", QMessageBox.Yes|QMessageBox.No) if answer == QMessageBox.Yes: self.treeBeforeSave = self.iface.layerTreeCanvasBridge().rootGroup().clone() self.groupToTree(reset_initial_visibility=True) self.iface.messageBar().pushMessage( 'CAUTION: The layer tree has been saved in its original format, ' 'check options if you want to change this behavior.', Qgis.Info ) def saved(self): if self.treeBeforeSave is not None: tempOldTree = self.oldTree self.oldTree = self.treeBeforeSave self.groupToTree(reset_initial_visibility=True) self.oldTree = tempOldTree self.treeBeforeSave = None def add_layer_sync(self, addedLayer): self.oldTree.addLayer(addedLayer) def remove_layer_sync(self, removedLayerId): removedLayer = self.oldTree.findLayer(removedLayerId) self.recursiveRemoveFromGroup(self.oldTree, removedLayer) def recursiveRemoveFromGroup(self, group, layer): group.removeChildNode(layer) for subGroup in group.findGroups(): self.recursiveRemoveFromGroup(subGroup, layer) def initTreeRec(self, hierarchyDefinition, tree): for (k, v) in hierarchyDefinition.items(): if "groupCriteria" in v: tree[k] = {} self.initTreeRec(v["values"], tree[k]) else: tree[k] = [] def treeToGroup(self, all_visible=True): self.layerDict = {} self.treeRoot = self.project.layerTreeRoot() self.initTreeRec(self.hierarchyDefinition['values'], self.layerDict) layerTree = self.iface.layerTreeCanvasBridge().rootGroup() self.oldTree = layerTree.clone() self.parseTreeRec(layerTree) # into self.layerDict self.layerDict = self.cleanTree(self.layerDict) oldLen = len(layerTree.children()) self.layerDictToTree(self.layerDict, layerTree, all_visible) # caution: commented instruction below removes all layers !! # iface.layerTreeCanvasBridge().rootGroup().clear() layerTree.removeChildren(0, oldLen) def groupToTree(self, reset_initial_visibility=True): self.treeRoot = self.project.layerTreeRoot() layerTree = self.iface.layerTreeCanvasBridge().rootGroup() oldLen = len(layerTree.children()) self.insertInto(self.oldTree, layerTree, reset_initial_visibility) layerTree.removeChildren(0, oldLen) def layerDictToTree(self, layerDict, destinationGroup, all_visible): if isinstance(layerDict, dict): for (layerType, layers) in layerDict.items(): grp = destinationGroup.addGroup(layerType) self.layerDictToTree(layers, grp, all_visible) elif isinstance(layerDict, list): for l in layerDict: isVisible = self.treeRoot.findLayer(l).isVisible() node = destinationGroup.addLayer(l) if not all_visible: node.setItemVisibilityChecked(isVisible) else: raise Exception("Tree dictionary has been initialized incorrectly.") def insertInto(self, origin, destination, reset_initial_visibility): for el in origin.children(): if QgsLayerTree.isLayer(el): node = destination.addLayer(el.layer()) node.setItemVisibilityChecked( self.treeRoot.findLayer(el.layer()).isVisible() ) elif QgsLayerTree.isGroup(el): node = destination.addGroup(el.name()) self.insertInto(el, node, reset_initial_visibility) if reset_initial_visibility: # overwrite visibility with previously saved visibility node.setItemVisibilityChecked(el.itemVisibilityChecked()) def parseTreeRec(self, treeLeaf): for el in treeLeaf.children(): if QgsLayerTree.isLayer(el): l = el.layer() self.sortInto(l, self.layerDict, self.hierarchyDefinition) elif QgsLayerTree.isGroup(el): self.parseTreeRec(el) def sortInto(self, layer, destination, definitions): if "groupCriteria" in definitions: groupValue = layer.__getattribute__(definitions["groupCriteria"])() itemFound = False for (label, criteria) in definitions["values"].items(): if groupValue == criteria["value"]: itemFound = True self.sortInto(layer, destination[label], criteria) if not itemFound: if self.groupAdditionalTypes: groupName = "others" else: groupName = str(groupValue) try: destination[groupName].append(layer) except KeyError: destination[groupName] = [layer] else: destination.append(layer) def cleanTree(self, sourceTree): # remove all branches without end leaves if isinstance(sourceTree, dict): groupContents = {} for (layerType, layers) in sourceTree.items(): groupLayers = self.cleanTree(layers) if groupLayers: groupContents[layerType] = groupLayers return groupContents elif isinstance(sourceTree, list): return sourceTree else: raise Exception("Tree dictionary has been initialized incorrectly.")
class BoundingBoxSample(QgsMapTool): def start(self): # バウンディングボックス作成元 srclayer = self.iface.activeLayer() if (srclayer == None) or (type(srclayer) is not QgsVectorLayer): QMessageBox.about(None, '警告', 'ベクタレイヤを選択してから実行してください') self.action.setChecked(False) return # バウンディングボックス投入先 fieldstr = '' for field in srclayer.fields(): fieldstr = fieldstr + '&field=' + str(field.name()) + ':' + str( field.typeName()) crsstr = srclayer.sourceCrs().authid() dstlayer = QgsVectorLayer("Polygon?crs=" + crsstr + fieldstr, "サンプルレイヤ", "memory") for f in srclayer.getFeatures(): # 属性 qf = QgsFields() ## フィールド for field in srclayer.fields(): qf.append( QgsField(str(field.name()), typeName=field.typeName())) record = QgsFeature(qf) ## 値投入 for i in range(0, f.fields().count()): record[i] = f[i] # オブジェクト mpol = f.geometry().asMultiPolygon() bnds = [] for i in range(0, len(mpol)): bnds.append( QgsGeometry.fromRect(QgsGeometry().fromPolygonXY( mpol[i]).boundingBox()).asPolygon()) newobj = QgsGeometry.fromMultiPolygonXY(bnds) record.setGeometry(newobj) # レイヤに追加 dstlayer.dataProvider().addFeatures([record]) dstlayer.updateExtents() # キャンバスにオブジェクトを表示する QgsProject.instance().addMapLayers([dstlayer]) self.canvas.refreshAllLayers() def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'バウンディングボックス作成サンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = False # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, BoundingBoxSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class featuresWithGPS: """QGIS Plugin Implementation.""" def __init__(self, iface): QgsMessageLog.logMessage("Starting featuresWithGPS ... ", tag="TOMs panel") """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__) self.actions = [] # ?? check - assume it initialises array of actions self.closeGPSToolsFlag = False # Set up local logging loggingUtils = TOMsMessageLog() loggingUtils.setLogFile() QgsMessageLog.logMessage("In featuresWithGPS. Finished init", tag="TOMs panel") def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" QgsMessageLog.logMessage("Registering expression functions ... ", tag="TOMs panel") #self.hideMenusToolbars() self.expressionsObject = operatorExpressions() #self.expressionsObject.registerFunctions() # Register the Expression functions that we need # set up menu. Is there a generic way to do this? from an xml file? QgsMessageLog.logMessage("Adding toolbar", tag="TOMs panel") # Add toolbar self.featuresWithGPSToolbar = self.iface.addToolBar( "featuresWithGPS Toolbar") self.featuresWithGPSToolbar.setObjectName( "featuresWithGPSToolbar Toolbar") self.actionGPSToolbar = QAction( QIcon(":/plugins/featureswithgps/resources/GPS.png"), QCoreApplication.translate("MyPlugin", "Start GPS Tools"), self.iface.mainWindow()) self.actionGPSToolbar.setCheckable(True) self.featuresWithGPSToolbar.addAction(self.actionGPSToolbar) self.actionGPSToolbar.triggered.connect(self.onInitGPSTools) #self.currGPSManager = gpsManager(self.iface) #self.tableNames = self.gpsManager.tableNames # Now set up the toolbar self.gpsTools = captureGPSFeatures(self.iface, self.featuresWithGPSToolbar) #self.gpsTools.disableFeaturesWithGPSToolbarItems() def onInitGPSTools(self): QgsMessageLog.logMessage("In onInitGPSTools", tag="TOMs panel") if self.actionGPSToolbar.isChecked(): QgsMessageLog.logMessage("In onInitGPSTools. Activating ...", tag="TOMs panel") self.openGPSTools() else: QgsMessageLog.logMessage("In onInitGPSTools. Deactivating ...", tag="TOMs panel") self.closeGPSTools() def openGPSTools(self): # actions when the Proposals Panel is closed or the toolbar "start" is toggled QgsMessageLog.logMessage("In openGPSTools. Activating ...", tag="TOMs panel") if self.closeGPSToolsFlag: QMessageBox.information(self.iface.mainWindow(), "ERROR", ("Unable to start GPSTools ...")) self.actionGPSToolbar.setChecked(False) return self.gpsTools.enableFeaturesWithGPSToolbarItems() # TODO: connect close project signal to closeGPSTools def setCloseGPSToolsFlag(self): self.closeGPSToolsFlag = True def closeGPSTools(self): # actions when the Proposals Panel is closed or the toolbar "start" is toggled QgsMessageLog.logMessage("In closeGPSTools. Deactivating ...", tag="TOMs panel") # TODO: Delete any objects that are no longer needed #self.proposalTransaction.rollBackTransactionGroup() #del self.proposalTransaction # There is another call to this function from the dock.close() # Now disable the items from the Toolbar self.gpsTools.disableFeaturesWithGPSToolbarItems() def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" #self.expressionsObject.unregisterFunctions() # unregister all the Expression functions used # remove the toolbar QgsMessageLog.logMessage("Clearing toolbar ... ", tag="TOMs panel") self.featuresWithGPSToolbar.clear() QgsMessageLog.logMessage("Deleting toolbar ... ", tag="TOMs panel") del self.featuresWithGPSToolbar #self.restoreMenusToolbars() QgsMessageLog.logMessage("Unload comnpleted ... ", tag="TOMs panel")
class RelationSample(QgsMapTool): def showChildren(self): parent = self.rel.referencedLayer() child = self.rel.referencingLayer() features = parent.selectedFeatures() if len(features) == 0: return child.removeSelection() # クリアしないと、属性テーブルに余計に表示されるから for c in self.rel.getRelatedFeatures(features[0]): child.select(c.id()) selectedlayer = self.iface.activeLayer() # 現在のアクティブレイヤ退避 try: # このプログラム実行中は属性テーブルは選択中のフューチャーしか表示しないように設定する self.oldsetting = QSettings().value( '/Qgis/attributeTableBehaviour') QSettings().setValue('/Qgis/attributeTableBehavior', 'ShowSelected') # テーブル表示 self.iface.setActiveLayer(child) self.iface.mainWindow().findChild(QtWidgets.QAction, 'mActionOpenTable').trigger() finally: # 設定を戻す self.iface.setActiveLayer(selectedlayer) QSettings().setValue('/Qgis/attributeTableBehavior', self.oldsetting) def start(self): self.referencedLayer = QgsProject.instance().mapLayersByName( self.referencedLayerName)[0] self.referencingLayer = QgsProject.instance().mapLayersByName( self.referencingLayerName)[0] self.rel = QgsRelation() self.rel.setReferencingLayer(self.referencingLayer.id()) self.rel.setReferencedLayer(self.referencedLayer.id()) self.rel.addFieldPair(self.referencingField, self.referencedField) self.rel.setId('適当なID') self.rel.setName('適当な名前') QgsProject.instance().relationManager().addRelation(self.rel) self.referencedLayer.selectionChanged.connect(self.showChildren) def finish(self): QgsProject.instance().relationManager().removeRelation(self.rel) self.referencedLayer.selectionChanged.disconnect(self.showChildren) def __init__(self, iface): self.plugin_name = 'リレーションサンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.referencedLayerName = '〇〇〇' # 被参照のレイヤ名 self.referencingLayerName = '□□□' # 参照元のレイヤ名 self.referencedField = '△△△' # 参照元とのリンクに使うフィールド名 self.referencingField = '×××' # 被参照とのリンクに使うフィールド名 self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, RelationSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class TemporaryLayerSample(QgsMapTool): def setGeometry(self, geom): qf = QgsFields() for field in self.tmplayer.fields(): qf.append(QgsField(str(field.name()), typeName=field.typeName())) record = QgsFeature(qf) # 地物をセットする record.setGeometry(geom) # 属性をセットする record.setAttributes([]) # 作成したレコードをレイヤに追加 self.tmplayer.dataProvider().addFeatures([record]) self.tmplayer.updateExtents() self.canvas.refreshAllLayers() def start(self): # 一時レイヤ作成 typestr = 'Polygon?' fieldstr = '&field=〇〇:string&field=□□:double&field=××:date' crsstr = '&crs=' + str(QgsProject.instance().crs().authid()) layername = '一時レイヤ' self.tmplayer = QgsVectorLayer(typestr + crsstr + fieldstr, layername, "memory") QgsProject.instance().addMapLayer(self.tmplayer) # ラバーバンドのための設定 self.objtype = QgsWkbTypes.PolygonGeometry # QgsWkbTypes.PointGeometry, QgsWkbTypes.LineGeometry, QgsWkbTypes.PolygonGeometry maptool = RubberBandClass(self.iface, self.canvas, self.objtype) maptool.getObject.connect(self.setGeometry) self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect( self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = '一時レイヤ作成サンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, TemporaryLayerSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class PgMetadataDock(QDockWidget, DOCK_CLASS): def __init__(self, parent=None): _ = parent super().__init__() self.setupUi(self) self.settings = QgsSettings() self.current_datasource_uri = None self.current_connection = None self.viewer.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.viewer.page().linkClicked.connect(self.open_link) # Help button self.external_help.setText('') self.external_help.setIcon(QIcon(QgsApplication.iconPath('mActionHelpContents.svg'))) self.external_help.clicked.connect(self.open_external_help) # Flat table button self.flatten_dataset_table.setText('') self.flatten_dataset_table.setToolTip(tr("Add the catalog table")) self.flatten_dataset_table.setIcon(QgsApplication.getThemeIcon("/mActionAddHtml.svg")) self.flatten_dataset_table.clicked.connect(self.add_flatten_dataset_table) # Settings menu self.config.setAutoRaise(True) self.config.setToolTip(tr("Settings")) self.config.setPopupMode(QToolButton.InstantPopup) self.config.setIcon(QgsApplication.getThemeIcon("/mActionOptions.svg")) self.auto_open_dock_action = QAction( tr('Auto open dock from locator'), iface.mainWindow()) self.auto_open_dock_action.setCheckable(True) self.auto_open_dock_action.setChecked( self.settings.value("pgmetadata/auto_open_dock", True, type=bool) ) self.auto_open_dock_action.triggered.connect(self.save_auto_open_dock) menu = QMenu() menu.addAction(self.auto_open_dock_action) self.config.setMenu(menu) # Setting PDF/HTML menu self.save_button.setAutoRaise(True) self.save_button.setToolTip(tr("Save metadata")) self.save_button.setPopupMode(QToolButton.InstantPopup) self.save_button.setIcon(QIcon(QgsApplication.iconPath('mActionFileSave.svg'))) self.save_as_pdf = QAction( tr('Save as PDF') + '…', iface.mainWindow()) self.save_as_pdf.triggered.connect(partial(self.export_dock_content, OutputFormats.PDF)) self.save_as_html = QAction( tr('Save as HTML') + '…', iface.mainWindow()) self.save_as_html.triggered.connect(partial(self.export_dock_content, OutputFormats.HTML)) self.save_as_dcat = QAction( tr('Save as DCAT') + '…', iface.mainWindow()) self.save_as_dcat.triggered.connect(partial(self.export_dock_content, OutputFormats.DCAT)) self.menu_save = QMenu() self.menu_save.addAction(self.save_as_pdf) self.menu_save.addAction(self.save_as_html) self.menu_save.addAction(self.save_as_dcat) self.save_button.setMenu(self.menu_save) self.save_button.setEnabled(False) self.metadata = QgsProviderRegistry.instance().providerMetadata('postgres') # Display message in the dock if not settings_connections_names(): self.default_html_content_not_installed() else: self.default_html_content_not_pg_layer() iface.layerTreeView().currentLayerChanged.connect(self.layer_changed) def export_dock_content(self, output_format: OutputFormats): """ Export the current displayed metadata sheet to the given format. """ layer_name = iface.activeLayer().name() file_path = os.path.join( self.settings.value("UI/lastFileNameWidgetDir"), '{name}.{ext}'.format(name=layer_name, ext=output_format.ext) ) output_file = QFileDialog.getSaveFileName( self, tr("Save File as {format}").format(format=output_format.label), file_path, "{label} (*.{ext})".format( label=output_format.label, ext=output_format.ext, ) ) if output_file[0] == '': return self.settings.setValue("UI/lastFileNameWidgetDir", os.path.dirname(output_file[0])) output_file_path = output_file[0] parent_folder = str(Path(output_file_path).parent) if output_format == OutputFormats.PDF: printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setPageMargins(20, 20, 20, 20, QPrinter.Millimeter) printer.setOutputFileName(output_file_path) self.viewer.print(printer) iface.messageBar().pushSuccess( tr("Export PDF"), tr( "The metadata has been exported as PDF successfully in " "<a href=\"{}\">{}</a>").format(parent_folder, output_file_path) ) elif output_format in [OutputFormats.HTML, OutputFormats.DCAT]: if output_format == OutputFormats.HTML: data_str = self.viewer.page().currentFrame().toHtml() else: sql = self.sql_for_layer( self.current_datasource_uri, output_format=OutputFormats.DCAT) data = self.current_connection.executeSql(sql) with open(resources_path('xml', 'dcat.xml')) as xml_file: xml_template = xml_file.read() locale = QgsSettings().value("locale/userLocale", QLocale().name()) locale = locale.split('_')[0].lower() xml = parseString(xml_template.format(locale=locale, content=data[0][0])) data_str = xml.toprettyxml() with open(output_file[0], "w") as file_writer: file_writer.write(data_str) iface.messageBar().pushSuccess( tr("Export") + ' ' + output_format.label, tr( "The metadata has been exported as {format} successfully in " "<a href=\"{folder}\">{path}</a>").format( format=output_format.label, folder=parent_folder, path=output_file_path) ) def save_auto_open_dock(self): """ Save settings about the dock. """ self.settings.setValue("pgmetadata/auto_open_dock", self.auto_open_dock_action.isChecked()) @staticmethod def sql_for_layer(uri, output_format: OutputFormats): """ Get the SQL query for a given layer and output format. """ locale = QgsSettings().value("locale/userLocale", QLocale().name()) locale = locale.split('_')[0].lower() if output_format == OutputFormats.HTML: sql = ( "SELECT pgmetadata.get_dataset_item_html_content('{schema}', '{table}', '{locale}');" ).format(schema=uri.schema(), table=uri.table(), locale=locale) elif output_format == OutputFormats.DCAT: sql = ( "SELECT dataset FROM pgmetadata.get_datasets_as_dcat_xml(" " '{locale}'," " (" " SELECT array_agg(uid)" " FROM pgmetadata.dataset AS d" " WHERE d.schema_name = '{schema}' " " AND d.table_name = '{table}'" " )" ") " ).format(schema=uri.schema(), table=uri.table(), locale=locale) else: raise NotImplementedError('Output format is not yet implemented.') return sql def layer_changed(self, layer): """ When the layer has changed in the legend, we must check this new layer. """ self.save_button.setEnabled(False) self.current_datasource_uri = None self.current_connection = None if not settings_connections_names(): self.default_html_content_not_installed() return if not isinstance(layer, QgsVectorLayer): self.default_html_content_not_pg_layer() return uri = layer.dataProvider().uri() if not uri.schema() or not uri.table(): self.default_html_content_not_pg_layer() return connections, message = connections_list() if not connections: LOGGER.critical(message) self.set_html_content('PgMetadata', message) return # TODO, find the correct connection to query according to the datasource # The metadata HTML is wrong if there are many pgmetadata in different databases for connection_name in connections: connection = self.metadata.findConnection(connection_name) if not connection: LOGGER.critical("The global variable pgmetadata_connection_names is not correct.") self.default_html_content_not_installed() continue if not check_pgmetadata_is_installed(connection_name): LOGGER.critical(tr('PgMetadata is not installed on {}').format(connection_name)) continue sql = self.sql_for_layer(uri, output_format=OutputFormats.HTML) try: data = connection.executeSql(sql) except QgsProviderConnectionException as e: LOGGER.critical(tr('Error when querying the database : ') + str(e)) self.default_html_content_not_installed() return if not data: # Go to the next database continue if data[0] == NULL or data[0][0] == NULL: continue self.set_html_content(body=data[0][0]) self.save_button.setEnabled(True) self.current_datasource_uri = uri self.current_connection = connection break else: origin = uri.database() if uri.database() else uri.service() self.set_html_content( 'Missing metadata', tr('The layer {origin} {schema}.{table} is missing metadata.').format( origin=origin, schema=uri.schema(), table=uri.table()) ) def add_flatten_dataset_table(self): """ Add a flatten dataset table with all links and contacts. """ connections, message = connections_list() if not connections: LOGGER.critical(message) self.set_html_content('PgMetadata', message) return if len(connections) > 1: dialog = QInputDialog() dialog.setComboBoxItems(connections) dialog.setWindowTitle(tr("Database")) dialog.setLabelText(tr("Choose the database to add the catalog")) if not dialog.exec_(): return connection_name = dialog.textValue() else: connection_name = connections[0] metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection = metadata.findConnection(connection_name) locale = QgsSettings().value("locale/userLocale", QLocale().name()) locale = locale.split('_')[0].lower() uri = QgsDataSourceUri(connection.uri()) uri.setTable(f'(SELECT * FROM pgmetadata.export_datasets_as_flat_table(\'{locale}\'))') uri.setKeyColumn('uid') layer = QgsVectorLayer(uri.uri(), '{} - {}'.format(tr("Catalog"), connection_name), 'postgres') QgsProject.instance().addMapLayer(layer) @staticmethod def open_external_help(): QDesktopServices.openUrl(QUrl('https://docs.3liz.org/qgis-pgmetadata-plugin/')) @staticmethod def open_link(url): QDesktopServices.openUrl(url) def set_html_content(self, title=None, body=None): """ Set the content in the dock. """ css_file = resources_path('css', 'dock.css') with open(css_file, 'r') as f: css = f.read() html = '<html><head><style>{css}</style></head><body>'.format(css=css) if title: html += '<h2>{title}</h2>'.format(title=title) if body: html += body html += '</body></html>' # It must be a file, even if it does not exist on the file system. base_url = QUrl.fromLocalFile(resources_path('images', 'must_be_a_file.png')) self.viewer.setHtml(html, base_url) def default_html_content_not_installed(self): """ When PgMetadata is not installed correctly or not at all. """ message = "<p>" message += tr("The 'pgmetadata' schema is not installed or configured.") message += "</p>" message += "<p>" message += tr( "Either install PgMetadata on a database (Processing → Database → Installation of the " "database structure) or make the link to an existing PgMetadata database (Processing → " "Administration → Set connections to database)." ) message += "</p>" message += "<p>" message += tr( "Visit the documentation on <a href=\"https://docs.3liz.org/qgis-pgmetadata-plugin/\">" "docs.3liz.org</a> to check how to setup PgMetadata." ) message += "</p>" self.set_html_content('PgMetadata', message) def default_html_content_not_pg_layer(self): """ When it's not a PostgreSQL layer. """ self.set_html_content( 'PgMetadata', tr('You should click on a layer in the legend which is stored in PostgreSQL.'))
class manageRestrictionDetails(RestrictionTypeUtilsMixin): def __init__(self, iface, TOMsToolbar, proposalsManager): TOMsMessageLog.logMessage("In manageRestrictionDetails::init", level=Qgis.Info) # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() self.proposalsManager = proposalsManager self.TOMsToolbar = TOMsToolbar #self.constants = TOMsConstants() #self.restrictionTypeUtils = RestrictionTypeUtilsClass(self.iface) # This will set up the items on the toolbar # Create actions self.actionSelectRestriction = QAction( QIcon(":/plugins/TOMs/resources/mActionSelect.png"), QCoreApplication.translate("MyPlugin", "Select"), self.iface.mainWindow()) self.actionSelectRestriction.setCheckable(True) self.actionRestrictionDetails = QAction( QIcon(":/plugins/TOMs/resources/mActionGetInfo.svg"), QCoreApplication.translate("MyPlugin", "Get Details"), self.iface.mainWindow()) #self.actionRestrictionDetails.setCheckable(True) self.actionCreateBayRestriction = QAction( QIcon(":/plugins/TOMs/resources/mActionAddTrack.svg"), QCoreApplication.translate("MyPlugin", "Create Bay"), self.iface.mainWindow()) self.actionCreateBayRestriction.setCheckable(True) self.actionCreateLineRestriction = QAction( QIcon(":/plugins/TOMs/resources/mActionAddLine.svg"), QCoreApplication.translate("MyPlugin", "Create Line"), self.iface.mainWindow()) self.actionCreateLineRestriction.setCheckable(True) self.actionCreatePolygonRestriction = QAction( QIcon(":/plugins/TOMs/resources/rpolygonBy2Corners.svg"), QCoreApplication.translate("MyPlugin", "Create Polygon"), self.iface.mainWindow()) self.actionCreatePolygonRestriction.setCheckable(True) self.actionCreateSignRestriction = QAction( QIcon(":/plugins/TOMs/resources/mActionSetEndPoint.svg"), QCoreApplication.translate("MyPlugin", "Create Sign"), self.iface.mainWindow()) self.actionCreateSignRestriction.setCheckable(True) self.actionRemoveRestriction = QAction( QIcon(":/plugins/TOMs/resources/mActionDeleteTrack.svg"), QCoreApplication.translate("MyPlugin", "Remove Restriction"), self.iface.mainWindow()) #self.actionRemoveRestriction.setCheckable(True) self.actionEditRestriction = QAction( QIcon(":/plugins/TOMs/resources/mActionEdit.svg"), QCoreApplication.translate("MyPlugin", "Edit Restriction"), self.iface.mainWindow()) self.actionEditRestriction.setCheckable(True) self.actionSplitRestriction = QAction( QIcon(":/plugins/TOMs/resources/scissors.png"), QCoreApplication.translate("MyPlugin", "Split Restriction"), self.iface.mainWindow()) self.actionSplitRestriction.setCheckable(True) self.actionCreateConstructionLine = QAction( QIcon(":/plugins/TOMs/resources/CreateConstructionLine.svg"), QCoreApplication.translate("MyPlugin", "Create construction line"), self.iface.mainWindow()) self.actionCreateConstructionLine.setCheckable(True) # Add actions to the toolbar self.TOMsToolbar.addAction(self.actionSelectRestriction) self.TOMsToolbar.addAction(self.actionRestrictionDetails) self.TOMsToolbar.addAction(self.actionCreateBayRestriction) self.TOMsToolbar.addAction(self.actionCreateLineRestriction) self.TOMsToolbar.addAction(self.actionCreatePolygonRestriction) self.TOMsToolbar.addAction(self.actionCreateSignRestriction) self.TOMsToolbar.addAction(self.actionRemoveRestriction) self.TOMsToolbar.addAction(self.actionEditRestriction) self.TOMsToolbar.addAction(self.actionSplitRestriction) self.TOMsToolbar.addAction(self.actionCreateConstructionLine) # Connect action signals to slots self.actionSelectRestriction.triggered.connect( self.doSelectRestriction) self.actionRestrictionDetails.triggered.connect( self.doRestrictionDetails) self.actionCreateBayRestriction.triggered.connect( self.doCreateBayRestriction) self.actionCreateLineRestriction.triggered.connect( self.doCreateLineRestriction) self.actionCreatePolygonRestriction.triggered.connect( self.doCreatePolygonRestriction) self.actionCreateSignRestriction.triggered.connect( self.doCreateSignRestriction) self.actionRemoveRestriction.triggered.connect( self.doRemoveRestriction) self.actionEditRestriction.triggered.connect(self.doEditRestriction) self.actionSplitRestriction.triggered.connect(self.doSplitRestriction) self.actionCreateConstructionLine.triggered.connect( self.doCreateConstructionLine) pass def enableTOMsToolbarItems(self, restrictionTransaction): TOMsMessageLog.logMessage("In enableTOMsToolbarItems", level=Qgis.Info) self.actionSelectRestriction.setEnabled(True) self.actionRestrictionDetails.setEnabled(True) self.actionCreateBayRestriction.setEnabled(True) self.actionCreateLineRestriction.setEnabled(True) self.actionCreatePolygonRestriction.setEnabled(True) self.actionCreateSignRestriction.setEnabled(True) self.actionRemoveRestriction.setEnabled(True) self.actionEditRestriction.setEnabled(True) self.actionSplitRestriction.setEnabled(True) self.actionCreateConstructionLine.setEnabled(True) # set up a Transaction object # self.tableNames = TOMSLayers(self.iface) # self.tableNames.getLayers() self.restrictionTransaction = restrictionTransaction """self.proposalsManager.TOMsToolChanged.connect( functools.partial(self.restrictionTransaction.commitTransactionGroup, self.tableNames.PROPOSALS))""" #self.iface.mapCanvas().mapToolSet.connect(self.unCheckNodeTool) pass def unCheckNodeTool(self): self.actionEditRestriction.setChecked(False) def disableTOMsToolbarItems(self): TOMsMessageLog.logMessage("In disableTOMsToolbarItems", level=Qgis.Info) self.actionSelectRestriction.setEnabled(False) self.actionRestrictionDetails.setEnabled(False) self.actionCreateBayRestriction.setEnabled(False) self.actionCreateLineRestriction.setEnabled(False) self.actionCreatePolygonRestriction.setEnabled(False) self.actionCreateSignRestriction.setEnabled(False) self.actionRemoveRestriction.setEnabled(False) self.actionEditRestriction.setEnabled(False) self.actionSplitRestriction.setEnabled(False) self.actionCreateConstructionLine.setEnabled(False) pass def doSelectRestriction(self): """ Select point and then display details """ TOMsMessageLog.logMessage("In doSelectRestriction", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() if not self.actionSelectRestriction.isChecked(): self.actionSelectRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None # self.actionPan.connect() return self.actionSelectRestriction.setChecked(True) self.mapTool = GeometryInfoMapTool(self.iface) self.mapTool.setAction(self.actionSelectRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) def doRestrictionDetails(self): """ Select point and then display details """ TOMsMessageLog.logMessage("In doRestrictionDetails", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() currRestrictionLayer = self.iface.activeLayer() if currRestrictionLayer: TOMsMessageLog.logMessage( "In doRestrictionDetails. currLayer: " + str(currRestrictionLayer.name() + " Nr feats: " + str(currRestrictionLayer.selectedFeatureCount())), level=Qgis.Info) if currRestrictionLayer.selectedFeatureCount() > 0: if currProposalID == 0: # Ensure that no updates can occur for Proposal = 0 self.restrictionTransaction.rollBackTransactionGroup( ) # stop any editing else: self.restrictionTransaction.startTransactionGroup( ) # start editing selectedRestrictions = currRestrictionLayer.selectedFeatures() for currRestriction in selectedRestrictions: #self.restrictionForm = BayRestrictionForm(currRestrictionLayer, currRestriction) #self.restrictionForm.show() TOMsMessageLog.logMessage( "In restrictionFormOpen. currRestrictionLayer: " + str(currRestrictionLayer.name()), level=Qgis.Info) dialog = self.iface.getFeatureForm(currRestrictionLayer, currRestriction) self.setupRestrictionDialog( dialog, currRestrictionLayer, currRestriction, self.restrictionTransaction) # connects signals dialog.show() #self.iface.openFeatureForm(self.currRestrictionLayer, self.currRestriction) # Disconnect the signal that QGIS has wired up for the dialog to the button box. # button_box.accepted.disconnect(restrictionsDialog.accept) # Wire up our own signals. #button_box.accepted.connect(self.restrictionTypeUtils.onSaveRestrictionDetails, currRestriction, # currRestrictionLayer, self.dialog)) else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction first and then choose information button", QMessageBox.Ok) pass #currRestrictionLayer.deselect(currRestriction.id()) else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction first and then choose information button", QMessageBox.Ok) pass def doCreateBayRestriction(self): TOMsMessageLog.logMessage("In doCreateBayRestriction", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() if currProposalID > 0: if self.actionCreateBayRestriction.isChecked(): # self.iface.mapCanvas().setMapTool(CreateRestrictionTool) # self.actionCreateRestiction.setChecked(True) # set TOMs layer as active layer (for editing)... TOMsMessageLog.logMessage( "In doCreateBayRestriction - tool activated", level=Qgis.Info) # self.restrictionTransaction.startTransactionGroup() # start editing #self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName("Bays")[0] #currLayer = self.tableNames.BAYS currLayer = self.proposalsManager.tableNames.TOMsLayerDict.get( "Bays") self.iface.setActiveLayer(currLayer) self.restrictionTransaction.startTransactionGroup( ) # start editing self.mapTool = CreateRestrictionTool( self.iface, currLayer, self.proposalsManager, self.restrictionTransaction) self.mapTool.setAction(self.actionCreateBayRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) #self.currLayer.featureAdded.connect(self.proposalsManager.updateMapCanvas) #self.currLayer.editingStopped.connect (self.proposalsManager.updateMapCanvas) else: TOMsMessageLog.logMessage( "In doCreateBayRestriction - tool deactivated", level=Qgis.Info) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None self.actionCreateBayRestriction.setChecked(False) #self.currLayer.featureAdded.disconnect(self.proposalsManager.updateMapCanvas) #self.currLayer.editingStopped() else: if self.actionCreateBayRestriction.isChecked(): self.actionCreateBayRestriction.setChecked(False) if self.mapTool == None: self.actionCreateBayRestriction.setChecked(False) reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data is not allowed. Changes are made via Proposals", QMessageBox.Ok) pass def doCreateLineRestriction(self): TOMsMessageLog.logMessage("In doCreateLineRestriction", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() if currProposalID > 0: if self.actionCreateLineRestriction.isChecked(): # self.iface.mapCanvas().setMapTool(CreateRestrictionTool) # self.actionCreateRestiction.setChecked(True) # set TOMs layer as active layer (for editing)... TOMsMessageLog.logMessage( "In doCreateLineRestriction - tool activated", level=Qgis.Info) # self.restrictionTransaction.startTransactionGroup() # start editing #self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName("Lines")[0] #currLayer = self.tableNames.LINES currLayer = self.proposalsManager.tableNames.TOMsLayerDict.get( "Lines") self.iface.setActiveLayer(currLayer) self.restrictionTransaction.startTransactionGroup( ) # start editing self.mapTool = CreateRestrictionTool( self.iface, currLayer, self.proposalsManager, self.restrictionTransaction) self.mapTool.setAction(self.actionCreateLineRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) #self.currLayer.editingStopped.connect (self.proposalsManager.updateMapCanvas) else: TOMsMessageLog.logMessage( "In doCreateLineRestriction - tool deactivated", level=Qgis.Info) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None self.actionCreateLineRestriction.setChecked(False) else: if self.actionCreateLineRestriction.isChecked(): self.actionCreateLineRestriction.setChecked(False) if self.mapTool == None: self.actionCreateLineRestriction.setChecked(False) reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data is not allowed. Changes are made via Proposals", QMessageBox.Ok) pass def doCreatePolygonRestriction(self): TOMsMessageLog.logMessage("In doCreatePolygonRestriction", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() if currProposalID > 0: if self.actionCreatePolygonRestriction.isChecked(): # self.iface.mapCanvas().setMapTool(CreateRestrictionTool) # self.actionCreateRestiction.setChecked(True) # set TOMs layer as active layer (for editing)... TOMsMessageLog.logMessage( "In doCreatePolygonRestriction - tool activated", level=Qgis.Info) #self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName("RestrictionPolygons")[0] #currLayer = self.tableNames.RESTRICTION_POLYGONS currLayer = self.proposalsManager.tableNames.TOMsLayerDict.get( "RestrictionPolygons") self.iface.setActiveLayer(currLayer) self.restrictionTransaction.startTransactionGroup() self.mapTool = CreateRestrictionTool( self.iface, currLayer, self.proposalsManager, self.restrictionTransaction) self.mapTool.setAction(self.actionCreatePolygonRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) #self.currLayer.editingStopped.connect (self.proposalsManager.updateMapCanvas) else: TOMsMessageLog.logMessage( "In doCreatePolygonRestriction - tool deactivated", level=Qgis.Info) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None self.actionCreatePolygonRestriction.setChecked(False) else: if self.actionCreatePolygonRestriction.isChecked(): self.actionCreatePolygonRestriction.setChecked(False) if self.mapTool == None: self.actionCreatePolygonRestriction.setChecked(False) reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data is not allowed. Changes are made via Proposals", QMessageBox.Ok) pass def doCreateSignRestriction(self): TOMsMessageLog.logMessage("In doCreateSignRestriction", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() if currProposalID > 0: if self.actionCreateSignRestriction.isChecked(): # self.iface.mapCanvas().setMapTool(CreateRestrictionTool) # self.actionCreateRestiction.setChecked(True) # set TOMs layer as active layer (for editing)... TOMsMessageLog.logMessage( "In doCreateSignRestriction - tool activated", level=Qgis.Info) # self.restrictionTransaction.startTransactionGroup() #self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName("Signs")[0] #currLayer = self.tableNames.SIGNS currLayer = self.proposalsManager.tableNames.TOMsLayerDict.get( "Signs") self.iface.setActiveLayer(currLayer) self.restrictionTransaction.startTransactionGroup() self.mapTool = CreateRestrictionTool( self.iface, currLayer, self.proposalsManager, self.restrictionTransaction) self.mapTool.setAction(self.actionCreateSignRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) #self.currLayer.editingStopped.connect (self.proposalsManager.updateMapCanvas) else: TOMsMessageLog.logMessage( "In doCreateSignRestriction - tool deactivated", level=Qgis.Info) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None self.actionCreateSignRestriction.setChecked(False) #self.currLayer.editingStopped() else: if self.actionCreateSignRestriction.isChecked(): self.actionCreateSignRestriction.setChecked(False) if self.mapTool == None: self.actionCreateSignRestriction.setChecked(False) reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data is not allowed. Changes are made via Proposals", QMessageBox.Ok) pass def doCreateConstructionLine(self): TOMsMessageLog.logMessage("In doCreateConstructionLine", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None if self.actionCreateConstructionLine.isChecked(): # self.iface.mapCanvas().setMapTool(CreateRestrictionTool) # self.actionCreateRestiction.setChecked(True) # set TOMs layer as active layer (for editing)... TOMsMessageLog.logMessage( "In doCreateConstructionLine - tool activated", level=Qgis.Info) self.currLayer = QgsProject.instance().mapLayersByName( "ConstructionLines")[0] self.iface.setActiveLayer(self.currLayer) self.currLayer.startEditing() self.mapTool = CreateRestrictionTool(self.iface, self.currLayer, self.proposalsManager, self.restrictionTransaction) self.mapTool.setAction(self.actionCreateConstructionLine) self.iface.mapCanvas().setMapTool(self.mapTool) #self.currLayer.editingStopped.connect (self.proposalsManager.updateMapCanvas) else: TOMsMessageLog.logMessage( "In doCreateConstructionLine - tool deactivated", level=Qgis.Info) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None self.actionCreateConstructionLine.setChecked(False) #self.currLayer.editingStopped () pass #def onCreateRestriction(self, newRestriction): """ Called by map tool when a restriction is created """ #TOMsMessageLog.logMessage("In onCreateRestriction - after shape created", level=Qgis.Info) #self.TOMslayer = QgsMapLayerRegistry.instance().mapLayersByName("TOMs_Layer")[0] # Obtain all the details for the restriction # Create the dislay geometry ... def doRemoveRestriction(self): # pass control to MapTool and then deal with Proposals issues from there ?? TOMsMessageLog.logMessage("In doRemoveRestriction", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() #self.mapTool = None # Get the current proposal from the session variables self.currProposalID = self.proposalsManager.currentProposal() if self.currProposalID > 0: ''' if self.actionRemoveRestriction.isChecked(): # self.iface.mapCanvas().setMapTool(CreateRestrictionTool) # self.actionCreateRestiction.setChecked(True) # set TOMs layer as active layer (for editing)... TOMsMessageLog.logMessage("In doRemoveRestriction - tool activated", level=Qgis.Info) #self.TOMslayer = QgsMapLayerRegistry.instance().mapLayersByName("TOMs_Layer")[0] #iface.setActiveLayer(self.TOMslayer) self.mapTool = RemoveRestrictionTool(self.iface, self.onRemoveRestriction) self.mapTool.setAction(self.actionRemoveRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) # self.currLayer.editingStopped.connect (self.proposalsManager.updateMapCanvas) else: TOMsMessageLog.logMessage("In doRemoveRestriction - tool deactivated", level=Qgis.Info) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None self.actionRemoveRestriction.setChecked(False) ''' currRestrictionLayer = self.iface.activeLayer() #currRestrictionLayer.editingStopped.connect(self.proposalsManager.updateMapCanvas) if currRestrictionLayer: TOMsMessageLog.logMessage( "In doRemoveRestriction. currLayer: " + str(currRestrictionLayer.name()), level=Qgis.Info) if currRestrictionLayer.selectedFeatureCount() > 0: selectedRestrictions = currRestrictionLayer.selectedFeatures( ) self.restrictionTransaction.startTransactionGroup() for currRestriction in selectedRestrictions: self.onRemoveRestriction(currRestrictionLayer, currRestriction) else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction for delete", QMessageBox.Ok) pass else: """if self.actionRemoveRestriction.isChecked(): self.actionRemoveRestriction.setChecked(False) if self.mapTool == None: self.actionRemoveRestriction.setChecked(False)""" reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data are not allowed. Changes are made via Proposals", QMessageBox.Ok) pass def onRemoveRestriction(self, currRestrictionLayer, currRestriction): TOMsMessageLog.logMessage("In onRemoveRestriction. currLayer: " + str(currRestrictionLayer.id()) + " CurrFeature: " + str(currRestriction.id()), level=Qgis.Info) #self.currRestrictionLayer = currRestrictionLayer #self.currRestriction = currRestriction currProposalID = self.proposalsManager.currentProposal() currRestrictionLayerID = self.getRestrictionLayerTableID( currRestrictionLayer) idxRestrictionID = currRestriction.fields().indexFromName( "RestrictionID") if self.restrictionInProposal(currRestriction[idxRestrictionID], currRestrictionLayerID, currProposalID): # remove the restriction from the RestrictionsInProposals table - and from the currLayer, i.e., it is totally removed. # NB: This is the only case of a restriction being truly deleted TOMsMessageLog.logMessage( "In onRemoveRestriction. Removing from RestrictionsInProposals and currLayer.", level=Qgis.Info) # Delete from RestrictionsInProposals result = self.deleteRestrictionInProposal( currRestriction[idxRestrictionID], currRestrictionLayerID, currProposalID) if result: TOMsMessageLog.logMessage( "In onRemoveRestriction. Deleting restriction id: " + str(currRestriction.id()), level=Qgis.Info) deleteStatus = currRestrictionLayer.deleteFeature( currRestriction.id()) TOMsMessageLog.logMessage( "In onRemoveRestriction. deleteStatus: " + str(deleteStatus), level=Qgis.Info) else: QMessageBox.information(None, "ERROR", ("Error deleting restriction ...")) else: # need to: # - enter the restriction into the table RestrictionInProposals as closed, and # TOMsMessageLog.logMessage( "In onRemoveRestriction. Closing existing restriction.", level=Qgis.Info) self.addRestrictionToProposal(currRestriction[idxRestrictionID], currRestrictionLayerID, currProposalID, RestrictionAction.OPEN) # 2 = Close # Now save all changes # Trying to unset map tool to force updates ... #self.iface.mapCanvas().unsetMapTool(self.iface.mapCanvas().mapTool()) self.restrictionTransaction.commitTransactionGroup(None) #self.restrictionTransaction.deleteTransactionGroup() #currRestrictionLayer.triggerRepaint() # This shouldn't be required ... def doEditRestriction(self): TOMsMessageLog.logMessage("In doEditRestriction - starting", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() if currProposalID > 0: if self.actionEditRestriction.isChecked(): TOMsMessageLog.logMessage( "In actionEditRestriction - tool being activated", level=Qgis.Info) # Need to clear any other maptools .... ******** currRestrictionLayer = self.iface.activeLayer() if currRestrictionLayer: TOMsMessageLog.logMessage( "In doEditRestriction. currLayer: " + str(currRestrictionLayer.name()), level=Qgis.Info) if currRestrictionLayer.selectedFeatureCount() > 0: self.restrictionTransaction.startTransactionGroup() """currRestriction = currRestrictionLayer.selectedFeatures()[0] restrictionForEdit = self.prepareRestrictionForEdit (currRestriction, currRestrictionLayer) currRestrictionLayer.deselect(currRestriction.id()) currRestrictionLayer.select(restrictionForEdit.id()) #currRestrictionLayer.selectByIds([editFeature.id()])""" #self.actionEditRestriction.setChecked(True) self.mapTool = TOMsNodeTool( self.iface, self.proposalsManager, self.restrictionTransaction ) # This is where we use the Node Tool ... need canvas and panel?? """self.mapTool = TOMsNodeTool(self.iface, self.proposalsManager, self.restrictionTransaction, restrictionForEdit, currRestrictionLayer) # This is where we use the Node Tool ... need canvas and panel??""" self.mapTool.setAction(self.actionEditRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) #currRestrictionLayer.editingStopped.connect(self.proposalsManager.updateMapCanvas) else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction for edit", QMessageBox.Ok) self.actionEditRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction for edit", QMessageBox.Ok) self.actionEditRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None else: TOMsMessageLog.logMessage( "In doEditRestriction - tool deactivated", level=Qgis.Info) self.actionEditRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None pass else: """if self.actionEditRestriction.isChecked(): self.actionEditRestriction.setChecked(False) if self.mapTool == None: self.actionEditRestriction.setChecked(False)""" reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data are not allowed. Changes are made via Proposals", QMessageBox.Ok) self.actionEditRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None pass TOMsMessageLog.logMessage("In doEditRestriction - leaving", level=Qgis.Info) pass def doSplitRestriction(self): TOMsMessageLog.logMessage("In doSplitRestriction - starting", level=Qgis.Info) self.proposalsManager.TOMsToolChanged.emit() self.mapTool = None # Get the current proposal from the session variables currProposalID = self.proposalsManager.currentProposal() if currProposalID > 0: if self.actionSplitRestriction.isChecked(): TOMsMessageLog.logMessage( "In doSplitRestriction - tool being activated", level=Qgis.Info) # Need to clear any other maptools .... ******** currRestrictionLayer = self.iface.activeLayer() if currRestrictionLayer: TOMsMessageLog.logMessage( "In doSplitRestriction. currLayer: " + str(currRestrictionLayer.name()), level=Qgis.Info) if currRestrictionLayer.selectedFeatureCount() > 0: self.restrictionTransaction.startTransactionGroup() """currRestriction = currRestrictionLayer.selectedFeatures()[0] restrictionForEdit = self.prepareRestrictionForEdit (currRestriction, currRestrictionLayer) currRestrictionLayer.deselect(currRestriction.id()) currRestrictionLayer.select(restrictionForEdit.id()) #currRestrictionLayer.selectByIds([editFeature.id()])""" #self.actionEditRestriction.setChecked(True) self.mapTool = TOMsSplitRestrictionTool( self.iface, currRestrictionLayer, self.proposalsManager, self.restrictionTransaction ) # This is where we use the Node Tool ... need canvas and panel?? """self.mapTool = TOMsNodeTool(self.iface, self.proposalsManager, self.restrictionTransaction, restrictionForEdit, currRestrictionLayer) # This is where we use the Node Tool ... need canvas and panel??""" self.mapTool.setAction(self.actionSplitRestriction) self.iface.mapCanvas().setMapTool(self.mapTool) #currRestrictionLayer.editingStopped.connect(self.proposalsManager.updateMapCanvas) else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction for edit", QMessageBox.Ok) self.actionSplitRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None else: reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Select restriction for edit", QMessageBox.Ok) self.actionSplitRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None else: TOMsMessageLog.logMessage( "In doSplitRestriction - tool deactivated", level=Qgis.Info) self.actionSplitRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None pass else: """if self.actionEditRestriction.isChecked(): self.actionEditRestriction.setChecked(False) if self.mapTool == None: self.actionEditRestriction.setChecked(False)""" reply = QMessageBox.information( self.iface.mainWindow(), "Information", "Changes to current data are not allowed. Changes are made via Proposals", QMessageBox.Ok) self.actionSplitRestriction.setChecked(False) self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None pass TOMsMessageLog.logMessage("In doSplitRestriction - leaving", level=Qgis.Info) pass
class RulebaseSample(QgsMapTool): def start(self): maptool = self self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect(self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 self.layer = self.iface.activeLayer() # 元の設定を保存 self.oldrenderer = self.layer.renderer().clone() # 設定 self.renderer = QgsRuleBasedRenderer(QgsSymbol.defaultSymbol(self.layer.geometryType())) self.root_rule = self.renderer.rootRule() for label, expression, color_name in self.style_rules: rule = self.root_rule.children()[0].clone() # ラベル、フィルタ、色以外はデフォルト rule.setLabel(label) rule.setFilterExpression(expression) rule.symbol().setColor(QColor(color_name)) self.root_rule.appendChild(rule) self.root_rule.removeChildAt(0) self.layer.setRenderer(self.renderer) self.layer.triggerRepaint() def finish(self): # 元の設定に戻す self.layer.setRenderer(self.oldrenderer) self.layer.triggerRepaint() self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'ルールによる色設定サンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる # ルール (ラベル, 式, 色) self.style_rules = ( ('設定1', '"フィールド名" = \'〇〇\'', '#ff0000'), # この設定では赤 ('設定2', '"フィールド名" = \'□□\'', '#00ff00'), # この設定では緑 ('その他', 'ELSE', '#ffffff') # それ以外は白 ) self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, RulebaseSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__)+'/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect(self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable(self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class PetroProfileDialog(QtWidgets.QDialog, FORM_CLASS): """Dialog to show the petrographic drilling profiles""" def __init__(self, iface, parent=None): """Constructor.""" super(PetroProfileDialog, self).__init__(parent) # Set up the user interface from Designer through FORM_CLASS. # After self.setupUi() you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self._setupScene() self._setupGeoDirectionActions() self._xFac = None self._yFac = None def _setupScene(self): """Set up a new scene""" self.scene = QtWidgets.QGraphicsScene() self.view = self.findChild(QtWidgets.QGraphicsView, "graphicsView") self.view.setScene(self.scene) self.view.viewport().installEventFilter(self) def _setupGeoDirectionActions(self): """Set up actions for geo-directions""" self._nsAction = QAction("North \u2794 South", self) self._nsAction.triggered.connect(self.drawProfilesNorthSouth) self._nsAction.setEnabled(True) self._nsAction.setCheckable(True) self._snAction = QAction("South \u2794 North", self) self._snAction.triggered.connect(self.drawProfilesSouthNorth) self._snAction.setEnabled(True) self._snAction.setCheckable(True) self._weAction = QAction("West \u2794 East", self) self._weAction.triggered.connect(self.drawProfilesWestEast) self._weAction.setEnabled(True) self._weAction.setCheckable(True) self._ewAction = QAction("East \u2794 West", self) self._ewAction.triggered.connect(self.drawProfilesEastWest) self._ewAction.setEnabled(True) self._ewAction.setCheckable(True) def _getActions(self): """Get actions that are displayed in the context menu""" actions = [] scaleAction = QAction("Scale...", self) scaleAction.triggered.connect(self._scale) scaleAction.setEnabled(True) actions.append(scaleAction) exportAction = QAction("Export as...", self) exportAction.triggered.connect(self._exportToFile) exportAction.setEnabled(True) actions.append(exportAction) sep = QAction("", self) sep.setSeparator(True) actions.append(sep) group = QActionGroup(self) group.addAction(self._nsAction) actions.append(self._nsAction) group.addAction(self._snAction) actions.append(self._snAction) group.addAction(self._weAction) actions.append(self._weAction) group.addAction(self._ewAction) actions.append(self._ewAction) sepAbout = QAction("", self) sepAbout.setSeparator(True) actions.append(sepAbout) manualAction = QAction("Manual...", self) manualAction.triggered.connect(self._openManual) manualAction.setEnabled(True) actions.append(manualAction) aboutAction = QAction("About...", self) aboutAction.triggered.connect(self._aboutPlugin) aboutAction.setEnabled(True) actions.append(aboutAction) return actions def contextMenuEvent(self, e): """Show context menu""" m = QMenu() for a in self._getActions(): m.addAction(a) m.exec(e.globalPos()) e.setAccepted(True) def showEvent(self, e): """Override showEvent""" super().showEvent(e) self.drawProfilesNorthSouth() def wheelEvent(self, e): """Zoom in/out""" delta = e.angleDelta() if delta.isNull(): return s = 1.0 if delta.y() > 0: s = 1.15 else: s = 0.85 self.view.scale(s, s) def eventFilter(self, obj, e): """Filter wheel event""" if e.type() == QEvent.Wheel: return True return super().eventFilter(obj, e) def _scale(self): """Provide scaling factor""" dlg = ScaleDialog(self._xFac, self._yFac, self) dlg.show() result = dlg.exec_() # Run the dialog event loop if result: self._xFac = dlg.xFac() self._yFac = dlg.yFac() if self._nsAction.isChecked(): self.drawProfilesNorthSouth() elif self._snAction.isChecked(): self.drawProfilesSouthNorth() elif self._weAction.isChecked(): self.drawProfilesWestEast() elif self._ewAction.isChecked(): self.drawProfilesEastWest() def _exportToFile(self): """Export drawing to file""" name = self._getFilename() if (name is None) or (len(name) == 0): return self._exportWithPainter(name) def _svgPaintDevice(self, name, sourceRect, targetRect): """Get QSvgGenerator as paint device""" generator = QSvgGenerator() generator.setDescription("This SVG was generated with the geoCore " "plugin of QGIS, written by T-Systems on site services GmbH") generator.setTitle("geoCore") generator.setSize(sourceRect.size().toSize()) generator.setViewBox(targetRect) generator.setFileName(name) return generator def _imgPaintDevice(self, sourceRect): """Get QImage as paint device""" img = QImage(sourceRect.width(), sourceRect.height(), QImage.Format_ARGB32) img.fill(QColor("transparent")) return img def _getSourceAndTargetRect(self): """Returns the source and target rect for export""" self.scene.clearSelection() margin = 5 sourceRect = self.scene.itemsBoundingRect() sourceRect.adjust(-margin, -margin, margin, margin) targetRect = QRectF(0, 0, sourceRect.width(), sourceRect.height()) return sourceRect, targetRect def _exportWithPainter(self, name): """Export as image file""" try: sourceRect, targetRect = self._getSourceAndTargetRect() pd = None if Path(name).suffix.upper() == ".SVG": pd = self._svgPaintDevice(name, sourceRect, targetRect) else: pd = self._imgPaintDevice(sourceRect) painter = QPainter() painter.begin(pd) painter.setRenderHint(QPainter.Antialiasing) self.scene.render(painter, targetRect, sourceRect) painter.end() if hasattr(pd, 'save') and callable(pd.save): pd.save(name) QgsMessageLog.logMessage("exported to {}".format(name), level=Qgis.Info) except IOError: self.showMessage("Error", "Failed to export to {}".format(name), Qgis.Critical) def _getFilename(self): """Get file name via file dialog""" home = str(Path.home()) name = QFileDialog.getSaveFileName(self, "Export to file", home, "Vector graphics (*.svg);;Images (*.png *.jpg)") if (name is None) or (len(name[0]) == 0): return None filename = name[0] suffix = Path(filename).suffix if len(suffix) == 0: if "svg" in name[1]: filename = filename + ".svg" else: filename = filename + ".png" return filename def drawProfilesNorthSouth(self): """Draw profiles in direction from north to south""" self._nsAction.setChecked(True) crit = lambda f: -f.attribute('ycoord') # north -> south self._drawProfiles(crit) def drawProfilesSouthNorth(self): """Draw profiles in direction from south to north""" self._snAction.setChecked(True) crit = lambda f: f.attribute('ycoord') # south -> north self._drawProfiles(crit) def drawProfilesWestEast(self): """Draw profiles in direction from west to east""" self._weAction.setChecked(True) crit = lambda f: f.attribute('xcoord') # west -> east self._drawProfiles(crit) def drawProfilesEastWest(self): """Draw profiles in direction from east to west""" self._ewAction.setChecked(True) crit = lambda f: -f.attribute('xcoord') # east -> west self._drawProfiles(crit) def _drawProfiles(self, sortCrit): """Draw the selected drilling profiles""" self.scene.clear() features = self._getSortedDrillingPositions(sortCrit) builder = ProfileBuilder(self.iface.activeLayer().name(), self.showMessage) pac = builder.getProfilesAndConnectors(features) painter = ProfilePainter(self.scene, self.view.width(), self.view.height()) painter.applyScale(self._xFac, self._yFac) painter.paint(pac, len(pac) == 1) self.view.resetTransform() self.view.setSceneRect(self.scene.itemsBoundingRect()) def _getSortedDrillingPositions(self, crit): """Sort profiles using given criterium""" features = self.iface.activeLayer().selectedFeatures() return sorted(features, key=crit) def _aboutPlugin(self): """Show the about dialog""" QMessageBox.about(self, "About", """<h1>geoCore</h1> <p> Copyright (C) 2019-2021 Gerrit Bette, T-Systems on site services GmbH<br> This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions; see <a href="https://www.gnu.org/licenses/gpl-3.0-standalone.html"> https://www.gnu.org/licenses</a> for details. </p> <p> Citation: G. Bette & M. Mennenga 2021: t-systems-on-site-services-gmbh/geoCore v0.8 (Version v0.8). Zenodo. <a href=" http://doi.org/10.5281/zenodo.4548887"> http://doi.org/10.5281/zenodo.4548887</a> </p> <p> <a href="https://github.com/t-systems-on-site-services-gmbh/geoCore/blob/master/geoCore/help/usage.md"> Manual</a> </p> """) def _openManual(self): """Open the user manual""" script_dir = os.path.dirname(__file__) rel_path = "help/usage.html" abs_file_path = os.path.join(script_dir, rel_path) os.system("start " + abs_file_path) def showMessage(self, title, message, level): """Display a message in the main window's messageBar""" self.iface.messageBar().pushMessage(title, message, level)
class OsCertificateStore: def __init__(self, iface): self.iface = iface self.action_setting = None self.action_about = None self.action_run = None if not self.is_supported(): return # noinspection PyBroadException try: # noinspection PyPackageRequirements,PyUnresolvedReferences from .tests import testerplugin # noinspection PyUnresolvedReferences from qgistester.tests import addTestModule addTestModule(testerplugin, "OS Certificate Store") except: pass @staticmethod def log(msg, level=Qgis.Info): QgsMessageLog.logMessage(msg, "OS Certificate Store", level=level) @staticmethod def is_supported(): """Check wether this plugin can run in this platform""" if platform == "linux" or platform == "linux2": # linux return False or TEST_ON_LINUX elif platform == "darwin": # OS X return False elif platform == "win32": # Windows... return True else: return False # noinspection PyPep8Naming def initGui(self): if not self.is_supported(): return self.action_setting = QAction( self.tr("Import Windows intermediate certificate authorities " "on startup"), self.iface.mainWindow()) self.action_setting.setObjectName("enableoscertstore") self.action_setting.setCheckable(True) self.action_setting.setChecked(QgsSettings().value(SETTINGS_KEY + '/import_enabled', True, type=bool)) # noinspection PyUnresolvedReferences self.action_setting.changed.connect(self.setting_changed) self.iface.addPluginToMenu(self.tr("OS Certificate Store"), self.action_setting) icon_run = QIcon(os.path.dirname(__file__) + "/icons/certificate.svg") if QgsSettings().value( SETTINGS_KEY + '/import_successfully_run', True, type=bool) \ or TEST_ON_LINUX: self.action_run = QAction( icon_run, self.tr( "Reimport Windows intermediate certificate authorities"), self.iface.mainWindow()) self.action_run.setObjectName("enableoscertstore") # noinspection PyUnresolvedReferences self.action_run.triggered.connect(partial(self.run_triggered, True)) self.iface.addPluginToMenu(self.tr("OS Certificate Store"), self.action_run) # noinspection PyArgumentList,PyCallByClass self.action_about = QAction( QgsApplication.getThemeIcon('/mActionHelpContents.svg'), "About...", self.iface.mainWindow()) self.action_about.setObjectName("oscertstoreabout") # noinspection PyUnresolvedReferences self.action_about.triggered.connect(self.about_triggered) self.iface.addPluginToMenu(self.tr("OS Certificate Store"), self.action_about) # No toolbar and other menus # self.iface.addToolBarIcon(self.action) # Run on startup if QgsSettings().value(SETTINGS_KEY + '/import_enabled', True, type=bool): self.run_triggered(False) def unload(self): if not self.is_supported(): return # noinspection PyBroadException try: # noinspection PyPackageRequirements,PyUnresolvedReferences from .tests import testerplugin # noinspection PyUnresolvedReferences from qgistester.tests import removeTestModule removeTestModule(testerplugin, self.tr("OS Certificate Store")) except: pass # noinspection PyBroadException try: # noinspection PyUnresolvedReferences from lessons import removeLessonsFolder folder = os.path.join(os.path.dirname(__file__), "_lessons") removeLessonsFolder(folder) except: pass self.iface.removePluginMenu(self.tr("OS Certificate Store"), self.action_about) self.iface.removePluginMenu(self.tr("OS Certificate Store"), self.action_setting) if self.action_run is not None: self.iface.removePluginMenu(self.tr("OS Certificate Store"), self.action_run) def setting_changed(self): if not self.is_supported(): return self.log("Import at startup: %s" % self.action_setting.isChecked()) QgsSettings().setValue(SETTINGS_KEY + '/import_enabled', self.action_setting.isChecked()) def run_triggered(self, notify): self.log("Importing intermediate certificates ...") try: from .certs_importer import run QgsSettings().setValue(SETTINGS_KEY + '/import_successfully_run', run(self)) if notify: self.iface.messageBar().pushMessage( self.tr("Success"), self.tr("Intermediate certificates imported correctly " "(see logs for details)."), level=Qgis.Info) except Exception as ex: self.log("Error importing intermediate certificates: %s" % ex) QgsSettings().setValue(SETTINGS_KEY + '/import_successfully_run', False) if notify: self.iface.messageBar().pushMessage( self.tr("Error"), self.tr("There was an error importing intermediate " "certificates (see the logs for details)."), level=Qgis.Critical) def about_triggered(self): # noinspection PyArgumentList dlg = QgsMessageOutput.createMessageOutput() dlg.setTitle(self.tr("Plugin info")) dlg.setMessage(self._plugin_details("oscertstore"), QgsMessageOutput.MessageHtml) dlg.showMessage() @staticmethod def tr(msg): return msg # noinspection PyUnusedLocal def _plugin_details(self, namespace): config = DictParser() config.read_file( open( os.path.join(os.path.realpath(os.path.dirname(__file__)), 'metadata.txt'))) plugin = config.as_dict()['general'] html = '<style>body, table {padding:0px; margin:0px; ' \ 'font-family:verdana; font-size: 1.1em;}</style>' html += '<body>' html += '<table cellspacing="4" width="100%"><tr><td>' html += '<h1>{}</h1>'.format(plugin.get('name')) html += '<h3>{}</h3>'.format(plugin.get('description')) if plugin.get('about'): html += plugin.get('about').replace('\n', '<br/>') html += '<br/><br/>' if plugin.get('category'): html += '{}: {} <br/>'.format(self.tr('Category'), plugin.get('category')) if plugin.get('tags'): html += '{}: {} <br/>'.format(self.tr('Tags'), plugin.get('tags')) if (plugin.get('homepage') or plugin.get('tracker') or plugin.get('code_repository')): html += self.tr('More info:') if plugin.get('homepage'): html += '<a href="{}">{}</a> '.format( plugin.get('homepage'), self.tr('homepage')) if plugin.get('tracker'): html += '<a href="{}">{}</a> '.format( plugin.get('tracker'), self.tr('bug_tracker')) if plugin.get('code_repository'): html += '<a href="{}">{}</a> '.format( plugin.get('code_repository'), self.tr('code_repository')) html += '<br/>' html += '<br/>' if plugin.get('author_email'): html += '{}: <a href="mailto:{}">{}</a>'.format( self.tr('Author email'), plugin.get('author_email'), plugin.get('author_name')) html += '<br/><br/>' elif plugin.get('author'): html += '{}: {}'.format(self.tr('Author'), plugin.get('author')) html += '<br/><br/>' if plugin.get('version_installed'): ver = plugin.get('version_installed') if ver == '-1': ver = '?' html += self.tr('Installed version: {} (in {})<br/>'.format( ver, plugin.get('library'))) if plugin.get('version_available'): html += self.tr('Available version: {} (in {})<br/>'.format( plugin.get('version_available'), plugin.get('zip_repository'))) if plugin.get('changelog'): html += '<br/>' changelog = self.tr('Changelog:<br/>{} <br/>'.format( plugin.get('changelog'))) html += changelog.replace('\n', '<br/>') html += '</td></tr></table>' html += '</body>' return html
class GetRasterPixelValueSample(QgsMapTool): def canvasMoveEvent(self, event): print( str( self.gr.getValueInterpolation( self.toMapCoordinates(event.pos())))) def start(self): self.gr = GetRasterPixelValueClass(self.iface.activeLayer()) maptool = self self.canvas.setMapTool(maptool) self.canvas.mapToolSet.connect( self.unsetTool) # このサンプル実行中に他のアイコンを押した場合 def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'ピクセル値取得サンプル' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所(このサンプルの場合、メニューの「プラグイン/雛形/ダイアログ無し雛形」) self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = True # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, GetRasterPixelValueSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()
class FeatureSelectSample: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface self.canvas = self.iface.mapCanvas() # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # プラグインの登録場所 self.menu_pos = 'サンプル フューチャー選択' # キャンバスウィンドウ上でのマウスイベントの設定 self.mouseEventSample = FeatureSelectionTool(self.canvas) def initGui(self): icon = QIcon(self.plugin_dir + '/icon.png') self.action = QAction(icon, '一つ選択→属性編集', self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable(True) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる。 #self.iface.addToolBarIcon(self.action) # ツールバーにアイコンを表示させたいなら#外して self.iface.addPluginToMenu(self.menu_pos, self.action) # このサンプル以外のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, FeatureSelectSample): try: self.mouseEventSample.featureIdentified.disconnect( self.editAttribute) except Exception: pass self.iface.layerTreeView().currentLayerChanged.disconnect( self.changeLayer) self.canvas.mapToolSet.disconnect(self.unsetTool) self.canvas.unsetMapTool(self.mouseEventSample) self.action.setChecked(False) def execSample(self): if self.action.isChecked(): self.layer = self.iface.activeLayer() if (self.layer == None) or (type(self.layer) is not qgis._core.QgsVectorLayer): QMessageBox.about(None, '警告', 'ベクタレイヤを選択してから実行してください') self.action.setChecked(False) return self.previousMapTool = self.canvas.mapTool() self.canvas.setMapTool(self.mouseEventSample) self.canvas.mapToolSet.connect(self.unsetTool) self.iface.layerTreeView().currentLayerChanged.connect( self.changeLayer) # アクティブレイヤが変更された時に呼ぶメソッドを登録 self.mouseEventSample.setLayer(self.iface.activeLayer()) self.mouseEventSample.featureIdentified.connect(self.editAttribute) else: self.mouseEventSample.featureIdentified.disconnect( self.editAttribute) self.iface.layerTreeView().currentLayerChanged.disconnect( self.changeLayer) self.canvas.mapToolSet.disconnect(self.unsetTool) self.canvas.unsetMapTool(self.mouseEventSample) self.canvas.setMapTool(self.previousMapTool) # フューチャーを一つ選択した時に呼ばれる。 def editAttribute(self, feature): self.layer.removeSelection() self.layer.select(feature.id()) self.layer.startEditing() # レイヤを編集状態にする # 選択しているフューチャーの属性フォーム表示 self.attdlg = self.iface.getFeatureForm(self.layer, feature) self.attdlg.setMode(qgis.gui.QgsAttributeEditorContext.SingleEditMode) self.attdlg.finished.connect(self.commitEdit) self.attdlg.show() def commitEdit(self, result): if result == 1: self.layer.commitChanges() else: self.layer.rollBack() self.attdlg.finished.disconnect(self.commitEdit) # レイヤウィンドウでレイヤを選択したときに呼ばれる def changeLayer(self, layer): if (layer == None) or (type(layer) is not qgis.core.QgsVectorLayer): return self.layer.removeSelection() self.layer = layer self.mouseEventSample.setLayer(self.layer)
class SplitFeaturesOnSteroidsPlugin(object): mapTool = None def __init__(self, iface): self.iface = iface def initGui(self): self.toolbar = self.iface.addToolBar(name) self.toolbar.setObjectName(name) icon = QIcon(":/plugins/SplitPolygonShowingAreas/icon.png") self.action = QAction(icon, name, self.iface.mainWindow()) self.action.setCheckable(True) self.action.triggered.connect(self.onClick) self.toolbar.addAction(self.action) self.actionMoveVertices = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/moveVertices.png"), moveVerticesName, self.iface.mainWindow()) self.actionMoveVertices.setCheckable(True) self.actionMoveVertices.triggered.connect(self.onClickMoveVertices) self.toolbar.addAction(self.actionMoveVertices) self.actionAddVertices = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/addVertices.png"), addVerticesName, self.iface.mainWindow()) self.actionAddVertices.setCheckable(True) self.actionAddVertices.triggered.connect(self.onClickAddVertices) self.toolbar.addAction(self.actionAddVertices) self.actionRemoveVertices = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/removeVertices.png"), removeVerticesName, self.iface.mainWindow()) self.actionRemoveVertices.setCheckable(True) self.actionRemoveVertices.triggered.connect(self.onClickRemoveVertices) self.toolbar.addAction(self.actionRemoveVertices) self.actionMoveSegment = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/moveSegment.png"), moveSegmentName, self.iface.mainWindow()) self.actionMoveSegment.setCheckable(True) self.actionMoveSegment.triggered.connect(self.onClickMoveSegment) self.toolbar.addAction(self.actionMoveSegment) self.actionLineClose = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/lineClose.png"), closeLineName, self.iface.mainWindow()) self.actionLineClose.setCheckable(False) self.actionLineClose.triggered.connect(self.onClickLineClose) self.toolbar.addAction(self.actionLineClose) self.actionLineOpen = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/lineOpen.png"), openLineName, self.iface.mainWindow()) self.actionLineOpen.setCheckable(False) self.actionLineOpen.triggered.connect(self.onClickLineOpen) self.toolbar.addAction(self.actionLineOpen) self.actionMoveLine = QAction( QIcon(":/plugins/SplitPolygonShowingAreas/moveLine.png"), moveLineName, self.iface.mainWindow()) self.actionMoveLine.setCheckable(True) self.actionMoveLine.triggered.connect(self.onClickMoveLine) self.toolbar.addAction(self.actionMoveLine) self.iface.addPluginToMenu(name, self.action) self.iface.addPluginToMenu(name, self.actionMoveVertices) self.iface.addPluginToMenu(name, self.actionAddVertices) self.iface.addPluginToMenu(name, self.actionRemoveVertices) self.iface.addPluginToMenu(name, self.actionMoveSegment) self.iface.addPluginToMenu(name, self.actionLineClose) self.iface.addPluginToMenu(name, self.actionLineOpen) self.iface.addPluginToMenu(name, self.actionMoveLine) self.help_action = QAction("Help", self.iface.mainWindow()) self.help_action.triggered.connect(self.onHelp) self.iface.addPluginToMenu(name, self.help_action) self.iface.currentLayerChanged.connect(self.currentLayerChanged) self.enableTool() def disableAll(self): self.actionMoveVertices.setChecked(False) self.actionMoveVertices.setEnabled(False) self.actionAddVertices.setChecked(False) self.actionAddVertices.setEnabled(False) self.actionRemoveVertices.setChecked(False) self.actionRemoveVertices.setEnabled(False) self.actionMoveSegment.setChecked(False) self.actionMoveSegment.setEnabled(False) self.actionLineClose.setEnabled(False) self.actionLineOpen.setEnabled(False) self.actionMoveLine.setChecked(False) self.actionMoveLine.setEnabled(False) def unload(self): self.iface.removePluginMenu(name, self.action) self.iface.removePluginMenu(name, self.actionMoveVertices) self.iface.removePluginMenu(name, self.actionAddVertices) self.iface.removePluginMenu(name, self.actionRemoveVertices) self.iface.removePluginMenu(name, self.actionMoveSegment) self.iface.removePluginMenu(name, self.actionLineClose) self.iface.removePluginMenu(name, self.actionLineOpen) self.iface.removePluginMenu(name, self.actionMoveLine) self.iface.removePluginMenu(name, self.help_action) self.iface.removeToolBarIcon(self.action) self.iface.removeToolBarIcon(self.actionMoveVertices) self.iface.removeToolBarIcon(self.actionAddVertices) self.iface.removeToolBarIcon(self.actionRemoveVertices) self.iface.removeToolBarIcon(self.actionMoveSegment) self.iface.removeToolBarIcon(self.actionLineClose) self.iface.removeToolBarIcon(self.actionLineOpen) self.iface.removeToolBarIcon(self.actionMoveLine) def onHelp(self): qgis.utils.showPluginHelp(filename="index") def onClick(self): self.disableAll() if not self.action.isChecked(): if self.mapTool != None and len(self.mapTool.capturedPoints) >= 2: reply = QMessageBox.question( self.iface.mapCanvas(), "Cancel splitting line?", "Your splitting line has " + str(len(self.mapTool.capturedPoints)) + " points. Do you want to remove it?", QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.No: self.action.setChecked(True) self.mapTool.restoreAction() return if self.mapTool != None: self.mapTool.stopCapturing() self.iface.mapCanvas().unsetMapTool(self.mapTool) self.mapTool = None return layer = self.iface.activeLayer() if layer == None or not isinstance(layer, QgsVectorLayer) or ( layer.wkbType() != QgsWkbTypes.Polygon and layer.wkbType() != QgsWkbTypes.MultiPolygon and layer.wkbType() != QgsWkbTypes.Polygon25D and layer.wkbType() != QgsWkbTypes.MultiPolygon25D): self.iface.messageBar().pushMessage( "No Polygon Vectorial Layer Selected", "Select a Polygon Vectorial Layer first", level=QgsMessageBar.WARNING) self.action.setChecked(False) return selectedFeatures = layer.selectedFeatures() if selectedFeatures == None or len(selectedFeatures) == 0: self.iface.messageBar().pushMessage("No Features Selected", "Select some features first", level=QgsMessageBar.WARNING) self.action.setChecked(False) return self.action.setChecked(True) self.mapTool = SplitMapTool( self.iface.mapCanvas(), layer, self.actionMoveVertices, self.actionAddVertices, self.actionRemoveVertices, self.actionMoveSegment, self.actionLineClose, self.actionLineOpen, self.actionMoveLine) self.mapTool.setAction(self.action) self.iface.mapCanvas().setMapTool(self.mapTool) self.mapTool.redrawActions() def onClickMoveVertices(self): if not self.actionMoveVertices.isChecked(): if self.mapTool != None: self.mapTool.stopMovingVertices() return self.mapTool.startMovingVertices() def onClickAddVertices(self): if not self.actionAddVertices.isChecked(): if self.mapTool != None: self.mapTool.stopAddingVertices() return self.actionAddVertices.setChecked(True) self.mapTool.startAddingVertices() def onClickRemoveVertices(self): if not self.actionRemoveVertices.isChecked(): if self.mapTool != None: self.mapTool.stopRemovingVertices() return self.actionRemoveVertices.setChecked(True) self.mapTool.startRemovingVertices() def onClickMoveSegment(self): if not self.actionMoveSegment.isChecked(): if self.mapTool != None: self.mapTool.stopMovingSegment() return self.actionMoveSegment.setChecked(True) self.mapTool.startMovingSegment() def onClickLineClose(self): self.mapTool.lineClose() def onClickLineOpen(self): self.mapTool.lineOpen() def onClickMoveLine(self): if not self.actionMoveLine.isChecked(): if self.mapTool != None: self.mapTool.stopMovingLine() return self.actionMoveLine.setChecked(True) self.mapTool.startMovingLine() def currentLayerChanged(self): if self.mapTool != None: self.mapTool.stopCapturing() layer = self.iface.activeLayer() if layer != None: try: layer.editingStarted.disconnect(self.layerEditingChanged) except: pass try: layer.editingStopped.disconnect(self.layerEditingChanged) except: pass try: layer.selectionChanged.disconnect(self.layerEditingChanged) except: pass if isinstance(layer, QgsVectorLayer): layer.editingStarted.connect(self.layerEditingChanged) layer.editingStopped.connect(self.layerEditingChanged) layer.selectionChanged.connect(self.layerSelectionChanged) self.enableTool() def layerEditingChanged(self): if self.mapTool != None: self.mapTool.stopCapturing() self.enableTool() def layerSelectionChanged(self): if self.mapTool != None: self.mapTool.stopCapturing() self.enableTool() def enableTool(self): self.disableAll() self.action.setEnabled(False) layer = self.iface.activeLayer() if layer != None and isinstance(layer, QgsVectorLayer): selectedFeatures = layer.selectedFeatures() if isinstance(layer, QgsVectorLayer) and ( layer.wkbType() == QgsWkbTypes.Polygon or layer.wkbType() == QgsWkbTypes.MultiPolygon or layer.wkbType() == QgsWkbTypes.Polygon25D or layer.wkbType() == QgsWkbTypes.MultiPolygon25D ) and selectedFeatures != None and len( selectedFeatures) > 0 and layer.isEditable(): self.action.setEnabled(True)
class ProcessingPlugin(QObject): def __init__(self, iface): super().__init__() self.iface = iface self.options_factory = None self.drop_handler = None self.item_provider = None self.locator_filter = None self.edit_features_locator_filter = None self.initialized = False self.initProcessing() def initProcessing(self): if not self.initialized: self.initialized = True Processing.initialize() def initGui(self): # port old log, ONCE ONLY! settings = QgsSettings() if not settings.value("/Processing/hasPortedOldLog", False, bool): processing_history_provider = QgsGui.historyProviderRegistry().providerById('processing') if processing_history_provider: processing_history_provider.portOldLog() settings.setValue("/Processing/hasPortedOldLog", True) self.options_factory = ProcessingOptionsFactory() self.options_factory.setTitle(self.tr('Processing')) iface.registerOptionsWidgetFactory(self.options_factory) self.drop_handler = ProcessingDropHandler() iface.registerCustomDropHandler(self.drop_handler) self.item_provider = ProcessingDataItemProvider() QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider) self.locator_filter = AlgorithmLocatorFilter() iface.registerLocatorFilter(self.locator_filter) # Invalidate the locator filter for in-place when active layer changes iface.currentLayerChanged.connect(lambda _: self.iface.invalidateLocatorResults()) self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter() iface.registerLocatorFilter(self.edit_features_locator_filter) self.toolbox = ProcessingToolbox() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.toolbox) self.toolbox.hide() self.toolbox.visibilityChanged.connect(self.toolboxVisibilityChanged) self.toolbox.executeWithGui.connect(self.executeAlgorithm) self.resultsDock = ResultsDock() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.resultsDock) self.resultsDock.hide() self.menu = QMenu(self.iface.mainWindow().menuBar()) self.menu.setObjectName('processing') self.menu.setTitle(self.tr('Pro&cessing')) self.toolboxAction = QAction(self.tr('&Toolbox'), self.iface.mainWindow()) self.toolboxAction.setCheckable(True) self.toolboxAction.setObjectName('toolboxAction') self.toolboxAction.setIcon( QgsApplication.getThemeIcon("/processingAlgorithm.svg")) self.iface.registerMainWindowAction(self.toolboxAction, QKeySequence('Ctrl+Alt+T').toString(QKeySequence.NativeText)) self.toolboxAction.toggled.connect(self.openToolbox) self.iface.attributesToolBar().insertAction(self.iface.actionOpenStatisticalSummary(), self.toolboxAction) self.menu.addAction(self.toolboxAction) self.modelerAction = QAction( QgsApplication.getThemeIcon("/processingModel.svg"), QCoreApplication.translate('ProcessingPlugin', '&Graphical Modeler…'), self.iface.mainWindow()) self.modelerAction.setObjectName('modelerAction') self.modelerAction.triggered.connect(self.openModeler) self.iface.registerMainWindowAction(self.modelerAction, QKeySequence('Ctrl+Alt+G').toString(QKeySequence.NativeText)) self.menu.addAction(self.modelerAction) self.historyAction = QAction( QgsApplication.getThemeIcon("/mIconHistory.svg"), QCoreApplication.translate('ProcessingPlugin', '&History…'), self.iface.mainWindow()) self.historyAction.setObjectName('historyAction') self.historyAction.triggered.connect(self.openHistory) self.iface.registerMainWindowAction(self.historyAction, QKeySequence('Ctrl+Alt+H').toString(QKeySequence.NativeText)) self.menu.addAction(self.historyAction) self.toolbox.processingToolbar.addAction(self.historyAction) self.resultsAction = QAction( QgsApplication.getThemeIcon("/processingResult.svg"), self.tr('&Results Viewer'), self.iface.mainWindow()) self.resultsAction.setObjectName('resultsViewer') self.resultsAction.setCheckable(True) self.iface.registerMainWindowAction(self.resultsAction, QKeySequence('Ctrl+Alt+R').toString(QKeySequence.NativeText)) self.menu.addAction(self.resultsAction) self.toolbox.processingToolbar.addAction(self.resultsAction) self.resultsDock.visibilityChanged.connect(self.resultsAction.setChecked) self.resultsAction.toggled.connect(self.resultsDock.setUserVisible) self.toolbox.processingToolbar.addSeparator() self.editInPlaceAction = QAction( QgsApplication.getThemeIcon("/mActionProcessSelected.svg"), self.tr('Edit Features In-Place'), self.iface.mainWindow()) self.editInPlaceAction.setObjectName('editInPlaceFeatures') self.editInPlaceAction.setCheckable(True) self.editInPlaceAction.toggled.connect(self.editSelected) self.menu.addAction(self.editInPlaceAction) self.toolbox.processingToolbar.addAction(self.editInPlaceAction) self.toolbox.processingToolbar.addSeparator() self.optionsAction = QAction( QgsApplication.getThemeIcon("/mActionOptions.svg"), self.tr('Options'), self.iface.mainWindow()) self.optionsAction.setObjectName('optionsAction') self.optionsAction.triggered.connect(self.openProcessingOptions) self.toolbox.processingToolbar.addAction(self.optionsAction) menuBar = self.iface.mainWindow().menuBar() menuBar.insertMenu( self.iface.firstRightStandardMenu().menuAction(), self.menu) self.menu.addSeparator() initializeMenus() createMenus() createButtons() # In-place editing button state sync self.iface.currentLayerChanged.connect(self.sync_in_place_button_state) self.iface.mapCanvas().selectionChanged.connect(self.sync_in_place_button_state) self.iface.actionToggleEditing().triggered.connect(partial(self.sync_in_place_button_state, None)) self.sync_in_place_button_state() # Sync project models self.projectModelsMenu = None self.projectMenuAction = None self.projectMenuSeparator = None self.projectProvider = QgsApplication.instance().processingRegistry().providerById("project") self.projectProvider.algorithmsLoaded.connect(self.updateProjectModelMenu) def updateProjectModelMenu(self): """Add projects models to menu""" if self.projectMenuAction is None: self.projectModelsMenu = QMenu(self.tr("Models")) self.projectMenuAction = self.iface.projectMenu().insertMenu(self.iface.projectMenu().children()[-1], self.projectModelsMenu) self.projectMenuAction.setParent(self.projectModelsMenu) self.iface.projectMenu().insertSeparator(self.projectMenuAction) self.projectModelsMenu.clear() for model in self.projectProvider.algorithms(): modelSubMenu = self.projectModelsMenu.addMenu(model.name()) modelSubMenu.setParent(self.projectModelsMenu) action = QAction(self.tr("Execute…"), modelSubMenu) action.triggered.connect(partial(self.executeAlgorithm, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode)) modelSubMenu.addAction(action) if model.flags() & QgsProcessingAlgorithm.FlagSupportsBatch: action = QAction(self.tr("Execute as Batch Process…"), modelSubMenu) modelSubMenu.addAction(action) action.triggered.connect(partial(self.executeAlgorithm, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode, True)) @pyqtSlot(str, QWidget, bool, bool) def executeAlgorithm(self, alg_id, parent, in_place=False, as_batch=False): """Executes a project model with GUI interaction if needed. :param alg_id: algorithm id :type alg_id: string :param parent: parent widget :type parent: QWidget :param in_place: in place flag, defaults to False :type in_place: bool, optional :param as_batch: execute as batch flag, defaults to False :type as_batch: bool, optional """ config = {} if in_place: config['IN_PLACE'] = True alg = QgsApplication.instance().processingRegistry().createAlgorithmById(alg_id, config) if alg is not None: ok, message = alg.canExecute() if not ok: dlg = MessageDialog() dlg.setTitle(self.tr('Error executing algorithm')) dlg.setMessage( self.tr('<h3>This algorithm cannot ' 'be run :-( </h3>\n{0}').format(message)) dlg.exec_() return if as_batch: dlg = BatchAlgorithmDialog(alg, iface.mainWindow()) dlg.show() dlg.exec_() else: in_place_input_parameter_name = 'INPUT' if hasattr(alg, 'inputParameterName'): in_place_input_parameter_name = alg.inputParameterName() if in_place and not [d for d in alg.parameterDefinitions() if d.name() not in (in_place_input_parameter_name, 'OUTPUT')]: parameters = {} feedback = MessageBarProgress(algname=alg.displayName()) ok, results = execute_in_place(alg, parameters, feedback=feedback) if ok: iface.messageBar().pushSuccess('', self.tr('{algname} completed. %n feature(s) processed.', n=results['__count']).format(algname=alg.displayName())) feedback.close() # MessageBarProgress handles errors return if alg.countVisibleParameters() > 0: dlg = alg.createCustomParametersWidget(parent) if not dlg: dlg = AlgorithmDialog(alg, in_place, iface.mainWindow()) canvas = iface.mapCanvas() prevMapTool = canvas.mapTool() dlg.show() dlg.exec_() if canvas.mapTool() != prevMapTool: try: canvas.mapTool().reset() except Exception: pass canvas.setMapTool(prevMapTool) else: feedback = MessageBarProgress(algname=alg.displayName()) context = dataobjects.createContext(feedback) parameters = {} ret, results = execute(alg, parameters, context, feedback) handleAlgorithmResults(alg, context, feedback) feedback.close() def sync_in_place_button_state(self, layer=None): """Synchronise the button state with layer state""" if layer is None: layer = self.iface.activeLayer() old_enabled_state = self.editInPlaceAction.isEnabled() new_enabled_state = layer is not None and layer.type() == QgsMapLayerType.VectorLayer self.editInPlaceAction.setEnabled(new_enabled_state) if new_enabled_state != old_enabled_state: self.toolbox.set_in_place_edit_mode(new_enabled_state and self.editInPlaceAction.isChecked()) def openProcessingOptions(self): self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions') def unload(self): self.toolbox.setVisible(False) self.iface.removeDockWidget(self.toolbox) self.iface.attributesToolBar().removeAction(self.toolboxAction) self.resultsDock.setVisible(False) self.iface.removeDockWidget(self.resultsDock) self.toolbox.deleteLater() self.menu.deleteLater() # also delete temporary help files folder = tempHelpFolder() if QDir(folder).exists(): shutil.rmtree(folder, True) self.iface.unregisterMainWindowAction(self.toolboxAction) self.iface.unregisterMainWindowAction(self.modelerAction) self.iface.unregisterMainWindowAction(self.historyAction) self.iface.unregisterMainWindowAction(self.resultsAction) self.iface.unregisterOptionsWidgetFactory(self.options_factory) self.iface.deregisterLocatorFilter(self.locator_filter) self.iface.deregisterLocatorFilter(self.edit_features_locator_filter) self.iface.unregisterCustomDropHandler(self.drop_handler) QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider) removeButtons() removeMenus() if self.projectMenuAction is not None: self.iface.projectMenu().removeAction(self.projectMenuAction) self.projectMenuAction = None if self.projectMenuSeparator is not None: self.iface.projectMenu().removeAction(self.projectMenuSeparator) self.projectMenuSeparator = None Processing.deinitialize() def openToolbox(self, show): self.toolbox.setUserVisible(show) def toolboxVisibilityChanged(self, visible): self.toolboxAction.setChecked(visible) def openModeler(self): dlg = ModelerDialog.create() dlg.update_model.connect(self.updateModel) dlg.show() def updateModel(self): model_provider = QgsApplication.processingRegistry().providerById('model') model_provider.refreshAlgorithms() def openResults(self): if self.resultsDock.isVisible(): self.resultsDock.hide() else: self.resultsDock.show() def openHistory(self): dlg = HistoryDialog() dlg.exec_() def tr(self, message, disambiguation=None, n=-1): return QCoreApplication.translate('ProcessingPlugin', message, disambiguation=disambiguation, n=n) def editSelected(self, enabled): self.toolbox.set_in_place_edit_mode(enabled)
class LockZoomToTiles: def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() self.epsg3857 = QgsCoordinateReferenceSystem('EPSG:3857') self.epsg4326 = QgsCoordinateReferenceSystem('EPSG:4326') self.islocking = False def initGui(self): '''Initialize Lock Zoom to Tiles GUI.''' icon = QIcon() icon.addFile(os.path.dirname(__file__) + "/images/zoomUnlocked.svg", state=QIcon.Off) icon.addFile(os.path.dirname(__file__) + "/images/zoomLocked.svg", state=QIcon.On) self.action = QAction(icon, "Lock zoom scale", self.iface.mainWindow()) self.action.setObjectName('lockZoom') self.action.triggered.connect(self.lockIt) self.action.setCheckable(True) self.iface.addPluginToMenu("Lock zoom to tile scale", self.action) self.iface.addToolBarIcon(self.action) icon = QIcon(os.path.dirname(__file__) + '/images/help.svg') self.helpAction = QAction(icon, "Help", self.iface.mainWindow()) self.helpAction.triggered.connect(self.help) self.iface.addPluginToMenu('Lock zoom to tile scale', self.helpAction) self.checkCrs() self.canvas.destinationCrsChanged.connect(self.checkCrs) self.canvas.layersChanged.connect(self.checkCrs) def unload(self): '''Unload from the QGIS interface''' self.iface.removePluginMenu('Lock zoom to tile scale', self.action) self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu("Lock zoom to tile scale", self.helpAction) self.canvas.destinationCrsChanged.disconnect(self.checkCrs) if self.islocking == True: try: self.canvas.scaleChanged.disconnect(self.lockIt) except Exception: pass def help(self): '''Display a help page''' url = QUrl.fromLocalFile(os.path.dirname(__file__) + "/index.html").toString() webbrowser.open(url, new=2) def lockIt(self): '''Set the focus of the copy coordinate tool''' if self.action.isChecked(): self.zoomTo() if self.islocking == False: self.islocking = True self.canvas.scaleChanged.connect(self.zoomTo) self.action.setText("Unlock zoom scale") self.action.setIconText("Unlock zoom scale") else: if self.islocking == True: self.canvas.scaleChanged.disconnect(self.zoomTo) self.islocking = False self.action.setText("Lock zoom scale") self.action.setIconText("Lock zoom scale") def zoomTo(self): crs = self.canvas.mapSettings().destinationCrs() mupp = self.canvas.mapUnitsPerPixel() if crs == self.epsg3857: r = 0 for i in range(0, len(r3857)): r = i if r3857[i] > mupp: if i > 0 and (r3857[i]-mupp > mupp-r3857[i-1]): r = i-1 break if not math.isclose(r3857[r], mupp, rel_tol=1e-5): self.canvas.zoomByFactor(r3857[r] / self.canvas.mapUnitsPerPixel()) else: r = 0 for i in range(0, len(r4326)): r = i if r4326[i] > mupp: if i > 0 and (r4326[i]-mupp > mupp-r4326[i-1]): r = i-1 break if not math.isclose(r4326[r], mupp, rel_tol=1e-5): self.canvas.zoomByFactor(r4326[r] / self.canvas.mapUnitsPerPixel()) def checkCrs(self): crs = self.canvas.mapSettings().destinationCrs() numlayers = self.canvas.layerCount() if (crs == self.epsg3857 or crs == self.epsg4326) and numlayers > 0: self.action.setEnabled(True) else: self.action.setEnabled(False) self.action.setChecked(False) self.lockIt()
class PhotoViewer(QScrollArea): """ Widget for viewing images by incorporating basic navigation options. """ def __init__(self, parent=None, photo_path=""): QScrollArea.__init__(self, parent) self.setBackgroundRole(QPalette.Dark) self._printer = QPrinter() self._lbl_photo = QLabel() self._lbl_photo.setBackgroundRole(QPalette.Base) self._lbl_photo.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self._lbl_photo.setScaledContents(True) self.setWidget(self._lbl_photo) self._photo_path = photo_path self._ph_image = None self._scale_factor = 1.0 self._aspect_ratio = -1 self._create_actions() if self._photo_path: self.load_document(self._photo_path) def _create_actions(self): """ Create actions for basic image navigation. """ self._zoom_in_act = QAction( QApplication.translate("PhotoViewer", "Zoom &In (25%)"), self) self._zoom_in_act.setShortcut( QApplication.translate("PhotoViewer", "Ctrl++")) self._zoom_in_act.setEnabled(False) self._zoom_in_act.triggered.connect(self.zoom_in) self._zoom_out_act = QAction( QApplication.translate("PhotoViewer", "Zoom &Out (25%)"), self) self._zoom_out_act.setShortcut( QApplication.translate("PhotoViewer", "Ctrl+-")) self._zoom_out_act.setEnabled(False) self._zoom_out_act.triggered.connect(self.zoom_out) self._normal_size_act = QAction( QApplication.translate("PhotoViewer", "&Normal Size"), self) self._normal_size_act.setShortcut( QApplication.translate("PhotoViewer", "Ctrl+S")) self._normal_size_act.setEnabled(False) self._normal_size_act.triggered.connect(self.normal_size) self._fit_to_window_act = QAction( QApplication.translate("PhotoViewer", "&Fit to Window"), self) self._fit_to_window_act.setShortcut( QApplication.translate("PhotoViewer", "Ctrl+F")) self._fit_to_window_act.setEnabled(False) self._fit_to_window_act.setCheckable(True) self._fit_to_window_act.triggered.connect(self.fit_to_window) self._print_act = QAction( QApplication.translate("PhotoViewer", "&Print"), self) self._print_act.setShortcut( QApplication.translate("PhotoViewer", "Ctrl+P")) self._print_act.setEnabled(False) self._print_act.triggered.connect(self.print_photo) def zoom_in(self): self.scale_photo(1.25) def zoom_out(self): self.scale_photo(0.8) def normal_size(self): self._lbl_photo.adjustSize() self._scale_factor = 1.0 def fit_to_window(self): fit_to_win = self._fit_to_window_act.isChecked() self.setWidgetResizable(fit_to_win) if not fit_to_win: self.normal_size() self.update_actions() def print_photo(self): print_dialog = QPrintDialog(self._printer, self) if print_dialog.exec_() == QDialog.Accepted: painter = QPainter(self._printer) rect = painter.viewport() size = self._lbl_photo.pixmap().size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.setWindow(self._lbl_photo.pixmap().rect()) painter.drawPixmap(0, 0, self._lbl_photo.pixmap()) def wheelEvent(self, event): """ Zoom the image based on the mouse wheel rotation action. :param event: Event containing the wheel rotation info. :type event: QWheelEvent """ degrees = event.delta() / 8 num_steps = degrees / 15 if num_steps < 0: abs_num_steps = abs(num_steps) zoom_factor = 1 + (abs_num_steps * 0.25) else: zoom_factor = 1 - (num_steps * 0.2) self.scale_photo(zoom_factor) def heightForWidth(self, width): if self._aspect_ratio != -1: return width / self._aspect_ratio else: return -1 def resizeEvent(self, event): """ Event for resizing the widget based on the pixmap's aspect ratio. :param event: Contains event parameters for the resize event. :type event: QResizeEvent """ super(PhotoViewer, self).resizeEvent(event) def update_actions(self): self._zoom_out_act.setEnabled(not self._fit_to_window_act.isChecked()) self._zoom_in_act.setEnabled(not self._fit_to_window_act.isChecked()) self._normal_size_act.setEnabled( not self._fit_to_window_act.isChecked()) def scale_photo(self, factor): """ :param factor: Value by which the image will be increased/decreased in the view. :type factor: float """ if not self._lbl_photo.pixmap().isNull(): self._scale_factor *= factor self._lbl_photo.resize(self._scale_factor * self._lbl_photo.pixmap().size()) self._adjust_scroll_bar(self.horizontalScrollBar(), factor) self._adjust_scroll_bar(self.verticalScrollBar(), factor) self._zoom_in_act.setEnabled(self._scale_factor < 3.0) self._zoom_out_act.setEnabled(self._scale_factor > 0.333) def _adjust_scroll_bar(self, scroll_bar, factor): scroll_bar.setValue( int(factor * scroll_bar.value() + ((factor - 1) * scroll_bar.pageStep() / 2))) def load_document(self, photo_path): if photo_path: self._ph_image = QImage(photo_path) if self._ph_image.isNull(): return False self._photo_path = photo_path ph_pixmap = QPixmap.fromImage(self._ph_image) self._lbl_photo.setPixmap(ph_pixmap) self._scale_factor = 1.0 self._aspect_ratio = ph_pixmap.width() / ph_pixmap.height() self._fit_to_window_act.setEnabled(True) self._print_act.setEnabled(True) self._fit_to_window_act.trigger() self.update_actions() return ph_pixmap return True def photo_location(self): """ :returns: Absolute path of the photo in the central document repository. """ return self._photo_path def set_actions(self, menu): """ Add custom actions to the sub-window menu """ menu.addSeparator() menu.addAction(self._zoom_in_act) menu.addAction(self._zoom_out_act) menu.addAction(self._normal_size_act) menu.addAction(self._fit_to_window_act) menu.addSeparator() menu.addAction(self._print_act)
class BulkLoadFrame(QFrame, FORM_CLASS): """Bulk Load outlines frame class""" closed = pyqtSignal() def __init__(self, dockwidget, parent=None): """Constructor.""" super(BulkLoadFrame, self).__init__(parent) self.setupUi(self) # Frame fields self.dockwidget = dockwidget self.layer_registry = LayerRegistry() # Set up pop-up dialog self.check_dialog = CheckDialog() self.error_dialog = None self.edit_dialog = None # bulk load changes instance self.change_instance = None # layer set up self.historic_layer = None self.bulk_load_layer = None # database setup self.db = db db.connect() # selection colour iface.mapCanvas().setSelectionColor(QColor("Yellow")) # set up confirmation message box self.msgbox_bulk_load = self.confirmation_dialog_box("bulk load") self.msgbox_compare = self.confirmation_dialog_box("compare") self.msgbox_publish = self.confirmation_dialog_box("publish") self.grpb_layers.hide() # Find current supplied dataset result = self.db._execute( bulk_load_select.supplied_dataset_count_processed_date_is_null) result = result.fetchall()[0][0] # if there is an unprocessed dataset if result > 1: # error self.error_dialog = ErrorDialog() self.error_dialog.fill_report( "\n ---------------------- DATASET ERROR ---------" "----------------- \n\nThere are multiple not processed" " datasets. Please fix database tables before continuing") self.error_dialog.show() self.display_dataset_error() elif result == 1: p_result = self.db._execute( bulk_load_select.supplied_dataset_processed_date_is_null) self.current_dataset = p_result.fetchall()[0][0] self.lb_dataset_id.setText(str(self.current_dataset)) self.add_outlines() self.display_current_bl_not_compared() self.grpb_layers.show() # Setup edit dialog self.edit_dialog = EditDialog(self) # if all datasets are processed else: result2 = self.db._execute( bulk_load_select.supplied_dataset_count_transfer_date_is_null) result2 = result2.fetchall()[0][0] # if there is a processed but not transferred dataset if result > 1: # error self.error_dialog = ErrorDialog() self.error_dialog.fill_report( "\n ---------------------- DATASET ERROR ---------" "----------------- \n\nThere are multiple not transferred" " datasets. Please fix database tables before continuing") self.error_dialog.show() self.display_dataset_error() elif result2 == 1: t_result = self.db._execute( bulk_load_select.supplied_dataset_transfer_date_is_null) self.current_dataset = t_result.fetchall()[0][0] self.lb_dataset_id.setText(str(self.current_dataset)) self.add_outlines() self.display_not_published() self.grpb_layers.show() # Setup edit dialog self.edit_dialog = EditDialog(self) # No current dataset is being worked on else: self.current_dataset = None self.lb_dataset_id.setText("None") self.display_no_bulk_load() self.cmb_capture_src_grp.currentIndexChanged.connect( self.cmb_capture_src_grp_changed) # initiate le_data_description self.le_data_description.setMaxLength(250) self.le_data_description.setPlaceholderText("Data Description") # set up signals and slots self.rad_external_id.toggled.connect( partial(bulk_load.enable_external_bulk, self)) self.ml_outlines_layer.currentIndexChanged.connect( partial(bulk_load.populate_external_fcb, self)) self.btn_bl_save.clicked.connect( partial(self.bulk_load_save_clicked, True)) self.btn_bl_reset.clicked.connect(self.bulk_load_reset_clicked) self.btn_compare_outlines.clicked.connect( partial(self.compare_outlines_clicked, True)) self.btn_alter_rel.clicked.connect(self.alter_relationships_clicked) self.btn_publish.clicked.connect(partial(self.publish_clicked, True)) self.btn_exit.clicked.connect(self.exit_clicked) self.cb_bulk_load.clicked.connect(self.cb_bulk_load_clicked) self.cb_removed.clicked.connect(self.cb_removed_clicked) self.cb_added.clicked.connect(self.cb_added_clicked) QgsProject.instance().layerWillBeRemoved.connect(self.layers_removed) def confirmation_dialog_box(self, button_text): return QMessageBox( QMessageBox.Question, button_text.upper(), "Are you sure you want to %s outlines?" % button_text, buttons=QMessageBox.No | QMessageBox.Yes, ) def confirm(self, msgbox): reply = msgbox.exec_() if reply == QMessageBox.Yes: return True return False def setup_toolbar(self): if "Add Outline" not in ( action.text() for action in iface.building_toolbar.actions()): image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "plus.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.add_action = QAction(icon, "Add Outline", iface.building_toolbar) iface.registerMainWindowAction(self.add_action, "Ctrl+1") self.add_action.triggered.connect(self.canvas_add_outline) iface.building_toolbar.addAction(self.add_action) if "Edit Geometry" not in ( action.text() for action in iface.building_toolbar.actions()): image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "edit_geometry.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.edit_geom_action = QAction(icon, "Edit Geometry", iface.building_toolbar) iface.registerMainWindowAction(self.edit_geom_action, "Ctrl+2") self.edit_geom_action.triggered.connect(self.canvas_edit_geometry) iface.building_toolbar.addAction(self.edit_geom_action) if "Edit Attributes" not in ( action.text() for action in iface.building_toolbar.actions()): image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "edit_attributes.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.edit_attrs_action = QAction(icon, "Edit Attributes", iface.building_toolbar) iface.registerMainWindowAction(self.edit_attrs_action, "Ctrl+3") self.edit_attrs_action.triggered.connect( self.canvas_edit_attribute) iface.building_toolbar.addAction(self.edit_attrs_action) iface.building_toolbar.show() def display_dataset_error(self): """UI Display when there are multiple supplied datasets.""" self.current_dataset = None self.lb_dataset_id.setText("None") self.grpb_bulk_load.hide() iface.building_toolbar.hide() self.btn_compare_outlines.setDisabled(1) self.btn_alter_rel.setDisabled(1) self.btn_publish.setDisabled(1) def display_no_bulk_load(self): """UI Display When there is no Current dataset.""" self.grpb_bulk_load.show() bulk_load.populate_bulk_comboboxes(self) self.ml_outlines_layer.setEnabled(1) self.rad_external_id.setEnabled(1) self.rad_external_id.setChecked(False) self.fcb_external_id.setDisabled(1) self.cmb_capture_src_grp.setEnabled(1) self.cmb_capture_src_grp.setCurrentIndex(0) self.cmb_cap_src_area.setEnabled(1) self.le_data_description.setEnabled(1) self.le_data_description.clear() self.cmb_capture_method.setEnabled(1) self.cmb_capture_method.setCurrentIndex(0) self.cmb_organisation.setEnabled(1) self.cmb_organisation.setCurrentIndex(0) self.btn_bl_save.show() self.btn_bl_reset.show() self.current_dataset = None self.lb_dataset_id.setText("None") self.btn_compare_outlines.setDisabled(1) self.btn_alter_rel.setDisabled(1) self.btn_publish.setDisabled(1) self.add_historic_outlines() self.l_cs_area_title.setText("") iface.building_toolbar.hide() def display_data_exists(self): """ Display setup when data has been bulk loaded - subfunction of: display_not_published & display_current_bl_not_compared """ bulk_load.populate_bulk_comboboxes(self) bulk_load.load_current_fields(self) self.grpb_bulk_load.show() self.ml_outlines_layer.setDisabled(1) self.rad_external_id.setDisabled(1) self.fcb_external_id.setDisabled(1) self.cmb_capture_src_grp.setDisabled(1) self.cmb_cap_src_area.setDisabled(1) self.le_data_description.setDisabled(1) self.cmb_capture_method.setDisabled(1) self.cmb_organisation.setDisabled(1) self.btn_bl_save.hide() self.btn_bl_reset.hide() sql = reference_select.capture_source_area_name_by_supplied_dataset area_id = self.db._execute(sql, (self.current_dataset, )) area_id = area_id.fetchall() if area_id is not None: self.l_cs_area_title.setText(area_id[0][0]) else: self.l_cs_area_title.setText("") def display_not_published(self): """ UI display when there is a dataset that hasn't been published. """ self.display_data_exists() self.btn_compare_outlines.setDisabled(1) self.btn_publish.setEnabled(1) self.setup_toolbar() def display_current_bl_not_compared(self): """ UI Display when there is a dataset that hasn't been compared. """ self.display_data_exists() self.btn_compare_outlines.setEnabled(1) sql = reference_select.capture_source_area_name_by_supplied_dataset area_id = self.db._execute(sql, (self.current_dataset, )) if area_id is not None: self.area_id = area_id.fetchall() if len(self.area_id) > 0: self.area_id = self.area_id[0][0] self.l_cs_area_title.setText(self.area_id) else: self.area_id = None self.l_cs_area_title.setText("") self.error_dialog = ErrorDialog() self.error_dialog.fill_report( "\n ---------------------- NO CAPTURE SOURCE AREA ---------" "----------------- \n\nThere is no area id, please fix in database" ) self.error_dialog.show() self.display_dataset_error() self.btn_compare_outlines.setDisabled(1) return self.btn_alter_rel.setDisabled(1) self.btn_publish.setDisabled(1) self.setup_toolbar() def add_outlines(self): """ Add bulk load outlines of current dataset to canvas. """ path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "styles/") # add the bulk_load_outlines to the layer registry self.bulk_load_layer = self.layer_registry.add_postgres_layer( "bulk_load_outlines", "bulk_load_outlines", "shape", "buildings_bulk_load", "", "supplied_dataset_id = {0}".format(self.current_dataset), ) self.bulk_load_layer.loadNamedStyle(path + "building_editing.qml") iface.setActiveLayer(self.bulk_load_layer) def add_historic_outlines(self): path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "styles/") self.historic_layer = self.layer_registry.add_postgres_layer( "loaded_datasets", "bulk_load_outlines", "shape", "buildings_bulk_load", "", "") self.historic_layer.loadNamedStyle(path + "building_historic.qml") @pyqtSlot(int) def cmb_capture_src_grp_changed(self, index): self.cmb_cap_src_area.clear() id_capture_src_grp = self.ids_capture_src_grp[index] result = self.db._execute( common_select. capture_source_external_id_and_area_title_by_group_id, (id_capture_src_grp, )) ls = result.fetchall() for (external_id, area_title) in reversed(ls): text = external_id + "- " + area_title self.cmb_cap_src_area.addItem(text) @pyqtSlot(bool) def cb_bulk_load_clicked(self, checked): layer_tree_layer = QgsProject.instance().layerTreeRoot().findLayer( self.bulk_load_layer.id()) layer_tree_model = iface.layerTreeView().model() categories = layer_tree_model.layerLegendNodes(layer_tree_layer) bulk_category = [ ln for ln in categories if ln.data(Qt.DisplayRole) == "Bulk Loaded" ] if checked: bulk_category[0].setData(Qt.Checked, Qt.CheckStateRole) else: bulk_category[0].setData(Qt.Unchecked, Qt.CheckStateRole) @pyqtSlot(bool) def cb_added_clicked(self, checked): layer_tree_layer = QgsProject.instance().layerTreeRoot().findLayer( self.bulk_load_layer.id()) layer_tree_model = iface.layerTreeView().model() categories = layer_tree_model.layerLegendNodes(layer_tree_layer) added_category = [ ln for ln in categories if ln.data(Qt.DisplayRole) == "Added During QA" ] added_edit_category = [ ln for ln in categories if ln.data(Qt.DisplayRole) == "Added- to be saved" ] if checked: added_category[0].setData(Qt.Checked, Qt.CheckStateRole) added_edit_category[0].setData(Qt.Checked, Qt.CheckStateRole) else: added_category[0].setData(Qt.Unchecked, Qt.CheckStateRole) added_edit_category[0].setData(Qt.Unchecked, Qt.CheckStateRole) @pyqtSlot(bool) def cb_removed_clicked(self, checked): layer_tree_layer = QgsProject.instance().layerTreeRoot().findLayer( self.bulk_load_layer.id()) layer_tree_model = iface.layerTreeView().model() categories = layer_tree_model.layerLegendNodes(layer_tree_layer) removed_category = [ ln for ln in categories if ln.data(Qt.DisplayRole) == "Removed During QA" ] if checked: removed_category[0].setData(Qt.Checked, Qt.CheckStateRole) else: removed_category[0].setData(Qt.Unchecked, Qt.CheckStateRole) @pyqtSlot(bool) def bulk_load_save_clicked(self, commit_status): """ When bulk load outlines save clicked """ if self.confirm(self.msgbox_bulk_load): QApplication.setOverrideCursor(Qt.WaitCursor) bulk_load.bulk_load(self, commit_status) # find if adding was successful result = self.db._execute( bulk_load_select.supplied_dataset_count_both_dates_are_null) result = result.fetchall()[0][0] # if bulk loading completed without errors if result == 1: QgsProject.instance().layerWillBeRemoved.disconnect( self.layers_removed) self.layer_registry.remove_layer(self.historic_layer) QgsProject.instance().layerWillBeRemoved.connect( self.layers_removed) self.cmb_capture_src_grp.currentIndexChanged.disconnect( self.cmb_capture_src_grp_changed) self.add_outlines() self.display_current_bl_not_compared() QApplication.restoreOverrideCursor() self.edit_dialog = EditDialog(self) @pyqtSlot() def bulk_load_reset_clicked(self): """ When bulk Load reset clicked """ self.cmb_capture_method.setCurrentIndex(0) self.ml_outlines_layer.setCurrentIndex(0) self.cmb_organisation.setCurrentIndex(0) self.le_data_description.clear() self.rad_external_id.setChecked(False) @pyqtSlot(bool) def compare_outlines_clicked(self, commit_status): """ When compare outlines clicked """ if self.confirm(self.msgbox_compare): QApplication.setOverrideCursor(Qt.WaitCursor) self.edit_cancel_clicked() comparisons.compare_outlines(self, commit_status) self.btn_publish.setEnabled(1) self.btn_compare_outlines.setDisabled(1) self.btn_alter_rel.setEnabled(1) QApplication.restoreOverrideCursor() def canvas_add_outline(self): """ When add outline radio button toggled """ self.edit_dialog.add_outline() self.edit_dialog.show() self.change_instance = self.edit_dialog.get_change_instance() self.circle_tool = None self.polyline = None # setup circle button image_dir = os.path.join(__location__, "..", "icons") icon_path = os.path.join(image_dir, "circle.png") icon = QIcon() icon.addFile(icon_path, QSize(8, 8)) self.circle_action = QAction(icon, "Draw Circle", iface.building_toolbar) iface.registerMainWindowAction(self.circle_action, "Ctrl+0") self.circle_action.triggered.connect(self.circle_tool_clicked) self.circle_action.setCheckable(True) iface.building_toolbar.addAction(self.circle_action) def circle_tool_clicked(self): if self.circle_action.isChecked(): circle_tool.setup_circle(self) else: iface.actionAddFeature().trigger() def canvas_edit_attribute(self): """ When edit outline radio button toggled """ self.edit_dialog.show() self.edit_dialog.edit_attribute() self.change_instance = self.edit_dialog.get_change_instance() self.change_instance.populate_edit_comboboxes() def canvas_edit_geometry(self): """ When edit geometry radio button toggled """ self.edit_dialog.edit_geometry() self.edit_dialog.show() self.change_instance = self.edit_dialog.get_change_instance() def edit_cancel_clicked(self): """ When cancel clicked """ if len(QgsProject.instance().mapLayersByName( "bulk_load_outlines")) > 0: if isinstance(self.change_instance, bulk_load_changes.EditAttribute): try: self.bulk_load_layer.selectionChanged.disconnect( self.change_instance.selection_changed) except TypeError: pass elif isinstance(self.change_instance, bulk_load_changes.EditGeometry): try: self.bulk_load_layer.geometryChanged.disconnect( self.change_instance.geometry_changed) except TypeError: pass try: self.bulk_load_layer.featureAdded.disconnect() except TypeError: pass elif isinstance(self.change_instance, bulk_load_changes.AddBulkLoad): try: self.bulk_load_layer.featureAdded.disconnect() except TypeError: pass try: self.bulk_load_layer.featureDeleted.disconnect() except TypeError: pass try: self.bulk_load_layer.geometryChanged.disconnect() except TypeError: pass if self.polyline: self.polyline.reset() if isinstance(self.circle_tool, PointTool): self.circle_tool.canvas_clicked.disconnect() self.circle_tool.mouse_moved.disconnect() self.circle_tool.deactivate() iface.actionPan().trigger() iface.actionCancelEdits().trigger() self.setup_toolbar() self.change_instance = None @pyqtSlot() def alter_relationships_clicked(self): """ When alter relationships button clicked open alter relationships frame """ if self.change_instance is not None: self.edit_dialog.close() self.db.close_connection() QgsProject.instance().layerWillBeRemoved.disconnect( self.layers_removed) self.layer_registry.remove_layer(self.bulk_load_layer) for action in iface.building_toolbar.actions(): if action.objectName() not in ["mActionPan"]: iface.building_toolbar.removeAction(action) iface.building_toolbar.hide() dw = self.dockwidget dw.stk_options.removeWidget(dw.stk_options.currentWidget()) dw.new_widget(AlterRelationships(dw, self.current_dataset)) @pyqtSlot(bool) def publish_clicked(self, commit_status): """ When publish button clicked """ if not self.check_duplicate_ids(): return if self.confirm(self.msgbox_publish): QApplication.setOverrideCursor(Qt.WaitCursor) if self.change_instance is not None: self.edit_dialog.close() self.db.open_cursor() sql = "SELECT buildings_bulk_load.load_building_outlines(%s);" self.db.execute_no_commit(sql, (self.current_dataset, )) if commit_status: self.db.commit_open_cursor() self.display_no_bulk_load() self.cmb_capture_src_grp.currentIndexChanged.connect( self.cmb_capture_src_grp_changed) self.current_dataset = None self.lb_dataset_id.setText("None") QgsProject.instance().layerWillBeRemoved.disconnect( self.layers_removed) self.layer_registry.remove_layer(self.bulk_load_layer) self.add_historic_outlines() QApplication.restoreOverrideCursor() self.grpb_layers.hide() QgsProject.instance().layerWillBeRemoved.connect( self.layers_removed) def check_duplicate_ids(self): """ Check same ids in different tables (added/matched/related) """ result = self.run_check() if not result: return True else: self.check_dialog.show() self.check_dialog.set_message("FAILED: duplicate id(s) found.") self.check_dialog.set_data(result) return False def run_check(self): """ Run check and return the output data """ result = self.db._execute( bulk_load_select.added_outlines_by_dataset_id, (self.current_dataset, )) added_outlines = result.fetchall() result = self.db._execute( bulk_load_select.matched_outlines_by_dataset_id, (self.current_dataset, )) matched_outlines = result.fetchall() result = self.db._execute( bulk_load_select.related_outlines_by_dataset_id, (self.current_dataset, )) related_outlines = result.fetchall() ids_added_matched = self.find_match_ids(added_outlines, matched_outlines) ids_added_related = self.find_match_ids(added_outlines, related_outlines) ids_matched_related = self.find_match_ids(matched_outlines, related_outlines) data = self.get_error_data(ids_added_matched, ids_added_related, ids_matched_related) return data def find_match_ids(self, ids_1, ids_2): return list(set(ids_1) & set(ids_2)) def get_error_data(self, ids_added_matched, ids_added_related, ids_matched_related): """ Return the output data """ data = [] for (feat_id, ) in ids_added_matched: data.append((feat_id, "Added", "Matched")) for (feat_id, ) in ids_added_related: data.append((feat_id, "Added", "Related")) for (feat_id, ) in ids_matched_related: data.append((feat_id, "Matched", "Related")) return data @pyqtSlot() def exit_clicked(self): """ Called when bulk load frame exit button clicked. """ self.close_frame() self.dockwidget.lst_sub_menu.clearSelection() def close_frame(self): """ Clean up and remove the bulk load frame. """ if self.change_instance is not None: self.edit_dialog.close() QgsProject.instance().layerWillBeRemoved.disconnect( self.layers_removed) iface.actionCancelEdits().trigger() if self.historic_layer is not None: self.layer_registry.remove_layer(self.historic_layer) if self.bulk_load_layer is not None: self.layer_registry.remove_layer(self.bulk_load_layer) from buildings.gui.menu_frame import MenuFrame dw = self.dockwidget dw.stk_options.removeWidget(dw.stk_options.currentWidget()) dw.new_widget(MenuFrame(dw)) for action in iface.building_toolbar.actions(): if action.text() not in ["Pan Map"]: iface.building_toolbar.removeAction(action) iface.building_toolbar.hide() @pyqtSlot(str) def layers_removed(self, layerids): self.layer_registry.update_layers() if "bulk_load_outlines" in layerids: self.btn_compare_outlines.setDisabled(1) self.btn_alter_rel.setDisabled(1) self.btn_publish.setDisabled(1) self.cb_bulk_load.setDisabled(1) self.cb_added.setDisabled(1) self.cb_removed.setDisabled(1) for action in iface.building_toolbar.actions(): if action.text() not in [ "Pan Map", "Add Outline", "Edit Geometry", "Edit Attributes" ]: iface.building_toolbar.removeAction(action) if action.text() in [ "Add Outline", "Edit Geometry", "Edit Attributes" ]: action.setDisabled(True) else: action.setEnabled(True) iface.messageBar().pushMessage( "ERROR", "Required layer Removed! Please reload the buildings plugin or the current frame before continuing", level=Qgis.Critical, duration=5, ) return if "loaded_datasets" in layerids: iface.messageBar().pushMessage( "ERROR", "Required layer Removed! Please reload the buildings plugin or the current frame before continuing", level=Qgis.Critical, duration=5, ) # disable bulk loading buttons self.btn_bl_save.setDisabled(1) self.btn_bl_reset.setDisabled(1) return def reload_bulk_load_layer(self): """To ensure QGIS has most up to date ID for the newly split feature see #349""" self.cb_added_clicked(False) self.cb_added_clicked(True)
class ProcessingPlugin: def __init__(self, iface): self.iface = iface self.options_factory = None self.drop_handler = None self.item_provider = None self.locator_filter = None self.edit_features_locator_filter = None self.initialized = False self.initProcessing() def initProcessing(self): if not self.initialized: self.initialized = True Processing.initialize() def initGui(self): self.options_factory = ProcessingOptionsFactory() self.options_factory.setTitle(self.tr('Processing')) iface.registerOptionsWidgetFactory(self.options_factory) self.drop_handler = ProcessingDropHandler() iface.registerCustomDropHandler(self.drop_handler) self.item_provider = ProcessingDataItemProvider() QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider) self.locator_filter = AlgorithmLocatorFilter() iface.registerLocatorFilter(self.locator_filter) # Invalidate the locator filter for in-place when active layer changes iface.currentLayerChanged.connect(lambda _: self.iface.invalidateLocatorResults()) self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter() iface.registerLocatorFilter(self.edit_features_locator_filter) self.toolbox = ProcessingToolbox() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.toolbox) self.toolbox.hide() self.toolbox.visibilityChanged.connect(self.toolboxVisibilityChanged) self.resultsDock = ResultsDock() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.resultsDock) self.resultsDock.hide() self.menu = QMenu(self.iface.mainWindow().menuBar()) self.menu.setObjectName('processing') self.menu.setTitle(self.tr('Pro&cessing')) self.toolboxAction = QAction(self.tr('&Toolbox'), self.iface.mainWindow()) self.toolboxAction.setCheckable(True) self.toolboxAction.setObjectName('toolboxAction') self.toolboxAction.setIcon( QgsApplication.getThemeIcon("/processingAlgorithm.svg")) self.iface.registerMainWindowAction(self.toolboxAction, QKeySequence('Ctrl+Alt+T').toString(QKeySequence.NativeText)) self.toolboxAction.toggled.connect(self.openToolbox) self.iface.attributesToolBar().insertAction(self.iface.actionOpenStatisticalSummary(), self.toolboxAction) self.menu.addAction(self.toolboxAction) self.modelerAction = QAction( QgsApplication.getThemeIcon("/processingModel.svg"), QCoreApplication.translate('ProcessingPlugin', 'Graphical &Modeler…'), self.iface.mainWindow()) self.modelerAction.setObjectName('modelerAction') self.modelerAction.triggered.connect(self.openModeler) self.iface.registerMainWindowAction(self.modelerAction, QKeySequence('Ctrl+Alt+M').toString(QKeySequence.NativeText)) self.menu.addAction(self.modelerAction) self.historyAction = QAction( QgsApplication.getThemeIcon("/mIconHistory.svg"), QCoreApplication.translate('ProcessingPlugin', '&History…'), self.iface.mainWindow()) self.historyAction.setObjectName('historyAction') self.historyAction.triggered.connect(self.openHistory) self.iface.registerMainWindowAction(self.historyAction, QKeySequence('Ctrl+Alt+H').toString(QKeySequence.NativeText)) self.menu.addAction(self.historyAction) self.toolbox.processingToolbar.addAction(self.historyAction) self.resultsAction = QAction( QgsApplication.getThemeIcon("/processingResult.svg"), self.tr('&Results Viewer'), self.iface.mainWindow()) self.resultsAction.setCheckable(True) self.iface.registerMainWindowAction(self.resultsAction, QKeySequence('Ctrl+Alt+R').toString(QKeySequence.NativeText)) self.menu.addAction(self.resultsAction) self.toolbox.processingToolbar.addAction(self.resultsAction) self.resultsDock.visibilityChanged.connect(self.resultsAction.setChecked) self.resultsAction.toggled.connect(self.resultsDock.setUserVisible) self.toolbox.processingToolbar.addSeparator() self.editInPlaceAction = QAction( QgsApplication.getThemeIcon("/mActionProcessSelected.svg"), self.tr('Edit Features In-Place'), self.iface.mainWindow()) self.editInPlaceAction.setObjectName('editInPlaceFeatures') self.editInPlaceAction.setCheckable(True) self.editInPlaceAction.toggled.connect(self.editSelected) self.menu.addAction(self.editInPlaceAction) self.toolbox.processingToolbar.addAction(self.editInPlaceAction) self.toolbox.processingToolbar.addSeparator() self.optionsAction = QAction( QgsApplication.getThemeIcon("/mActionOptions.svg"), self.tr('Options'), self.iface.mainWindow()) self.optionsAction.setObjectName('optionsAction') self.optionsAction.triggered.connect(self.openProcessingOptions) self.toolbox.processingToolbar.addAction(self.optionsAction) menuBar = self.iface.mainWindow().menuBar() menuBar.insertMenu( self.iface.firstRightStandardMenu().menuAction(), self.menu) self.menu.addSeparator() initializeMenus() createMenus() # In-place editing button state sync self.iface.currentLayerChanged.connect(self.sync_in_place_button_state) self.iface.mapCanvas().selectionChanged.connect(self.sync_in_place_button_state) self.iface.actionToggleEditing().triggered.connect(partial(self.sync_in_place_button_state, None)) self.sync_in_place_button_state() def sync_in_place_button_state(self, layer=None): """Synchronise the button state with layer state""" if layer is None: layer = self.iface.activeLayer() old_enabled_state = self.editInPlaceAction.isEnabled() new_enabled_state = layer is not None and layer.type() == QgsMapLayerType.VectorLayer self.editInPlaceAction.setEnabled(new_enabled_state) if new_enabled_state != old_enabled_state: self.toolbox.set_in_place_edit_mode(new_enabled_state and self.editInPlaceAction.isChecked()) def openProcessingOptions(self): self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions') def unload(self): self.toolbox.setVisible(False) self.iface.removeDockWidget(self.toolbox) self.iface.attributesToolBar().removeAction(self.toolboxAction) self.resultsDock.setVisible(False) self.iface.removeDockWidget(self.resultsDock) self.toolbox.deleteLater() self.menu.deleteLater() # delete temporary output files folder = QgsProcessingUtils.tempFolder() if QDir(folder).exists(): shutil.rmtree(folder, True) # also delete temporary help files folder = tempHelpFolder() if QDir(folder).exists(): shutil.rmtree(folder, True) self.iface.unregisterMainWindowAction(self.toolboxAction) self.iface.unregisterMainWindowAction(self.modelerAction) self.iface.unregisterMainWindowAction(self.historyAction) self.iface.unregisterMainWindowAction(self.resultsAction) self.iface.unregisterOptionsWidgetFactory(self.options_factory) self.iface.deregisterLocatorFilter(self.locator_filter) self.iface.deregisterLocatorFilter(self.edit_features_locator_filter) self.iface.unregisterCustomDropHandler(self.drop_handler) QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider) removeMenus() Processing.deinitialize() def openToolbox(self, show): self.toolbox.setUserVisible(show) def toolboxVisibilityChanged(self, visible): self.toolboxAction.setChecked(visible) def openModeler(self): dlg = ModelerDialog() dlg.update_model.connect(self.updateModel) dlg.show() def updateModel(self): model_provider = QgsApplication.processingRegistry().providerById('model') model_provider.refreshAlgorithms() def openResults(self): if self.resultsDock.isVisible(): self.resultsDock.hide() else: self.resultsDock.show() def openHistory(self): dlg = HistoryDialog() dlg.exec_() def tr(self, message): return QCoreApplication.translate('ProcessingPlugin', message) def editSelected(self, enabled): self.toolbox.set_in_place_edit_mode(enabled)
class ScreenShotSample(QgsMapTool): def exportMap(self): self.canvas.saveAsImage(self.outputdir + '\{}.png'.format(self.layername)) QgsProject.instance().removeMapLayer(qgis.utils.iface.activeLayer()) if len(self.filelist) > self.count: self.setNextFeatureExtent() else: self.canvas.mapCanvasRefreshed.disconnect(self.exportMap) def setNextFeatureExtent(self): self.layername, ext = os.path.splitext( os.path.basename(self.filelist[self.count])) self.layer = self.iface.addVectorLayer(self.filelist[self.count], self.layername, "ogr") self.iface.zoomToActiveLayer() self.count += 1 def start(self): self.ext = '.shp' self.inputdir = 'shpが格納されているフォルダパス' self.outputdir = '画像の保存先のファイルパス' self.filelist = glob.glob(self.inputdir + "\*" + self.ext) if len(self.filelist) == 0: return self.count = 0 self.canvas.mapCanvasRefreshed.connect(self.exportMap) self.setNextFeatureExtent() def finish(self): self.canvas.mapToolSet.disconnect(self.unsetTool) def __init__(self, iface): self.plugin_name = 'ファイル毎にスクリーンショット' # プラグイン名 self.menu_pos = 'サンプル' # プラグインの登録場所 self.toolbar = True # Trueならツールバーにアイコンを表示する self.checkable = False # Trueならプラグイン実行中はアイコンが凹んだままになる self.iface = iface self.canvas = self.iface.mapCanvas() QgsMapTool.__init__(self, self.canvas) # このプラグイン実行中に他のアイコンが押された場合、アイコンを元の状態に戻す def unsetTool(self, tool): if not isinstance(tool, ScreenShotSample): self.finish() self.action.setChecked(False) def initGui(self): icon = QIcon(os.path.dirname(__file__) + '/icon.png') self.action = QAction(icon, self.plugin_name, self.iface.mainWindow()) self.action.triggered.connect( self.execSample) # アイコンを押下した時に実行されるメソッドを登録 self.action.setCheckable( self.checkable) # Trueだとアイコンを押下したら次に押下するまで凹んだままになる if self.toolbar: self.iface.addToolBarIcon(self.action) # ツールバーにこのツールのアイコンを表示する self.iface.addPluginToMenu(self.menu_pos, self.action) # このプラグインを無効にしたときに呼ばれる def unload(self): self.iface.removePluginMenu(self.menu_pos, self.action) self.iface.removeToolBarIcon(self.action) # このツールのアイコンを押下したときに呼ばれる def execSample(self): if self.checkable: if self.action.isChecked(): # 凹状態になった self.previousMapTool = self.canvas.mapTool() # 現在のマップツールを退避 self.start() else: # 凸状態になった self.finish() self.canvas.setMapTool(self.previousMapTool) # このツール実行前に戻す else: self.start()