def testMoveToTopActionGroup(self): """Test move to top action on group""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().addGroup("embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), ]) nodeLayerIndex = self.model.node2index(group) view.setCurrentIndex(nodeLayerIndex) movetotop = actions.actionMoveToTop() movetotop.trigger() self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), self.layer.name(), self.layer2.name(), self.layer3.name(), ])
def testMoveToTopActionEmbeddedGroup(self): """Test move to top action on embeddedgroup layer""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().addGroup("embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), ]) view.setCurrentLayer(self.layer5) movetotop = actions.actionMoveToTop() movetotop.trigger() self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer5.name(), groupname + '-' + self.layer4.name(), ])
def testMoveOutOfGroupActionLayer(self): """Test move out of group action on layer""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().addGroup("embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), ]) view.setCurrentLayer(self.layer5) moveOutOfGroup = actions.actionMoveOutOfGroup() moveOutOfGroup.trigger() self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), self.layer5.name(), groupname, groupname + '-' + self.layer4.name(), ])
def __init__(self, view, canvas, proj): QgsLayerTreeViewMenuProvider.__init__(self) self.view = view self.canvas = canvas self.proj = proj self.defActions = QgsLayerTreeViewDefaultActions(self.view) self.name = None
def testAddGroupActionGroup(self): """Test add group action on single group""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().insertGroup(0, "embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) if USE_MODEL_TESTER: proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), self.layer.name(), self.layer2.name(), self.layer3.name(), ]) nodeLayerIndex = view.node2index(group) view.setCurrentIndex(nodeLayerIndex) addgroup = actions.actionAddGroup() addgroup.trigger() self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), groupname + '-' + self.subgroupname + '1', self.layer.name(), self.layer2.name(), self.layer3.name() ])
def testMoveToBottomActionEmbeddedGroup(self): """Test move to bottom action on embeddedgroup layer""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().addGroup("embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) if USE_MODEL_TESTER: proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), ]) view.setCurrentLayer(self.layer4) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer5.name(), groupname + '-' + self.layer4.name(), ])
def testMoveToBottomActionLayerAndGroup(self): """Test move to top action for a group and it's layer simultaneously""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().insertGroup(0, "embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), self.layer.name(), self.layer2.name(), self.layer3.name(), ]) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.MultiSelection) nodeLayerIndex = self.model.node2index(group) view.setCurrentIndex(nodeLayerIndex) view.setCurrentLayer(self.layer4) view.setSelectionMode(selectionMode) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() self.assertEqual(self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer5.name(), groupname + '-' + self.layer4.name(), ])
def testMoveToTopActionLayer(self): """Test move to top action on layer""" view = QgsLayerTreeView() view.setModel(self.model) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual(self.project.layerTreeRoot().layerOrder(), [self.layer, self.layer2, self.layer3]) view.setCurrentLayer(self.layer3) movetotop = actions.actionMoveToTop() movetotop.trigger() self.assertEqual(self.project.layerTreeRoot().layerOrder(), [self.layer3, self.layer, self.layer2])
def testDefaultActions(self): view = QgsLayerTreeView() view.setModel(self.model) actions = QgsLayerTreeViewDefaultActions(view) # show in overview action view.setCurrentLayer(self.layer) self.assertEqual(view.currentNode().customProperty('overview', 0), False) show_in_overview = actions.actionShowInOverview() show_in_overview.trigger() self.assertEqual(view.currentNode().customProperty('overview', 0), True) show_in_overview.trigger() self.assertEqual(view.currentNode().customProperty('overview', 0), False)
def testMoveToBottomActionLayer(self): """Test move to bottom action on layer""" view = QgsLayerTreeView() view.setModel(self.model) if USE_MODEL_TESTER: proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual(self.project.layerTreeRoot().layerOrder(), [self.layer, self.layer2, self.layer3]) view.setCurrentLayer(self.layer) movetobottom = actions.actionMoveToBottom() movetobottom.trigger() self.assertEqual(self.project.layerTreeRoot().layerOrder(), [self.layer2, self.layer3, self.layer])
def testDefaultActions(self): view = QgsLayerTreeView() view.setModel(self.model) if USE_MODEL_TESTER: proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) # show in overview action view.setCurrentLayer(self.layer) self.assertEqual(view.currentNode().customProperty('overview', 0), False) show_in_overview = actions.actionShowInOverview() show_in_overview.trigger() self.assertEqual(view.currentNode().customProperty('overview', 0), True) show_in_overview.trigger() self.assertEqual(view.currentNode().customProperty('overview', 0), False)
def testMoveToTopActionLayerAndGroup(self): """Test move to top action for a group and it's layer simultaneously""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().addGroup("embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) if USE_MODEL_TESTER: proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ self.layer.name(), self.layer2.name(), self.layer3.name(), groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), ]) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.MultiSelection) nodeLayerIndex = view.node2index(group) view.setCurrentIndex(nodeLayerIndex) view.setCurrentLayer(self.layer5) view.setSelectionMode(selectionMode) movetotop = actions.actionMoveToTop() movetotop.trigger() self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer5.name(), groupname + '-' + self.layer4.name(), self.layer.name(), self.layer2.name(), self.layer3.name(), ])
def testAddGroupActionLayers(self): """Test add group action on several layers""" view = QgsLayerTreeView() group = self.project.layerTreeRoot().insertGroup(0, "embeddedgroup") group.addLayer(self.layer4) group.addLayer(self.layer5) groupname = group.name() view.setModel(self.model) if USE_MODEL_TESTER: proxy_tester = QAbstractItemModelTester(view.model()) actions = QgsLayerTreeViewDefaultActions(view) self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), self.layer.name(), self.layer2.name(), self.layer3.name(), ]) selectionMode = view.selectionMode() view.setSelectionMode(QgsLayerTreeView.MultiSelection) view.setCurrentLayer(self.layer) view.setCurrentLayer(self.layer2) view.setSelectionMode(selectionMode) addgroup = actions.actionAddGroup() addgroup.trigger() self.assertEqual( self.nodeOrder(self.project.layerTreeRoot().children()), [ groupname, groupname + '-' + self.layer4.name(), groupname + '-' + self.layer5.name(), self.groupname + '1', self.groupname + '1' + '-' + self.layer.name(), self.groupname + '1' + '-' + self.layer2.name(), self.layer3.name() ])
class MenuProvider(QgsLayerTreeViewMenuProvider): def __init__(self, view, canvas, proj): QgsLayerTreeViewMenuProvider.__init__(self) self.view = view self.canvas = canvas self.proj = proj self.defActions = QgsLayerTreeViewDefaultActions(self.view) self.name = None def createContextMenu(self): if not self.view.currentLayer(): return None layer = self.view.currentLayer() self.connect_signal_name() m = QMenu() m.addAction("Zoom to Layer", self.zoom_to_layer) m.addAction("Rename Layer", self.rename_layer) # we only offer the option to save layer if it is a vector layer and has a valid geometry if layer.type() == 0 and layer.geometryType() not in [3, 4]: m.addAction("Save Layer", self.save_layer) m.addAction("Remove Layer", self.remove_layer) # properties option only for vector or raster layers that are single band (0 or 1) if layer.type() != 1 or layer.rasterType() < 2: m.addAction("Properties", self.layer_properties) m.addAction("Select CRS", self.layer_crs) return m def zoom_to_layer(self): self.defActions.zoomToLayer(self.canvas) def rename_layer(self): self.name = self.view.currentLayer().name() self.defActions.renameGroupOrLayer() def name_changed(self, node, name): n = 0 # check every layer for layer in self.proj.mapLayers().values(): if layer.name() == name: n += 1 # if exists more than one layer with the same name if n > 1: logger.error("More than one layer was found with this name") # set previous name self.view.currentLayer().setName(self.name) QMessageBox.critical(None, "Error in renaming", "More than one layer was found with this name. Please enter another name.", QMessageBox.Close) if name.rfind('/') != -1: if self.view.currentLayer().name() == name: name = name.replace('/', '') self.view.currentLayer().setName(name) QMessageBox.warning(None, "Warning", "Usage of '/' is forbidden \n\n You may use '\\' instead") def remove_layer(self): self.defActions.removeGroupOrLayer() def save_layer(self): layer = self.view.currentLayer() # if it is a vector layer and has a valid geometry if layer.type() == 0 and layer.geometryType() not in [3, 4]: layer_name, selected_filter = QFileDialog.getSaveFileName(None, 'Save Layer', "", 'Shapefile (*.shp);;KML (*.kml);;GPX (*.gpx)') if layer_name != '': if selected_filter == "Shapefile (*.shp)": if not layer_name.endswith('.shp'): layer_name = layer_name + '.shp' ret = QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "ESRI Shapefile") if ret == QgsVectorFileWriter.NoError: logger.info(layer.name() + " saved to " + layer_name) # After saving always delete layer and reload from saved file renderer = layer.renderer() file_info = QFileInfo(layer_name) base_name = file_info.baseName() vlayer = QgsVectorLayer(layer_name, base_name, "ogr") if not vlayer.isValid(): logger.warning("Layer failed to load!") vlayer.setRenderer(renderer.clone()) self.remove_layer() self.proj.addMapLayer(vlayer) elif selected_filter == "KML (*.kml)": if not layer_name.endswith('.kml'): layer_name = layer_name + '.kml' file_info = QFileInfo(layer_name) QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "KML") elif selected_filter == "GPX (*.gpx)": if not layer_name.endswith('.gpx'): layer_name = layer_name + '.gpx' ds_options = list() ds_options.append("GPX_USE_EXTENSIONS=TRUE") # Option needed to write gpx correctly QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8", QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId), "GPX", datasourceOptions=ds_options) def layer_properties(self): layer = self.view.currentLayer() # if it is a vector layer and has a valid geometry if layer.type() == 0 and layer.geometryType() not in [3, 4]: # wrap style dialog with the buttons ok and cancel so that we can apply changes dlg = QDialog() dlg.widget = QgsRendererPropertiesDialog(self.view.currentLayer(), QgsStyle.defaultStyle(), True) dlg.layout = QVBoxLayout(dlg) dlg.buttons = QDialogButtonBox(dlg) dlg.layout.addWidget(dlg.widget) dlg.layout.addWidget(dlg.buttons) dlg.buttons.setOrientation(Qt.Horizontal) dlg.buttons.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # set signals def on_style_edit_accept(d): # this will update the layer's style dlg.widget.onOK() dlg.accept() dlg.buttons.accepted.connect(lambda d=dlg: on_style_edit_accept(d)) dlg.buttons.rejected.connect(dlg.reject) dlg.exec_() self.canvas.refresh() elif layer.type() == 1 and layer.rasterType() != 2: dlg = QDialog() dlg.widget = QgsSingleBandPseudoColorRendererWidget(layer) dlg.layout = QVBoxLayout(dlg) dlg.buttons = QDialogButtonBox(dlg) dlg.layout.addWidget(dlg.widget) dlg.layout.addWidget(dlg.buttons) dlg.buttons.setOrientation(Qt.Horizontal) dlg.buttons.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) # set signals def on_rasterstyle_edit_accept(d): # this will update the layer's style renderer = dlg.widget.renderer() layer.setRenderer(renderer) dlg.accept() dlg.buttons.accepted.connect(lambda d=dlg: on_rasterstyle_edit_accept(d)) dlg.buttons.rejected.connect(dlg.reject) dlg.exec_() self.canvas.refresh() elif layer.type() == 1 and layer.rasterType() == 2: logger.info("multiband") # TODO: Check that it really changes CRS def layer_crs(self): self.projection_selector = QgsProjectionSelectionDialog() self.projection_selector.exec() crs = (self.projection_selector.crs()) layer = self.view.currentLayer() layer.setCrs(crs) self.zoom_to_layer() def connect_signal_name(self): # catch signal nameChanged on name_changed slot while True: try: if self.view.currentNode() is not None: # disconnect function name_changed for signal nameChanged self.view.currentNode().nameChanged.disconnect(self.name_changed) else: break except TypeError: break if self.view.currentNode() is not None: # connect function name_changed on signal nameChanged self.view.currentNode().nameChanged.connect(self.name_changed)