def testFilterByLayer(self): """ test filtering by layer""" QgsProject.instance().clear() m = QgsMapLayerComboBox() l1 = QgsVectorLayer( "Point?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", 'layer 1', "memory") QgsProject.instance().addMapLayer(l1) l2 = QgsVectorLayer( "Polygon?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", 'lAyEr 2', "memory") QgsProject.instance().addMapLayer(l2) l3 = QgsVectorLayer("None?field=fldtxt:string&field=fldint:integer", 'another', "memory") QgsProject.instance().addMapLayer(l3) l4 = QgsVectorLayer( "LineString?crs=EPSG:3111&field=fldtxt:string&field=fldint:integer", 'final layer', "memory") QgsProject.instance().addMapLayer(l4) self.assertEqual(m.count(), 4) self.assertEqual(m.itemText(0), 'another') self.assertEqual(m.itemText(1), 'final layer') self.assertEqual(m.itemText(2), 'layer 1') self.assertEqual(m.itemText(3), 'lAyEr 2') m.setExceptedLayerList([l1, l3]) self.assertEqual(m.count(), 2) self.assertEqual(m.itemText(0), 'final layer') self.assertEqual(m.itemText(1), 'lAyEr 2') m.setExceptedLayerList([l2, l4]) self.assertEqual(m.count(), 2) self.assertEqual(m.itemText(0), 'another') self.assertEqual(m.itemText(1), 'layer 1')
def testMeshLayer(self): m = QgsMapLayerComboBox() l1 = create_mesh_layer("l1") QgsProject.instance().addMapLayer(l1) l2 = create_layer('l2') QgsProject.instance().addMapLayer(l2) m.setFilters(QgsMapLayerProxyModel.MeshLayer) self.assertEqual(m.filters(), QgsMapLayerProxyModel.MeshLayer) self.assertEqual(m.count(), 1) self.assertEqual(m.itemText(0), 'l1')
class FieldMappingDialog(QDialog, FORM_CLASS): """Dialog implementation class for the InaSAFE field mapping tool.""" def __init__(self, parent=None, iface=None, setting=None): """Constructor.""" QDialog.__init__(self, parent) self.setupUi(self) self.setWindowTitle(self.tr('InaSAFE Field Mapping Tool')) icon = resources_path('img', 'icons', 'show-mapping-tool.svg') self.setWindowIcon(QIcon(icon)) self.parent = parent self.iface = iface if setting is None: setting = QSettings() self.setting = setting self.keyword_io = KeywordIO() self.layer = None self.metadata = {} self.layer_input_layout = QHBoxLayout() self.layer_label = QLabel(tr('Layer')) self.layer_combo_box = QgsMapLayerComboBox() # Filter only for Polygon and Point self.layer_combo_box.setFilters( QgsMapLayerProxyModel.PolygonLayer | QgsMapLayerProxyModel.PointLayer) # Filter out a layer that don't have layer groups excepted_layers = [] for i in range(self.layer_combo_box.count()): layer = self.layer_combo_box.layer(i) try: keywords = self.keyword_io.read_keywords(layer) except (KeywordNotFoundError, NoKeywordsFoundError): excepted_layers.append(layer) continue layer_purpose = keywords.get('layer_purpose') if not layer_purpose: excepted_layers.append(layer) continue if layer_purpose == layer_purpose_exposure['key']: layer_subcategory = keywords.get('exposure') elif layer_purpose == layer_purpose_hazard['key']: layer_subcategory = keywords.get('hazard') else: layer_subcategory = None field_groups = get_field_groups(layer_purpose, layer_subcategory) if len(field_groups) == 0: excepted_layers.append(layer) continue self.layer_combo_box.setExceptedLayerList(excepted_layers) # Select the active layer. if self.iface.activeLayer(): found = self.layer_combo_box.findText( self.iface.activeLayer().name()) if found > -1: self.layer_combo_box.setLayer(self.iface.activeLayer()) self.field_mapping_widget = None self.main_stacked_widget.setCurrentIndex(1) # Input self.layer_input_layout.addWidget(self.layer_label) self.layer_input_layout.addWidget(self.layer_combo_box) self.header_label = QLabel() self.header_label.setWordWrap(True) self.main_layout.addWidget(self.header_label) self.main_layout.addLayout(self.layer_input_layout) # Signal self.layer_combo_box.layerChanged.connect(self.set_layer) if self.layer_combo_box.currentLayer(): self.set_layer(self.layer_combo_box.currentLayer()) # Set up things for context help self.help_button = self.button_box.button(QDialogButtonBox.Help) # Allow toggling the help button self.help_button.setCheckable(True) self.help_button.toggled.connect(self.help_toggled) # Set up things for ok button self.ok_button = self.button_box.button(QDialogButtonBox.Ok) self.ok_button.clicked.connect(self.accept) # Set up things for cancel button self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel) self.cancel_button.clicked.connect(self.reject) def set_layer(self, layer=None, keywords=None): """Set layer and update UI accordingly. :param layer: A QgsVectorLayer. :type layer: QgsVectorLayer :param keywords: Keywords for the layer. :type keywords: dict, None """ if self.field_mapping_widget is not None: self.field_mapping_widget.setParent(None) self.field_mapping_widget.close() self.field_mapping_widget.deleteLater() self.main_layout.removeWidget(self.field_mapping_widget) if layer: self.layer = layer else: self.layer = self.layer_combo_box.currentLayer() if not self.layer: return if keywords is not None: self.metadata = keywords else: # Always read from metadata file. try: self.metadata = self.keyword_io.read_keywords(self.layer) except ( NoKeywordsFoundError, KeywordNotFoundError, MetadataReadError) as e: raise e if 'inasafe_default_values' not in self.metadata: self.metadata['inasafe_default_values'] = {} if 'inasafe_fields' not in self.metadata: self.metadata['inasafe_fields'] = {} self.field_mapping_widget = FieldMappingWidget( parent=self, iface=self.iface) self.field_mapping_widget.set_layer(self.layer, self.metadata) self.field_mapping_widget.show() self.main_layout.addWidget(self.field_mapping_widget) # Set header label group_names = [ self.field_mapping_widget.tabText(i) for i in range( self.field_mapping_widget.count())] if len(group_names) == 0: header_text = tr( 'There is no field group for this layer. Please select ' 'another layer.') self.header_label.setText(header_text) return elif len(group_names) == 1: pretty_group_name = group_names[0] elif len(group_names) == 2: pretty_group_name = group_names[0] + tr(' and ') + group_names[1] else: pretty_group_name = ', '.join(group_names[:-1]) pretty_group_name += tr(', and {0}').format(group_names[-1]) header_text = tr( 'Please fill the information for every tab to determine the ' 'attribute for {0} group.').format(pretty_group_name) self.header_label.setText(header_text) @pyqtSlot() @pyqtSignature('bool') # prevents actions being handled twice def help_toggled(self, flag): """Show or hide the help tab in the stacked widget. .. versionadded: 3.2.1 :param flag: Flag indicating whether help should be shown or hidden. :type flag: bool """ if flag: self.help_button.setText(self.tr('Hide Help')) self.show_help() else: self.help_button.setText(self.tr('Show Help')) self.hide_help() def hide_help(self): """Hide the usage info from the user. .. versionadded: 3.2.1 """ self.main_stacked_widget.setCurrentIndex(1) def show_help(self): """Show usage info to the user.""" # Read the header and footer html snippets self.main_stacked_widget.setCurrentIndex(0) header = html_header() footer = html_footer() string = header message = field_mapping_help() string += message.to_html() string += footer self.help_web_view.setHtml(string) def save_metadata(self): """Save metadata based on the field mapping state.""" metadata = self.field_mapping_widget.get_field_mapping() for key, value in metadata['fields'].items(): # Delete the key if it's set to None if key in self.metadata['inasafe_default_values']: self.metadata['inasafe_default_values'].pop(key) if value is None or value == []: if key in self.metadata['inasafe_fields']: self.metadata['inasafe_fields'].pop(key) else: self.metadata['inasafe_fields'][key] = value for key, value in metadata['values'].items(): # Delete the key if it's set to None if key in self.metadata['inasafe_fields']: self.metadata['inasafe_fields'].pop(key) if value is None: if key in self.metadata['inasafe_default_values']: self.metadata['inasafe_default_values'].pop(key) else: self.metadata['inasafe_default_values'][key] = value # Save metadata try: self.keyword_io.write_keywords( layer=self.layer, keywords=self.metadata) except InaSAFEError, e: error_message = get_error_message(e) # noinspection PyCallByClass,PyTypeChecker,PyArgumentList QMessageBox.warning( self, self.tr('InaSAFE'), ((self.tr( 'An error was encountered when saving the following ' 'keywords:\n %s') % error_message.to_html()))) # Update setting fir recent value if self.metadata.get('inasafe_default_values'): for key, value in \ self.metadata['inasafe_default_values'].items(): set_inasafe_default_value_qsetting( self.setting, key, RECENT, value)
def testAdditionalLayers(self): QgsProject.instance().clear() l1 = create_layer('l1') l2 = create_layer('l2') QgsProject.instance().addMapLayers([l1, l2]) m = QgsMapLayerComboBox() self.assertEqual(m.count(), 2) l3 = create_layer('l3') l4 = create_layer('l4') m.setAdditionalLayers([l3, l4]) self.assertEqual(m.count(), 4) m.setAdditionalItems(['a', 'b']) self.assertEqual(m.count(), 6) self.assertEqual(m.itemText(0), 'l1') self.assertEqual(m.itemText(1), 'l2') self.assertEqual(m.itemText(2), 'l3') self.assertEqual(m.itemText(3), 'l4') self.assertEqual(m.itemText(4), 'a') self.assertEqual(m.itemText(5), 'b') m.setAllowEmptyLayer(True) self.assertEqual(m.count(), 7) self.assertFalse(m.itemText(0)) self.assertEqual(m.itemText(1), 'l1') self.assertEqual(m.itemText(2), 'l2') self.assertEqual(m.itemText(3), 'l3') self.assertEqual(m.itemText(4), 'l4') self.assertEqual(m.itemText(5), 'a') self.assertEqual(m.itemText(6), 'b') l3.deleteLater() QCoreApplication.sendPostedEvents(None, QEvent.DeferredDelete) self.assertEqual(m.count(), 6) self.assertFalse(m.itemText(0)) self.assertEqual(m.itemText(1), 'l1') self.assertEqual(m.itemText(2), 'l2') self.assertEqual(m.itemText(3), 'l4') self.assertEqual(m.itemText(4), 'a') self.assertEqual(m.itemText(5), 'b') l5 = create_layer('l5') l6 = create_layer('l6') m.setAdditionalLayers([l5, l6, l4]) self.assertEqual(m.count(), 8) self.assertFalse(m.itemText(0)) self.assertEqual(m.itemText(1), 'l1') self.assertEqual(m.itemText(2), 'l2') self.assertEqual(m.itemText(3), 'l4') self.assertEqual(m.itemText(4), 'l5') self.assertEqual(m.itemText(5), 'l6') self.assertEqual(m.itemText(6), 'a') self.assertEqual(m.itemText(7), 'b') m.setAdditionalLayers([l5, l4]) self.assertEqual(m.count(), 7) self.assertFalse(m.itemText(0)) self.assertEqual(m.itemText(1), 'l1') self.assertEqual(m.itemText(2), 'l2') self.assertEqual(m.itemText(3), 'l4') self.assertEqual(m.itemText(4), 'l5') self.assertEqual(m.itemText(5), 'a') self.assertEqual(m.itemText(6), 'b') QgsProject.instance().removeMapLayers([l1.id(), l2.id()]) self.assertEqual(m.count(), 5) self.assertFalse(m.itemText(0)) self.assertEqual(m.itemText(1), 'l4') self.assertEqual(m.itemText(2), 'l5') self.assertEqual(m.itemText(3), 'a') self.assertEqual(m.itemText(4), 'b')
class FieldMappingDialog(QDialog, FORM_CLASS): """Dialog implementation class for the InaSAFE field mapping tool.""" def __init__(self, parent=None, iface=None, setting=None): """Constructor.""" QDialog.__init__(self, parent) self.setupUi(self) self.setWindowTitle(self.tr('InaSAFE Field Mapping Tool')) icon = resources_path('img', 'icons', 'show-mapping-tool.svg') self.setWindowIcon(QIcon(icon)) self.parent = parent self.iface = iface if setting is None: setting = QSettings() self.setting = setting self.keyword_io = KeywordIO() self.layer = None self.metadata = {} self.layer_input_layout = QHBoxLayout() self.layer_label = QLabel(tr('Layer')) self.layer_combo_box = QgsMapLayerComboBox() # Filter only for Polygon and Point self.layer_combo_box.setFilters( QgsMapLayerProxyModel.PolygonLayer | QgsMapLayerProxyModel.PointLayer) # Filter out a layer that don't have layer groups excepted_layers = [] for i in range(self.layer_combo_box.count()): layer = self.layer_combo_box.layer(i) try: keywords = self.keyword_io.read_keywords(layer) except (KeywordNotFoundError, NoKeywordsFoundError): excepted_layers.append(layer) continue layer_purpose = keywords.get('layer_purpose') if not layer_purpose: excepted_layers.append(layer) continue if layer_purpose == layer_purpose_exposure['key']: layer_subcategory = keywords.get('exposure') elif layer_purpose == layer_purpose_hazard['key']: layer_subcategory = keywords.get('hazard') else: layer_subcategory = None field_groups = get_field_groups(layer_purpose, layer_subcategory) if len(field_groups) == 0: excepted_layers.append(layer) continue self.layer_combo_box.setExceptedLayerList(excepted_layers) # Select the active layer. if self.iface.activeLayer(): found = self.layer_combo_box.findText( self.iface.activeLayer().name()) if found > -1: self.layer_combo_box.setLayer(self.iface.activeLayer()) self.field_mapping_widget = None self.main_stacked_widget.setCurrentIndex(1) # Input self.layer_input_layout.addWidget(self.layer_label) self.layer_input_layout.addWidget(self.layer_combo_box) self.header_label = QLabel() self.header_label.setWordWrap(True) self.main_layout.addWidget(self.header_label) self.main_layout.addLayout(self.layer_input_layout) # Signal self.layer_combo_box.layerChanged.connect(self.set_layer) if self.layer_combo_box.currentLayer(): self.set_layer(self.layer_combo_box.currentLayer()) # Set up things for context help self.help_button = self.button_box.button(QDialogButtonBox.Help) # Allow toggling the help button self.help_button.setCheckable(True) self.help_button.toggled.connect(self.help_toggled) # Set up things for ok button self.ok_button = self.button_box.button(QDialogButtonBox.Ok) self.ok_button.clicked.connect(self.accept) # Set up things for cancel button self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel) self.cancel_button.clicked.connect(self.reject) def set_layer(self, layer=None, keywords=None): """Set layer and update UI accordingly. :param layer: A QgsVectorLayer. :type layer: QgsVectorLayer :param keywords: Keywords for the layer. :type keywords: dict, None """ if self.field_mapping_widget is not None: self.field_mapping_widget.setParent(None) self.field_mapping_widget.close() self.field_mapping_widget.deleteLater() self.main_layout.removeWidget(self.field_mapping_widget) self.field_mapping_widget = None if layer: self.layer = layer else: self.layer = self.layer_combo_box.currentLayer() if not self.layer: return if keywords is not None: self.metadata = keywords else: # Always read from metadata file. try: self.metadata = self.keyword_io.read_keywords(self.layer) except ( NoKeywordsFoundError, KeywordNotFoundError, MetadataReadError) as e: raise e if 'inasafe_default_values' not in self.metadata: self.metadata['inasafe_default_values'] = {} if 'inasafe_fields' not in self.metadata: self.metadata['inasafe_fields'] = {} self.field_mapping_widget = FieldMappingWidget( parent=self, iface=self.iface) self.field_mapping_widget.set_layer(self.layer, self.metadata) self.field_mapping_widget.show() self.main_layout.addWidget(self.field_mapping_widget) # Set header label group_names = [ self.field_mapping_widget.tabText(i) for i in range( self.field_mapping_widget.count())] if len(group_names) == 0: header_text = tr( 'There is no field group for this layer. Please select ' 'another layer.') self.header_label.setText(header_text) return elif len(group_names) == 1: pretty_group_name = group_names[0] elif len(group_names) == 2: pretty_group_name = group_names[0] + tr(' and ') + group_names[1] else: pretty_group_name = ', '.join(group_names[:-1]) pretty_group_name += tr(', and {0}').format(group_names[-1]) header_text = tr( 'Please fill the information for every tab to determine the ' 'attribute for {0} group.').format(pretty_group_name) self.header_label.setText(header_text) @pyqtSlot(bool) # prevents actions being handled twice def help_toggled(self, flag): """Show or hide the help tab in the stacked widget. .. versionadded: 3.2.1 :param flag: Flag indicating whether help should be shown or hidden. :type flag: bool """ if flag: self.help_button.setText(self.tr('Hide Help')) self.show_help() else: self.help_button.setText(self.tr('Show Help')) self.hide_help() def hide_help(self): """Hide the usage info from the user. .. versionadded: 3.2.1 """ self.main_stacked_widget.setCurrentIndex(1) def show_help(self): """Show usage info to the user.""" # Read the header and footer html snippets self.main_stacked_widget.setCurrentIndex(0) header = html_header() footer = html_footer() string = header message = field_mapping_help() string += message.to_html() string += footer self.help_web_view.setHtml(string) def save_metadata(self): """Save metadata based on the field mapping state.""" metadata = self.field_mapping_widget.get_field_mapping() for key, value in list(metadata['fields'].items()): # Delete the key if it's set to None if key in self.metadata['inasafe_default_values']: self.metadata['inasafe_default_values'].pop(key) if value is None or value == []: if key in self.metadata['inasafe_fields']: self.metadata['inasafe_fields'].pop(key) else: self.metadata['inasafe_fields'][key] = value for key, value in list(metadata['values'].items()): # Delete the key if it's set to None if key in self.metadata['inasafe_fields']: self.metadata['inasafe_fields'].pop(key) if value is None: if key in self.metadata['inasafe_default_values']: self.metadata['inasafe_default_values'].pop(key) else: self.metadata['inasafe_default_values'][key] = value # Save metadata try: self.keyword_io.write_keywords( layer=self.layer, keywords=self.metadata) except InaSAFEError as e: error_message = get_error_message(e) # noinspection PyCallByClass,PyTypeChecker,PyArgumentList QMessageBox.warning( self, self.tr('InaSAFE'), ((self.tr( 'An error was encountered when saving the following ' 'keywords:\n %s') % error_message.to_html()))) # Update setting fir recent value if self.metadata.get('inasafe_default_values'): for key, value in \ list(self.metadata['inasafe_default_values'].items()): set_inasafe_default_value_qsetting( self.setting, key, RECENT, value) def accept(self): """Method invoked when OK button is clicked.""" try: self.save_metadata() except InvalidValidationException as e: display_warning_message_box( self, tr('Invalid Field Mapping'), str(e)) return super(FieldMappingDialog, self).accept()
class NewProjectDialog(Dialog): ''' dialog to select a layer and a name as inputs for creating a new project ''' def setupUi(self): ''' set up the user interface ''' self.setMinimumWidth(500) self.setWindowTitle('Neues Projekt erstellen') project_manager = ProjectManager() self.project_names = [p.name for p in project_manager.projects] layout = QVBoxLayout(self) label = QLabel('Name des Projekts') self.name_edit = QLineEdit() self.name_edit.textChanged.connect(self.validate) layout.addWidget(label) layout.addWidget(self.name_edit) self.path = os.path.join(project_manager.settings.TEMPLATE_PATH, 'projektflaechen') hlayout = QHBoxLayout(self) label = QLabel('Import der (Teil-)Flächen des Plangebiets') self.layer_combo = QgsMapLayerComboBox() self.layer_combo.setFilters(QgsMapLayerProxyModel.VectorLayer) self.source = None self.layer_combo.layerChanged.connect(self.set_layer) self.layer_combo.layerChanged.connect(self.validate) browse_button = QPushButton('...') browse_button.clicked.connect(self.browse_path) browse_button.setMaximumWidth(30) hlayout.addWidget(self.layer_combo) hlayout.addWidget(browse_button) layout.addWidget(label) layout.addLayout(hlayout) self.status_label = QLabel() layout.addWidget(self.status_label) spacer = QSpacerItem( 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) layout.addItem(spacer) buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.ok_button = buttons.button(QDialogButtonBox.Ok) self.ok_button.setEnabled(False) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) if len(self.layer_combo) > 0: self.set_layer(self.layer_combo.currentLayer()) self.layer_combo.setCurrentIndex(0) def set_layer(self, layer: QgsVectorLayer = None): ''' set layer as user selection Parameters ---------- layer : QgsVectorLayer the selected layer ''' if not layer: path = self.layer_combo.currentText() layer = QgsVectorLayer(path, 'testlayer_shp', 'ogr') self.source = layer self.validate() def browse_path(self): ''' open dialog for user input of path to a shapefile and add it to the layer-combo ''' path, sf = QFileDialog.getOpenFileName( self, 'Datei wählen', filter="Shapefile(*.shp)", directory=self.path) if path: self.path = os.path.split(path)[0] self.layer_combo.setAdditionalItems([str(path)]) self.layer_combo.setCurrentIndex(self.layer_combo.count()-1) self.set_layer() def show(self) -> Tuple[bool, str, QgsVectorLayer]: ''' show dialog and return selections made by user ''' confirmed = self.exec_() if confirmed: return confirmed, self.name_edit.text(), self.source return False, None, None def validate(self): ''' validate current input of name and layer, set the status label according to validation result ''' name = str(self.name_edit.text()) status_text = '' regexp = re.compile('[\\\/\:*?\"\'<>|]') error = False if name and regexp.search(name): status_text = ('Der Projektname darf keines der folgenden Zeichen ' 'enthalten: \/:*?"\'<>|') error = True elif name in self.project_names: status_text = ( f'Ein Projekt mit dem Namen {name} existiert bereits!\n' 'Projektnamen müssen einzigartig sein.') error = True if self.source: if not self.source.isValid(): status_text = 'Der Layer ist ungültig.' error = True elif not self.source.geometryType() == QgsWkbTypes.PolygonGeometry: status_text = 'Der Layer hat keine Polygongeometrie.' error = True self.status_label.setText(status_text) if not error and (name and self.source): self.ok_button.setEnabled(True) else: self.ok_button.setEnabled(False)