class DataSourceSelectDialog(base, ui): """ Reusable dialog for selecting a map layer source based on the QGIS browser. Allows for selection of disk based layers, together with layers from database and online providers (such as Oracle/Postgres/etc) """ def __init__(self, layer_name, original_uri, layer_type, parent=None): super().__init__(parent) self.setupUi(self) self.setWindowTitle("Select Source for {}".format(layer_name)) QgsGui.enableAutoGeometryRestore(self) # in case browser panel isn't open, we need to force initialize the model now iface.browserModel().initialize() self.browser_proxy_model = QgsBrowserProxyModel(self) self.browser_proxy_model.setBrowserModel(iface.browserModel()) self.browser_proxy_model.setFilterByLayerType(True) self.browser_proxy_model.setLayerType(layer_type) self.mBrowserTreeView.setHeaderHidden(True) self.mBrowserTreeView.setModel(self.browser_proxy_model) self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) self.mBrowserTreeView.clicked.connect(self.on_layer_selected) self.uri = None self.description_label = None self.setDescription("Original source: {}".format(original_uri)) def setDescription(self, description): """ Sets the description to show in the dialog """ if description: if not self.description_label: self.description_label = QLabel() self.description_label.setWordWrap(True) self.description_label.setMargin(4) self.verticalLayout.insertWidget(1, self.description_label) self.description_label.setText(description) else: if self.description_label: self.verticalLayout.removeWidget(self.description_label) self.description_label.deleteLater() self.description_label = None def on_layer_selected(self, index): """ Triggered on selecting a layer """ is_layer_compatible = False self.uri = QgsMimeDataUtils.Uri() if index.isValid(): item = self.browser_proxy_model.dataItem(index) if item: if issubclass(item.__class__, QgsLayerItem): is_layer_compatible = True self.uri = item.mimeUri() self.buttonBox.button( QDialogButtonBox.Ok).setEnabled(is_layer_compatible)
def addLayer(self, geometryType=None, crs=None): layer = self.toMapLayer(geometryType, crs) layers = QgsProject.instance().addMapLayers([layer]) if len(layers) != 1: QgsMessageLog.logMessage(self.tr("{layer} is an invalid layer - not loaded").format(layer=layer.publicSource())) msgLabel = QLabel(self.tr("{layer} is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info.").format(layer=layer.publicSource()), self.mainWindow.infoBar) msgLabel.setWordWrap(True) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_) self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, Qgis.Warning))
def update_history_view(self): """Update the history view.""" historic_folder = query_historic() files = os.listdir(historic_folder) self.dialog.list_historic.clear() for file in files[::-1]: file_path = join(historic_folder, file) with open(file_path, encoding='utf8') as json_file: data = json.load(json_file, object_hook=as_enum) name = data['file_name'] item = QListWidgetItem(self.dialog.list_historic) self.dialog.list_historic.addItem(item) group = QFrame() group.setFrameStyle(QFrame.StyledPanel) group.setStyleSheet('QFrame { margin: 3px; }') group.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hbox = QHBoxLayout() vbox = QVBoxLayout() label_name = QLabel(name) label_name.setStyleSheet('font-weight: bold;') label_name.setWordWrap(True) vbox.addWidget(label_name) for label in data['description']: if not label: label = tr('No description') real_label = QLabel(label) real_label.setWordWrap(True) vbox.addWidget(real_label) hbox.addItem(vbox) button_run = QPushButton() button_save = QPushButton() button_run.setIcon(QIcon(QgsApplication.iconPath("mActionStart.svg"))) button_save.setIcon(QIcon(QgsApplication.iconPath("mActionFileSave.svg"))) button_run.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button_save.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button_run.setToolTip(tr('Run the query')) button_save.setToolTip(tr('Save this query in a new preset')) hbox.addWidget(button_run) hbox.addWidget(button_save) group.setLayout(hbox) # Actions on click run = partial(self.run_saved_query, data) button_run.clicked.connect(run) save = partial(self.save_history_preset, data) button_save.clicked.connect(save) item.setSizeHint(group.minimumSizeHint()) self.dialog.list_historic.setItemWidget(item, group)
def show_error(self, error_text): self.lstSearchResult.clear() new_widget = QLabel() new_widget.setTextFormat(Qt.RichText) new_widget.setOpenExternalLinks(True) new_widget.setWordWrap(True) new_widget.setText( u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>" .format(self.tr('Error'), error_text)) new_item = QListWidgetItem(self.lstSearchResult) new_item.setSizeHint(new_widget.sizeHint()) self.lstSearchResult.addItem(new_item) self.lstSearchResult.setItemWidget(new_item, new_widget)
def createWidgets(self): vlayout = QVBoxLayout() lbl = QLabel( "A column labeled 'ID' with unique increasing numbers for every row will be "\ "added to the output table automatically. In addition to this column it is also "\ "possible to copy one of the columns of the source table to the output table "\ "(tip: if a row identifying column is copied this can later be used for transferring "\ "more data from source table to the new table if necessary).") lbl.setWordWrap(True); vlayout.addWidget(lbl) vlayout.addSpacing(20) self._copyCheck = WidgetEnableCheckBox("Copy column from source table") self.regProp("copy_column_enabled", WizProp(self._copyCheck, False)) vlayout.addWidget(self._copyCheck) glayout = QGridLayout() glayout.setColumnMinimumWidth(0, 20) lbl = QLabel( "The selected column of the source table will be added to the output table "\ "(possibly with a new name). For every object in the output table the value of "\ "its source object will be copied to this column.") lbl.setWordWrap(True); self._copyCheck.addWidget(lbl) glayout.addWidget(lbl, 0, 1, 1, 3) lbl = QLabel("Column in source table") self._copyCheck.addWidget(lbl) glayout.addWidget(lbl, 1, 1) self._sourceCombo = QComboBox() self.regProp("copy_column_in", WizProp(self._sourceCombo, "")) self._copyCheck.addWidget(self._sourceCombo) glayout.addWidget(self._sourceCombo, 1, 2) lbl = QLabel("Column in output table") self._copyCheck.addWidget(lbl) glayout.addWidget(lbl, 2, 1) self._outputEdit = QLineEdit() self.regProp("copy_column_out", WizProp(self._outputEdit, "")) self._copyCheck.addWidget(self._outputEdit) glayout.addWidget(self._outputEdit, 2, 2) vlayout.addLayout(glayout) vlayout.addStretch(1) self.setLayout(vlayout)
def addLayer(self): table = self.currentTable() if table is not None: layer = table.toMapLayer() layers = QgsMapLayerRegistry.instance().addMapLayers([layer]) if len(layers) != 1: QgsMessageLog.logMessage( self.tr("%1 is an invalid layer - not loaded").replace("%1", layer.publicSource())) msgLabel = QLabel(self.tr( "%1 is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info.").replace( "%1", layer.publicSource()), self.mainWindow.infoBar) msgLabel.setWordWrap(True) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_) self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, QgsMessageBar.WARNING))
def setup_default_preset(self): """Setup the display of presets""" preset_folder = resources_path('map_preset') folders = os.listdir(preset_folder) for folder_name in folders: file_path = join(preset_folder, folder_name, folder_name + '.json') with open(file_path, encoding='utf8') as json_file: data = json.load(json_file, object_hook=as_enum) item = QListWidgetItem(self.dialog.list_default_mp) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.dialog.list_default_mp.addItem(item) widget = QFrame() widget.setFrameStyle(QFrame.StyledPanel) widget.setStyleSheet('QFrame { margin: 3px; };') widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hbox = QHBoxLayout() vbox = QVBoxLayout() picture = QLabel() icon_path = resources_path('map_preset', folder_name, folder_name + '_icon.png') if not os.path.isfile(icon_path): icon_path = resources_path('icons', 'QuickOSM.svg') icon = QPixmap(icon_path) icon.scaled(QSize(150, 250), Qt.KeepAspectRatio) picture.setPixmap(icon) picture.setStyleSheet( 'max-height: 150px; max-width: 250px; margin-right: 50px;') hbox.addWidget(picture) title = QLabel(data['file_name']) title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) title.setStyleSheet('font: bold 20px; margin-bottom: 25px;') vbox.addWidget(title) for label in data['description']: if not label: label = tr('No description') real_label = QLabel(label) real_label.setWordWrap(True) vbox.addWidget(real_label) hbox.addItem(vbox) widget.setLayout(hbox) item.setSizeHint(widget.minimumSizeHint()) self.dialog.list_default_mp.setItemWidget(item, widget)
def _create_labels(self): for i in range(len(self.steps)): if i != 0: spacer = QSpacerItem( self.label_spacing_width, 0, QSizePolicy.Expanding, QSizePolicy.Minimum, ) self.layout_labels.addItem(spacer) label = QLabel(self.steps[i]) label.font_size = 11 label.setWordWrap(True) label.setAlignment(Qt.AlignCenter) label.setFixedWidth(self.label_width) self.layout_labels.addWidget(label) self.widgets[i].append(label)
def populate_functions_dlg(self, dialog, result): status = False for group, function in result['fields'].items(): if len(function) != 0: dialog.setWindowTitle(function[0]['alias']) dialog.txt_info.setText(str(function[0]['descript'])) if str(function[0]['isparametric']) in ('false', 'False', False, 'None', None, 'null'): self.is_paramtetric = False self.control_isparametric(dialog) self.load_settings_values(dialog, function) if str(function[0]['isnotparammsg']) is not None: layout = dialog.findChild(QGridLayout, 'grl_option_parameters') if layout is None: status = True break label = QLabel() label.setWordWrap(True) label.setText("Info: " + str(function[0]['isnotparammsg'])) layout.addWidget(label, 0, 0) status = True break if not function[0]['input_params']['featureType']: dialog.grb_input_layer.setVisible(False) dialog.grb_selection_type.setVisible(False) else: feature_types = function[0]['input_params']['featureType'] self.populate_cmb_type(feature_types) self.dlg_functions.cmb_geom_type.currentIndexChanged.connect( partial(self.populate_layer_combo)) self.populate_layer_combo() construct_form_param_user(dialog, function, 0, self.function_list, self.temp_layers_added) self.load_settings_values(dialog, function) self.load_parametric_values(dialog, function) status = True break return status
def show_error(self, error_text): self.lstSearchResult.clear() new_widget = QLabel() new_widget.setTextFormat(Qt.RichText) new_widget.setOpenExternalLinks(True) new_widget.setWordWrap(True) new_widget.setText( u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>".format( self.tr('Error'), error_text ) ) new_item = QListWidgetItem(self.lstSearchResult) new_item.setSizeHint(new_widget.sizeHint()) self.lstSearchResult.addItem(new_item) self.lstSearchResult.setItemWidget( new_item, new_widget )
def search_finished_progress(self): self.lstSearchResult.takeItem(0) if self.lstSearchResult.count() == 0: new_widget = QLabel() new_widget.setTextFormat(Qt.RichText) new_widget.setOpenExternalLinks(True) new_widget.setWordWrap(True) new_widget.setText( u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>" .format( self.tr(u"No results."), self. tr(u"You can add a service to become searchable. Start <a href='{}'>here</a>." ).format(u"https://qms.nextgis.com/create"), )) new_item = QListWidgetItem(self.lstSearchResult) new_item.setSizeHint(new_widget.sizeHint()) self.lstSearchResult.addItem(new_item) self.lstSearchResult.setItemWidget(new_item, new_widget)
def search_finished_progress(self): self.lstSearchResult.takeItem(0) if self.lstSearchResult.count() == 0: new_widget = QLabel() new_widget.setTextFormat(Qt.RichText) new_widget.setOpenExternalLinks(True) new_widget.setWordWrap(True) new_widget.setText( u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>".format( self.tr(u"No results."), self.tr(u"You can add a service to become searchable. Start <a href='{}'>here</a>.").format( u"https://qms.nextgis.com/create" ), ) ) new_item = QListWidgetItem(self.lstSearchResult) new_item.setSizeHint(new_widget.sizeHint()) self.lstSearchResult.addItem(new_item) self.lstSearchResult.setItemWidget( new_item, new_widget )
def addLayer(self): table = self.currentTable() if table is not None: layer = table.toMapLayer() layers = QgsProject.instance().addMapLayers([layer]) if len(layers) != 1: QgsMessageLog.logMessage( self.tr("%1 is an invalid layer - not loaded").replace( "%1", layer.publicSource())) msgLabel = QLabel( self. tr("%1 is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info." ).replace("%1", layer.publicSource()), self.mainWindow.infoBar) msgLabel.setWordWrap(True) msgLabel.linkActivated.connect( self.mainWindow.iface.mainWindow().findChild( QWidget, "MessageLog").show) msgLabel.linkActivated.connect( self.mainWindow.iface.mainWindow().raise_) self.mainWindow.infoBar.pushItem( QgsMessageBarItem(msgLabel, Qgis.Warning))
def setup_value_mapping_panels(self, classification): """Setup value mapping panel in the right panel. :param classification: Classification definition. :type classification: dict """ # Set text in the label layer_purpose = self.parent.step_kw_purpose.selected_purpose() layer_subcategory = self.parent.step_kw_subcategory. \ selected_subcategory() if is_raster_layer(self.parent.layer): description_text = classify_raster_question % ( layer_subcategory['name'], layer_purpose['name'], classification['name']) dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly) active_band = self.parent.step_kw_band_selector.selected_band() unique_values = numpy.unique(numpy.array( dataset.GetRasterBand(active_band).ReadAsArray())) field_type = 0 # Convert datatype to a json serializable type if numpy.issubdtype(unique_values.dtype, float): unique_values = [float(i) for i in unique_values] else: unique_values = [int(i) for i in unique_values] else: field = self.parent.step_kw_field.selected_fields() field_index = self.parent.layer.fields().indexFromName(field) field_type = self.parent.layer.fields()[field_index].type() description_text = classify_vector_question % ( layer_subcategory['name'], layer_purpose['name'], classification['name'], field.upper()) unique_values = list(self.parent.layer.uniqueValues(field_index)) # Set description description_label = QLabel(description_text) description_label.setWordWrap(True) self.right_layout.addWidget(description_label) self.list_unique_values = QListWidget() self.list_unique_values.setDragDropMode(QAbstractItemView.DragDrop) self.list_unique_values.setDefaultDropAction(Qt.MoveAction) self.tree_mapping_widget = QTreeWidget() self.tree_mapping_widget.setDragDropMode(QAbstractItemView.DragDrop) self.tree_mapping_widget.setDefaultDropAction(Qt.MoveAction) self.tree_mapping_widget.header().hide() self.tree_mapping_widget.itemChanged.connect( self.update_dragged_item_flags) value_mapping_layout = QHBoxLayout() value_mapping_layout.addWidget(self.list_unique_values) value_mapping_layout.addWidget(self.tree_mapping_widget) self.right_layout.addLayout(value_mapping_layout) default_classes = classification['classes'] # Assign unique values to classes (according to default) unassigned_values = list() assigned_values = dict() for default_class in default_classes: assigned_values[default_class['key']] = list() for unique_value in unique_values: if (unique_value is None or (hasattr(unique_value, 'isNull') and unique_value.isNull())): # Don't classify features with NULL value continue # Capitalization of the value and removing '_' (raw OSM data). value_as_string = str(unique_value).upper().replace('_', ' ') assigned = False for default_class in default_classes: if 'string_defaults' in default_class: # To make it case insensitive upper_string_defaults = [ c.upper() for c in default_class['string_defaults']] in_string_default = ( value_as_string in upper_string_defaults) condition_1 = field_type > 9 and in_string_default else: condition_1 = False condition_2 = ( field_type < 10 and 'numeric_default_min' in default_class and 'numeric_default_max' in default_class and (default_class['numeric_default_min'] <= unique_value < default_class['numeric_default_max'])) if condition_1 or condition_2: assigned_values[default_class['key']] += [unique_value] assigned = True break if not assigned: # add to unassigned values list otherwise unassigned_values += [unique_value] self.populate_classified_values( unassigned_values, assigned_values, default_classes, self.list_unique_values, self.tree_mapping_widget ) # Current value map for exposure and classification available_classifications = self.value_maps.get( self.active_exposure['key']) if not available_classifications: return # Get active one current_classification = available_classifications.get( classification['key']) if not current_classification: return # Should come from metadata current_value_map = current_classification.get('classes') if not current_value_map: return unassigned_values = list() assigned_values = dict() for default_class in default_classes: assigned_values[default_class['key']] = list() for unique_value in unique_values: if (unique_value is None or (hasattr(unique_value, 'isNull') and unique_value.isNull())): # Don't classify features with NULL value continue # check in value map assigned = False for key, value_list in list(current_value_map.items()): if unique_value in value_list and key in assigned_values: assigned_values[key] += [unique_value] assigned = True if not assigned: unassigned_values += [unique_value] self.populate_classified_values( unassigned_values, assigned_values, default_classes, self.list_unique_values, self.tree_mapping_widget )
def setup_thresholds_panel(self, classification): """Setup threshold panel in the right panel. :param classification: Classification definition. :type classification: dict """ # Set text in the label layer_purpose = self.parent.step_kw_purpose.selected_purpose() layer_subcategory = self.parent.step_kw_subcategory.\ selected_subcategory() if is_raster_layer(self.parent.layer): active_band = self.parent.step_kw_band_selector.selected_band() layer_extent = self.parent.layer.extent() statistics = self.parent.layer.dataProvider().bandStatistics( active_band, QgsRasterBandStats.All, layer_extent, 0) description_text = continuous_raster_question % ( layer_purpose['name'], layer_subcategory['name'], classification['name'], statistics.minimumValue, statistics.maximumValue) else: field_name = self.parent.step_kw_field.selected_fields() field_index = self.parent.layer.fields().lookupField(field_name) min_value_layer = self.parent.layer.minimumValue(field_index) max_value_layer = self.parent.layer.maximumValue(field_index) description_text = continuous_vector_question % ( layer_purpose['name'], layer_subcategory['name'], field_name, classification['name'], min_value_layer, max_value_layer) # Set description description_label = QLabel(description_text) description_label.setWordWrap(True) self.right_layout.addWidget(description_label) if self.thresholds: thresholds = self.thresholds else: thresholds = self.parent.get_existing_keyword('thresholds') selected_unit = self.parent.step_kw_unit.selected_unit()['key'] self.threshold_classes = OrderedDict() classes = classification.get('classes') # Sort by value, put the lowest first classes = sorted(classes, key=lambda the_key: the_key['value']) grid_layout_thresholds = QGridLayout() for i, the_class in enumerate(classes): class_layout = QHBoxLayout() # Class label class_label = QLabel(the_class['name']) # Min label min_label = QLabel(tr('Min >')) # Min value as double spin min_value_input = QDoubleSpinBox() # TODO(IS) We can set the min and max depends on the unit, later min_value_input.setMinimum(0) min_value_input.setMaximum(999999) if thresholds.get(self.active_exposure['key']): exposure_thresholds = thresholds.get( self.active_exposure['key']) if exposure_thresholds.get(classification['key']): exposure_thresholds_classifications = exposure_thresholds\ .get(classification['key']) min_value_input.setValue( exposure_thresholds_classifications['classes'][ the_class['key']][0]) else: default_min = the_class['numeric_default_min'] if isinstance(default_min, dict): default_min = the_class[ 'numeric_default_min'][selected_unit] min_value_input.setValue(default_min) else: default_min = the_class['numeric_default_min'] if isinstance(default_min, dict): default_min = the_class[ 'numeric_default_min'][selected_unit] min_value_input.setValue(default_min) min_value_input.setSingleStep(0.1) # Max label max_label = QLabel(tr('Max <=')) # Max value as double spin max_value_input = QDoubleSpinBox() # TODO(IS) We can set the min and max depends on the unit, later max_value_input.setMinimum(0) max_value_input.setMaximum(999999) if thresholds.get(self.active_exposure['key']): exposure_thresholds = thresholds.get( self.active_exposure['key']) if exposure_thresholds.get(classification['key']): exposure_thresholds_classifications = exposure_thresholds \ .get(classification['key']) max_value_input.setValue( exposure_thresholds_classifications['classes'][ the_class['key']][1]) else: default_max = the_class['numeric_default_max'] if isinstance(default_max, dict): default_max = the_class[ 'numeric_default_max'][selected_unit] max_value_input.setValue(default_max) else: default_max = the_class['numeric_default_max'] if isinstance(default_max, dict): default_max = the_class[ 'numeric_default_max'][selected_unit] max_value_input.setValue(default_max) max_value_input.setSingleStep(0.1) # Add to class_layout class_layout.addWidget(min_label) class_layout.addWidget(min_value_input) class_layout.addWidget(max_label) class_layout.addWidget(max_value_input) class_layout.setStretch(0, 1) class_layout.setStretch(1, 2) class_layout.setStretch(2, 1) class_layout.setStretch(3, 2) # Add to grid_layout grid_layout_thresholds.addWidget(class_label, i, 0) grid_layout_thresholds.addLayout(class_layout, i, 1) self.threshold_classes[the_class['key']] = [ min_value_input, max_value_input] grid_layout_thresholds.setColumnStretch(0, 1) grid_layout_thresholds.setColumnStretch(0, 2) def min_max_changed(double_spin_index, mode): """Slot when min or max value change. :param double_spin_index: The index of the double spin. :type double_spin_index: int :param mode: The flag to indicate the min or max value. :type mode: int """ if mode == MAX_VALUE_MODE: current_max_value = list(self.threshold_classes.values())[ double_spin_index][1] target_min_value = list(self.threshold_classes.values())[ double_spin_index + 1][0] if current_max_value.value() != target_min_value.value(): target_min_value.setValue(current_max_value.value()) elif mode == MIN_VALUE_MODE: current_min_value = list(self.threshold_classes.values())[ double_spin_index][0] target_max_value = list(self.threshold_classes.values())[ double_spin_index - 1][1] if current_min_value.value() != target_max_value.value(): target_max_value.setValue(current_min_value.value()) # Set behaviour for k, v in list(self.threshold_classes.items()): index = list(self.threshold_classes.keys()).index(k) if index < len(self.threshold_classes) - 1: # Max value changed v[1].valueChanged.connect(partial( min_max_changed, double_spin_index=index, mode=MAX_VALUE_MODE)) if index > 0: # Min value v[0].valueChanged.connect(partial( min_max_changed, double_spin_index=index, mode=MIN_VALUE_MODE)) grid_layout_thresholds.setSpacing(0) self.right_layout.addLayout(grid_layout_thresholds)
def update_personal_preset_view(self): """Update the presets displayed.""" preset_folder = query_preset() files = filter( lambda folder: os.path.isdir(join(preset_folder, folder)), os.listdir(preset_folder)) self.dialog.list_personal_preset_mp.clear() for file in files: file_path = join(preset_folder, file, file + '.json') with open(file_path, encoding='utf8') as json_file: data = json.load(json_file, object_hook=as_enum) name = data['file_name'] item = QListWidgetItem(self.dialog.list_personal_preset_mp) item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) self.dialog.list_personal_preset_mp.addItem(item) preset = QFrame() preset.setObjectName('FramePreset') preset.setFrameStyle(QFrame.StyledPanel) preset.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hbox = QHBoxLayout() vbox = QVBoxLayout() label_name = QLabel(name) label_name.setStyleSheet('font-weight: bold;') label_name.setWordWrap(True) vbox.addWidget(label_name) for label in data['description']: if not label: label = tr('No description') real_label = QLabel(label) real_label.setWordWrap(True) vbox.addWidget(real_label) hbox.addItem(vbox) button_edit = QPushButton() button_remove = QPushButton() button_edit.setIcon( QIcon(QgsApplication.iconPath("mActionToggleEditing.svg"))) button_remove.setIcon( QIcon(QgsApplication.iconPath('symbologyRemove.svg'))) button_edit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button_remove.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button_edit.setToolTip(tr('Edit the preset')) button_remove.setToolTip(tr('Delete the preset')) hbox.addWidget(button_edit) hbox.addWidget(button_remove) if data['advanced']: self.listAdvanced.append(True) preset.setStyleSheet('#FramePreset { margin: 3px;' ' border: 3px solid ' + self.advanced_selected + ';' ' border-width: 1px 1px 1px 4px;}') else: self.listAdvanced.append(False) preset.setStyleSheet('#FramePreset { margin: 3px;' ' border: 3px solid ' + self.basic_selected + ';' ' border-width: 1px 1px 1px 4px;}') preset.setLayout(hbox) # Actions on click remove = partial(self.verification_remove_preset, item, name) button_remove.clicked.connect(remove) edit = partial(self.edit_preset, data) button_edit.clicked.connect(edit) item.setSizeHint(preset.minimumSizeHint()) self.dialog.list_personal_preset_mp.setItemWidget(item, preset) self.listAdvanced.append(False)
class PlanetOrderBundleWidget(QFrame): selectionChanged = pyqtSignal() def __init__(self, bundleid, bundle, item_type): super().__init__() self.bundleid = bundleid self.name = bundle["name"] self.description = bundle["description"] self.udm = bundle.get("auxiliaryFiles", "").lower().startswith("udm2") assets = bundle["assets"] self.can_harmonize = ("ortho_analytic_4b_sr" in assets or "ortho_analytic_8b_sr" in assets) self.can_harmonize = bundle.get("canHarmonize", False) self.can_clip = bundle.get("canClip", False) self.rectified = bundle["rectification"] == "orthorectified" bands = [] asset_def = PlanetClient.getInstance( ).asset_types_for_item_type_as_dict(item_type) for asset in assets: asset_bands = asset_def[asset].get("bands", []) for band in asset_bands: bands.append(band["name"]) bands = set(bands) layout = QVBoxLayout() hlayout = QHBoxLayout() hlayout.setMargin(0) self.labelName = QLabel(f"<b>{self.name}</b>") hlayout.addWidget(self.labelName) hlayout.addStretch() self.chkSelected = QCheckBox() self.chkSelected.stateChanged.connect(self.checkStateChanged) hlayout.addWidget(self.chkSelected) layout.addLayout(hlayout) self.labelDescription = QLabel(self.description) self.labelDescription.setWordWrap(True) layout.addWidget(self.labelDescription) self.labelBands = QLabel( f"Bands: {', '.join([str(b) for b in bands])}") layout.addWidget(self.labelBands) hlayouttype = QHBoxLayout() hlayouttype.setMargin(0) self.radioTiff = QRadioButton("GeoTIFF") self.radioTiff.setChecked(True) self.radioTiff.toggled.connect(self.selectionChanged.emit) hlayouttype.addWidget(self.radioTiff) self.radioNitf = QRadioButton("NITF") self.radioNitf.toggled.connect(self.selectionChanged.emit) hlayouttype.addWidget(self.radioNitf) hlayouttype.addStretch() layout.addLayout(hlayouttype) if self.udm: hlayoutudm = QHBoxLayout() hlayoutudm.setMargin(0) self.labelUdm = IconLabel("UDM2", UDM_ICON) hlayoutudm.addWidget(self.labelUdm) hlayoutudm.addStretch() layout.addLayout(hlayoutudm) layout.addStretch() self.setFrameStyle(QFrame.Panel | QFrame.Raised) self.setLayout(layout) self.checkStateChanged() def checkStateChanged(self): self.radioTiff.setEnabled(self.chkSelected.isChecked()) self.radioNitf.setEnabled(self.chkSelected.isChecked()) self.labelName.setEnabled(self.chkSelected.isChecked()) self.labelDescription.setEnabled(self.chkSelected.isChecked()) self.labelBands.setEnabled(self.chkSelected.isChecked()) if self.udm: self.labelUdm.setEnabled(self.chkSelected.isChecked()) self.selectionChanged.emit() def selected(self): return self.chkSelected.isChecked() def setSelected(self, selected, emit=False): if not emit: self.blockSignals(True) self.chkSelected.setChecked(selected) self.blockSignals(False) def filetype(self): if self.radioTiff.isChecked(): return "GeoTIFF" else: return "NITF"
class DockWidgetGimpSelectionFeature(QDockWidget): def __init__(self, iface): def setupUi(): def getLayout(parent, widgets): lyt = QGridLayout(parent) for item in widgets: if 'spam' in item: sRow, sCol = item['spam']['row'], item['spam']['col'] lyt.addWidget(item['widget'], item['row'], item['col'], sRow, sCol, Qt.AlignLeft) else: lyt.addWidget(item['widget'], item['row'], item['col'], Qt.AlignLeft) return lyt def getGroupBox(name, parent, widgets): lyt = getLayout(parent, widgets) gbx = QGroupBox(name, parent) gbx.setLayout(lyt) return gbx def getSpinBoxOffset(wgt, value): sp = QDoubleSpinBox(wgt) sp.setRange(0.0, 50.0) sp.setSingleStep(12.5) sp.setDecimals(2) sp.setSuffix(' %') sp.setValue(value) return sp def getSpinRemoveAreaPixels(wgt, value): sp = QSpinBox(wgt) sp.setRange(0, 1000) sp.setSingleStep(1) sp.setSuffix(' pixels') sp.setValue(value) return sp def getSpinBoxAzimuth(wgt, value): sp = QSpinBox(wgt) sp.setRange(0, 45) sp.setSingleStep(1) sp.setSuffix(' degrees') sp.setValue(value) msg = QCoreApplication.translate( 'GimpSelectionFeature', 'Degrees of azimuth between vertexs') sp.setToolTip(msg) return sp def getSpinBoxIteration(wgt, value): sp = QSpinBox(wgt) sp.setRange(0, 3) sp.setSingleStep(1) sp.setValue(value) return sp self.setObjectName('gimpselectionfeature_dockwidget') wgt = QWidget(self) wgt.setAttribute(Qt.WA_DeleteOnClose) # Image width = 180 self.lblLegendImages = QLabel('', wgt) self.lblLegendImages.setWordWrap(True) self.lblLegendImages.setMaximumWidth(width) l_wts = [{'widget': self.lblLegendImages, 'row': 0, 'col': 0}] name = self.formatTitleImages.format(0) self.gbxImage = getGroupBox(name, wgt, l_wts) # Transfer msg = QCoreApplication.translate('GimpSelectionFeature', 'Send image') self.btnSendImage = QPushButton(msg, wgt) # msg = QCoreApplication.translate('GimpSelectionFeature', 'Get features') self.btnGetFeatures = QPushButton(msg, wgt) msg = QCoreApplication.translate('GimpSelectionFeature', 'Remove last features') self.btnRemoveLastFeatures = QPushButton(msg, wgt) # msg = QCoreApplication.translate('GimpSelectionFeature', 'Adjust the borders') self.chkAdjustBorder = QCheckBox(msg, wgt) self.leditAnnotation = QLineEdit(wgt) self.sbRemoveAreaPixels = getSpinRemoveAreaPixels(wgt, 10) self.sbAzimuthThreshold = getSpinBoxAzimuth(wgt, 0) self.spSmoothOffset = getSpinBoxOffset(wgt, 25) self.sbSmoothIteration = getSpinBoxIteration(wgt, 1) msgLevel = QCoreApplication.translate('GimpSelectionFeature', 'Level(0-3):') msgFraction = QCoreApplication.translate( 'GimpSelectionFeature', 'Fraction of line(0-50):') l_wts = [{ 'widget': QLabel(msgLevel, wgt), 'row': 0, 'col': 0 }, { 'widget': self.sbSmoothIteration, 'row': 0, 'col': 1 }, { 'widget': QLabel(msgFraction, wgt), 'row': 1, 'col': 0 }, { 'widget': self.spSmoothOffset, 'row': 1, 'col': 1 }] msg = QCoreApplication.translate('GimpSelectionFeature', 'Smooth') gbxSmooth = getGroupBox(msg, wgt, l_wts) spamSmooth = {'row': 1, 'col': 2} msgAnnotation = QCoreApplication.translate('GimpSelectionFeature', 'Annotation:') msgRemoveArea = QCoreApplication.translate('GimpSelectionFeature', 'Remove Area:') msgRemoveVertex = QCoreApplication.translate( 'GimpSelectionFeature', 'Remove Vertex:') l_wts = [{ 'widget': QLabel(msgAnnotation, wgt), 'row': 0, 'col': 0 }, { 'widget': self.leditAnnotation, 'row': 0, 'col': 1 }, { 'widget': QLabel(msgRemoveArea, wgt), 'row': 1, 'col': 0 }, { 'widget': self.sbRemoveAreaPixels, 'row': 1, 'col': 1 }, { 'widget': QLabel(msgRemoveVertex, wgt), 'row': 2, 'col': 0 }, { 'widget': self.sbAzimuthThreshold, 'row': 2, 'col': 1 }, { 'widget': gbxSmooth, 'row': 3, 'col': 0, 'spam': spamSmooth }, { 'widget': self.chkAdjustBorder, 'row': 4, 'col': 0, }] msg = QCoreApplication.translate('GimpSelectionFeature', 'Setting') self.gbxSettingFeatures = getGroupBox(msg, wgt, l_wts) spamSetting = {'row': 1, 'col': 2} l_wts = [{ 'widget': self.btnGetFeatures, 'row': 0, 'col': 0 }, { 'widget': self.btnRemoveLastFeatures, 'row': 0, 'col': 1 }, { 'widget': self.gbxSettingFeatures, 'row': 1, 'col': 0, 'spam': spamSetting }] gbxGQ = getGroupBox("GIMP->QGIS", wgt, l_wts) l_wts = [{'widget': self.btnSendImage, 'row': 0, 'col': 0}] gbxQG = getGroupBox("QGIS->GIMP", wgt, l_wts) spamGroup = {'row': 1, 'col': 2} l_wts = [{ 'widget': gbxQG, 'row': 0, 'col': 0, 'spam': spamGroup }, { 'widget': gbxGQ, 'row': 1, 'col': 0, 'spam': spamGroup }] msg = QCoreApplication.translate('GimpSelectionFeature', 'Transfer') gbxTransfer = getGroupBox(msg, wgt, l_wts) # l_wts = [{ 'widget': self.gbxImage, 'row': 0, 'col': 0 }, { 'widget': gbxTransfer, 'row': 1, 'col': 0 }] lyt = getLayout(wgt, l_wts) lyt.setSizeConstraint(QLayout.SetMaximumSize) wgt.setLayout(lyt) self.setWidget(wgt) super().__init__("Gimp Selection Feature", iface.mainWindow()) # msg = QCoreApplication.translate('GimpSelectionFeature', 'Visibles Images(total {})') self.formatTitleImages = msg setupUi() self.gsf = GimpSelectionFeature(iface, self) # def __del__(self): # del self.gsf def clean(self): del self.gsf
def upload_data(self): if self.check_login(): if self.local_data_sources.count() == 0: return if self.db_connections.count() == 0: QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab.")) return if not self.ui.cbUploadDatabase.currentIndex() >= 0: QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data.")) return db_name = self.ui.cbUploadDatabase.currentText() if not self.db_connections.isPortOpen(db_name): uri = self.db_connections.cloud_layer_uri(db_name, "", "") host = str(uri.host()) port = uri.port() QMessageBox.critical(self, self.tr("Network Error"), self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port))) return # disable update of local data sources during upload, as there are # temporary layers added and removed self.do_update_local_data_sources = False self.statusBar().showMessage(self.tr("Uploading data...")) self.setCursor(Qt.WaitCursor) self.ui.btnUploadData.hide() self.ui.spinner.start() self.ui.progressWidget.show() # Map<data_source, {schema: schema, table: table, layers: layers}> data_sources_items = {} for row in range(0, self.ui.tblLocalLayers.rowCount()): data_source = unicode( self.ui.tblLocalLayers.item( row, self.COLUMN_DATA_SOURCE).text()) layers = self.local_data_sources.layers(data_source) if layers is not None: schema_name = unicode( self.ui.tblLocalLayers.cellWidget( row, self.COLUMN_SCHEMA_NAME).currentText()) table_name = unicode( self.ui.tblLocalLayers.item( row, self.COLUMN_TABLE_NAME).text()) data_sources_items[data_source] = { u'schema': unicode(schema_name), u'table': unicode(table_name), u'layers': layers} login_info = self.api.check_login(version_info=self._version_info()) try: self.maxSize = login_info['max_storage'] self.maxDBs = login_info['max_dbs'] except: self.maxSize = 50 self.maxDBs = 5 try: self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize)) upload_ok = True except Exception as e: ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_() upload_ok = False self.ui.spinner.stop() self.ui.progressWidget.hide() self.ui.btnUploadData.show() self.unsetCursor() self.statusBar().showMessage("") # Refresh local layers self.do_update_local_data_sources = True self.update_local_layers() # Refresh used space after upload self.db_size(self.db_connections) if upload_ok: # Show save project dialog save_dialog = QDialog(self) save_dialog.setWindowTitle(self.tr("Save Project")) save_dialog.setLayout(QVBoxLayout()) header = QWidget() header.setLayout(QVBoxLayout()) label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database.")) label.setWordWrap(True) header.layout().addWidget(label) label = QLabel(self.tr("Choose were to save the modified project:")) label.setWordWrap(True) header.layout().addWidget(label) save_dialog.layout().setContentsMargins(0, 0, 0, 0) save_dialog.layout().addWidget(header) initialPath = QgsProject.instance().fileName() if not initialPath: initialPath = QSettings().value("/UI/lastProjectDir", ".") fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files")) fd.setParent(save_dialog, Qt.Widget) fd.setOption(QFileDialog.DontUseNativeDialog) fd.setAcceptMode(QFileDialog.AcceptSave) save_dialog.layout().addWidget(fd) header.layout().setContentsMargins(fd.layout().contentsMargins()) fd.accepted.connect(save_dialog.accept) fd.rejected.connect(save_dialog.reject) if save_dialog.exec_() == QDialog.Accepted: files = list(fd.selectedFiles()) if files: QgsProject.instance().setFileName(files[0]) self.iface.actionSaveProject().trigger() # Switch to map tab self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
class DockWidgetGimpSelectionFeature(QDockWidget): def __init__(self, iface): def setupUi(): def getLayout(parent, widgets): lyt = QGridLayout( parent ) for item in widgets: if 'spam' in item: sRow, sCol = item['spam']['row'], item['spam']['col'] lyt.addWidget( item['widget'], item['row'], item['col'], sRow, sCol, Qt.AlignLeft ) else: lyt.addWidget( item['widget'], item['row'], item['col'], Qt.AlignLeft ) return lyt def getGroupBox(name, parent, widgets): lyt = getLayout( parent, widgets ) gbx = QGroupBox(name, parent ) gbx.setLayout( lyt ) return gbx def getSpinBoxOffset(wgt, value): sp = QDoubleSpinBox( wgt) sp.setRange(0.0, 50.0) sp.setSingleStep(12.5) sp.setDecimals(2) sp.setSuffix(' %') sp.setValue(value) return sp def getSpinRemoveAreaPixels(wgt, value): sp = QSpinBox( wgt) sp.setRange(0, 1000) sp.setSingleStep(1) sp.setSuffix(' pixels') sp.setValue(value) return sp def getSpinBoxAzimuth(wgt, value): sp = QSpinBox( wgt) sp.setRange(0, 45) sp.setSingleStep(1) sp.setSuffix(' degrees') sp.setValue(value) msg = QCoreApplication.translate('GimpSelectionFeature', 'Degrees of azimuth between vertexs') sp.setToolTip( msg ) return sp def getSpinBoxIteration(wgt, value): sp = QSpinBox( wgt) sp.setRange(0, 3) sp.setSingleStep(1) sp.setValue(value) return sp self.setObjectName('gimpselectionfeature_dockwidget') wgt = QWidget( self ) wgt.setAttribute(Qt.WA_DeleteOnClose) # Image width = 180 self.lblLegendImages = QLabel('', wgt ) self.lblLegendImages.setWordWrap( True ) self.lblLegendImages.setMaximumWidth(width ) l_wts = [ { 'widget': self.lblLegendImages, 'row': 0, 'col': 0 } ] name = self.formatTitleImages.format(0) self.gbxImage = getGroupBox(name, wgt, l_wts) # Transfer msg = QCoreApplication.translate('GimpSelectionFeature', 'Send image') self.btnSendImage = QPushButton(msg, wgt ) # msg = QCoreApplication.translate('GimpSelectionFeature', 'Get features') self.btnGetFeatures = QPushButton( msg, wgt ) msg = QCoreApplication.translate('GimpSelectionFeature', 'Remove last features') self.btnRemoveLastFeatures = QPushButton( msg, wgt ) # msg = QCoreApplication.translate('GimpSelectionFeature', 'Adjust the borders' ) self.chkAdjustBorder = QCheckBox( msg, wgt ) self.leditAnnotation = QLineEdit( wgt ) self.sbRemoveAreaPixels = getSpinRemoveAreaPixels( wgt, 10 ) self.sbAzimuthThreshold = getSpinBoxAzimuth( wgt, 0 ) self.spSmoothOffset = getSpinBoxOffset( wgt, 25 ) self.sbSmoothIteration = getSpinBoxIteration( wgt, 1) msgLevel = QCoreApplication.translate('GimpSelectionFeature','Level(0-3):') msgFraction = QCoreApplication.translate('GimpSelectionFeature','Fraction of line(0-50):') l_wts = [ { 'widget': QLabel( msgLevel, wgt ), 'row': 0, 'col': 0 }, { 'widget': self.sbSmoothIteration, 'row': 0, 'col': 1 }, { 'widget': QLabel( msgFraction, wgt ), 'row': 1, 'col': 0 }, { 'widget': self.spSmoothOffset, 'row': 1, 'col': 1 } ] msg = QCoreApplication.translate('GimpSelectionFeature', 'Smooth') gbxSmooth = getGroupBox( msg, wgt, l_wts) spamSmooth = { 'row': 1, 'col': 2 } msgAnnotation = QCoreApplication.translate('GimpSelectionFeature', 'Annotation:' ) msgRemoveArea = QCoreApplication.translate('GimpSelectionFeature', 'Remove Area:' ) msgRemoveVertex = QCoreApplication.translate('GimpSelectionFeature', 'Remove Vertex:' ) l_wts = [ { 'widget': QLabel( msgAnnotation, wgt ), 'row': 0, 'col': 0 }, { 'widget': self.leditAnnotation, 'row': 0, 'col': 1 }, { 'widget': QLabel( msgRemoveArea, wgt ), 'row': 1, 'col': 0 }, { 'widget': self.sbRemoveAreaPixels, 'row': 1, 'col': 1 }, { 'widget': QLabel( msgRemoveVertex, wgt ), 'row': 2, 'col': 0 }, { 'widget': self.sbAzimuthThreshold, 'row': 2, 'col': 1 }, { 'widget': gbxSmooth, 'row': 3, 'col': 0, 'spam': spamSmooth }, { 'widget': self.chkAdjustBorder, 'row': 4, 'col': 0, } ] msg = QCoreApplication.translate('GimpSelectionFeature', 'Setting' ) self.gbxSettingFeatures = getGroupBox( msg, wgt, l_wts) spamSetting = { 'row': 1, 'col': 2 } l_wts = [ { 'widget': self.btnGetFeatures, 'row': 0, 'col': 0 }, { 'widget': self.btnRemoveLastFeatures, 'row': 0, 'col': 1 }, { 'widget': self.gbxSettingFeatures, 'row': 1, 'col': 0, 'spam': spamSetting } ] gbxGQ = getGroupBox( "GIMP->QGIS", wgt, l_wts) l_wts = [ { 'widget': self.btnSendImage, 'row': 0, 'col': 0 } ] gbxQG = getGroupBox( "QGIS->GIMP", wgt, l_wts) spamGroup = { 'row': 1, 'col': 2 } l_wts = [ { 'widget': gbxQG, 'row': 0, 'col': 0, 'spam': spamGroup }, { 'widget': gbxGQ, 'row': 1, 'col': 0, 'spam': spamGroup } ] msg = QCoreApplication.translate('GimpSelectionFeature', 'Transfer' ) gbxTransfer = getGroupBox( msg, wgt, l_wts) # l_wts = [ { 'widget': self.gbxImage, 'row': 0, 'col': 0 }, { 'widget': gbxTransfer, 'row': 1, 'col': 0 } ] lyt = getLayout( wgt, l_wts ) lyt.setSizeConstraint( QLayout.SetMaximumSize ) wgt.setLayout( lyt ) self.setWidget( wgt ) super().__init__( "Gimp Selection Feature", iface.mainWindow() ) # msg = QCoreApplication.translate('GimpSelectionFeature', 'Visibles Images(total {})') self.formatTitleImages = msg setupUi() self.gsf = GimpSelectionFeature( iface, self ) def __del__(self): del self.gsf
class ProgressDialog(QDialog): """ Progress dialog shows progress bar for algorithm. """ def __init__(self, iface): QDialog.__init__(self, iface.mainWindow()) self.workerThread = None self.state = False self.resultStatus = None self.doReRun = False self.wasCanceled = False self.wasSuccessful = False self.savedProj = None self.result = None self.messageTxt = { 'msg_optimierung': self.tr('Berechnung der optimalen Stuetzenpositionen...'), 'msg_seillinie': self.tr('Berechnung der optimale Seillinie...') } # Build GUI Elements self.setWindowTitle(self.tr("SEILAPLAN wird ausgefuehrt")) self.resize(500, 100) self.container = QVBoxLayout() self.progressBar = QProgressBar(self) self.progressBar.setMinimumWidth(500) self.statusLabel = QLabel(self) self.hbox = QHBoxLayout() self.cancelButton = QDialogButtonBox() self.closeButton = QDialogButtonBox() self.resultLabel = QLabel(self) self.resultLabel.setMaximumWidth(500) self.resultLabel.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)) self.resultLabel.setWordWrap(True) spacer1 = QSpacerItem(20, 20, QSizePolicy.Fixed, QSizePolicy.Fixed) self.rerunButton = QPushButton(self.tr("zurueck zum Startfenster")) self.rerunButton.setVisible(False) spacer2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.cancelButton.setStandardButtons(QDialogButtonBox.Cancel) self.cancelButton.button(QDialogButtonBox.Cancel).setText(self.tr("Abbrechen")) self.cancelButton.clicked.connect(self.onAbort) self.closeButton.setStandardButtons(QDialogButtonBox.Close) self.closeButton.button(QDialogButtonBox.Close).setText(self.tr("Schliessen")) self.closeButton.clicked.connect(self.onClose) self.hbox.addWidget(self.rerunButton) self.hbox.addItem(spacer2) self.hbox.addWidget(self.cancelButton) self.hbox.setAlignment(self.cancelButton, Qt.AlignHCenter) self.hbox.addWidget(self.closeButton) self.hbox.setAlignment(self.closeButton, Qt.AlignHCenter) self.closeButton.hide() self.container.addWidget(self.progressBar) self.container.addWidget(self.statusLabel) self.container.addWidget(self.resultLabel) self.container.addItem(spacer1) self.container.addLayout(self.hbox) self.container.setSizeConstraint(QLayout.SetFixedSize) self.setLayout(self.container) # noinspection PyMethodMayBeStatic def tr(self, message, **kwargs): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString Parameters ---------- **kwargs """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate(type(self).__name__, message) def setThread(self, workerThread): self.workerThread = workerThread self.connectThreadSignals() def connectThreadSignals(self): # Connect signals of thread self.workerThread.sig_jobEnded.connect(self.jobEnded) self.workerThread.sig_jobError.connect(self.onError) self.workerThread.sig_value.connect(self.valueFromThread) self.workerThread.sig_range.connect(self.rangeFromThread) self.workerThread.sig_text.connect(self.textFromThread) self.workerThread.sig_result.connect(self.resultFromThread) self.rerunButton.clicked.connect(self.onRerun) def run(self): # Show modal dialog window (QGIS is still responsive) self.show() # start event loop self.exec() def jobEnded(self, success): self.setWindowTitle("SEILAPLAN") if success: self.progressBar.setValue(self.progressBar.maximum()) self.wasSuccessful = True # Close progress dialog so that adjustment window can be opened self.close() else: # If there was an abort by the user self.statusLabel.setText(self.tr("Berechnungen abgebrochen.")) self.progressBar.setValue(self.progressBar.minimum()) self.finallyDo() def valueFromThread(self, value): self.progressBar.setValue(int(value)) def rangeFromThread(self, range_vals): self.progressBar.setRange(int(round(range_vals[0])), int(round(range_vals[1]))) def maxFromThread(self, max): self.progressBar.setValue(self.progressBar.maximum()) def textFromThread(self, message): self.statusLabel.setText(self.messageTxt[message]) def resultFromThread(self, resultStatus): self.resultStatus = resultStatus # resultStatus: # 1 = Optimization successful # 2 = Cable takes off from support # 3 = Optimization partially successful def onAbort(self): self.setWindowTitle('SEILAPLAN') self.statusLabel.setText(self.tr( 'Laufender Prozess wird abgebrochen...')) self.workerThread.cancel() # Terminates process cleanly self.wasCanceled = True def onError(self, exception_string): self.setWindowTitle(self.tr('SEILAPLAN: Berechnung fehlgeschlagen')) self.statusLabel.setText(self.tr('Ein Fehler ist aufgetreten:')) self.resultLabel.setText(self.tr(exception_string)) self.resultLabel.setHidden(False) self.progressBar.setValue(self.progressBar.minimum()) self.setLayout(self.container) self.finallyDo() def onRerun(self): self.doReRun = True self.onClose() def finallyDo(self): self.rerunButton.setVisible(True) self.cancelButton.hide() self.closeButton.show() def onClose(self): self.close()
def upload_data(self): if self.check_login(): if self.local_data_sources.count() == 0: return if self.db_connections.count() == 0: QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab.")) return if not self.ui.cbUploadDatabase.currentIndex() >= 0: QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data.")) return db_name = self.ui.cbUploadDatabase.currentText() if not self.db_connections.isPortOpen(db_name): uri = self.db_connections.cloud_layer_uri(db_name, "", "") host = str(uri.host()) port = uri.port() QMessageBox.critical(self, self.tr("Network Error"), self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port))) return # disable update of local data sources during upload, as there are # temporary layers added and removed self.do_update_local_data_sources = False self.statusBar().showMessage(self.tr("Uploading data...")) self.setCursor(Qt.WaitCursor) self.ui.btnUploadData.hide() self.ui.spinner.start() self.ui.progressWidget.show() # Map<data_source, {table: table, layers: layers}> data_sources_items = {} for row in range(0, self.ui.tblLocalLayers.rowCount()): data_source = unicode( self.ui.tblLocalLayers.item( row, self.COLUMN_DATA_SOURCE).text()) layers = self.local_data_sources.layers(data_source) if layers is not None: table_name = unicode( self.ui.tblLocalLayers.item( row, self.COLUMN_TABLE_NAME).text()) data_sources_items[data_source] = { u'table': unicode(table_name), u'layers': layers} login_info = self.api.check_login(version_info=self._version_info()) try: self.maxSize = login_info['max_storage'] self.maxDBs = login_info['max_dbs'] except: self.maxSize = 50 self.maxDBs = 5 try: self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize)) upload_ok = True except Exception as e: ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_() upload_ok = False self.ui.spinner.stop() self.ui.progressWidget.hide() self.ui.btnUploadData.show() self.unsetCursor() self.statusBar().showMessage("") # Refresh local layers self.do_update_local_data_sources = True self.update_local_layers() # Refresh used space after upload self.db_size(self.db_connections) if upload_ok: # Show save project dialog save_dialog = QDialog(self) save_dialog.setWindowTitle(self.tr("Save Project")) save_dialog.setLayout(QVBoxLayout()) header = QWidget() header.setLayout(QVBoxLayout()) label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database.")) label.setWordWrap(True) header.layout().addWidget(label) label = QLabel(self.tr("Choose were to save the modified project:")) label.setWordWrap(True) header.layout().addWidget(label) save_dialog.layout().setContentsMargins(0, 0, 0, 0) save_dialog.layout().addWidget(header) initialPath = QgsProject.instance().fileName() if not initialPath: initialPath = QSettings().value("/UI/lastProjectDir", ".") fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files")) fd.setParent(save_dialog, Qt.Widget) fd.setOption(QFileDialog.DontUseNativeDialog) fd.setAcceptMode(QFileDialog.AcceptSave) save_dialog.layout().addWidget(fd) header.layout().setContentsMargins(fd.layout().contentsMargins()) fd.accepted.connect(save_dialog.accept) fd.rejected.connect(save_dialog.reject) if save_dialog.exec_() == QDialog.Accepted: files = list(fd.selectedFiles()) if files: QgsProject.instance().setFileName(files[0]) self.iface.actionSaveProject().trigger() # Switch to map tab self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
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 FieldMappingTab(QWidget, object): """Widget class for field mapping.""" def __init__(self, field_group=None, parent=None, iface=None): """Constructor.""" # Init from parent class QWidget.__init__(self, parent) # Attributes self.layer = None self.metadata = {} self.parent = parent self.iface = iface self.field_group = field_group self.setting = QSettings() # TODO(IS): Make dynamic # Main container self.main_layout = QVBoxLayout() # Inner layout self.header_layout = QHBoxLayout() self.content_layout = QHBoxLayout() self.footer_layout = QHBoxLayout() # Header self.header_label = QLabel() self.header_label.setWordWrap(True) # Content self.field_layout = QVBoxLayout() self.parameter_layout = QHBoxLayout() self.field_description = QLabel(tr('List of fields')) self.field_list = QListWidget() self.field_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.field_list.setDragDropMode(QAbstractItemView.DragDrop) self.field_list.setDefaultDropAction(Qt.MoveAction) self.field_list.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) # noinspection PyUnresolvedReferences self.field_list.itemSelectionChanged.connect(self.update_footer) # Footer self.footer_label = QLabel() self.footer_label.setWordWrap(True) # Parameters self.extra_parameters = [(GroupSelectParameter, GroupSelectParameterWidget)] self.parameters = [] self.parameter_container = None # Adding to layout self.header_layout.addWidget(self.header_label) self.field_layout.addWidget(self.field_description) self.field_layout.addWidget(self.field_list) self.field_layout.setSizeConstraint(QLayout.SetMaximumSize) self.content_layout.addLayout(self.field_layout) self.content_layout.addLayout(self.parameter_layout) self.footer_layout.addWidget(self.footer_label) self.main_layout.addLayout(self.header_layout) self.main_layout.addLayout(self.content_layout) self.main_layout.addLayout(self.footer_layout) self.setLayout(self.main_layout) def set_layer(self, layer, keywords=None): """Set layer and update UI accordingly. :param layer: A vector layer that has been already patched with metadata. :type layer: QgsVectorLayer :param keywords: Custom keyword for the layer. :type keywords: dict, None """ self.layer = layer if keywords is not None: self.metadata = keywords else: # Check if it has keywords if not hasattr(layer, 'keywords'): message = 'Layer {layer_name} does not have keywords.'.format( layer_name=layer.name()) raise KeywordNotFoundError(message) self.metadata = layer.keywords self.populate_parameter() def populate_field_list(self, excluded_fields=None): """Helper to add field of the layer to the list. :param excluded_fields: List of field that want to be excluded. :type excluded_fields: list """ # Populate fields list if excluded_fields is None: excluded_fields = [] self.field_list.clear() for field in self.layer.fields(): # Skip if it's excluded if field.name() in excluded_fields: continue # Skip if it's not number (float, int, etc) if field.type() not in qvariant_numbers: continue field_item = QListWidgetItem(self.field_list) field_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field.name()) field_item.setText(field.name()) self.field_list.addItem(field_item) def populate_parameter(self): """Helper to setup the parameter widget.""" used_fields = [] self.parameters = [] for field in self.field_group.get('fields', []): selected_option = DO_NOT_REPORT options = OrderedDict([ (DO_NOT_REPORT, { 'label': tr('Do not report'), 'value': None, 'type': STATIC, 'constraint': {} }), ]) # Example: count if field['absolute']: # Used in field options field_label = tr('Count fields') else: # Example: ratio # Used in field options field_label = tr('Ratio fields') global_default_value = get_inasafe_default_value_qsetting( self.setting, GLOBAL, field['key']) options[GLOBAL_DEFAULT] = { 'label': tr('Global default'), 'value': global_default_value, 'type': STATIC, 'constraint': {} } default_custom_value = get_inasafe_default_value_qsetting( self.setting, RECENT, field['key']) custom_value = self.metadata.get('inasafe_default_values', {}).get( field['key'], default_custom_value) if field['key'] in self.metadata.get('inasafe_default_values', {}): if custom_value == global_default_value: selected_option = GLOBAL_DEFAULT else: selected_option = CUSTOM_VALUE min_value = field['default_value'].get('min_value', 0) max_value = field['default_value'].get('max_value', 100) default_step = (max_value - min_value) / 100.0 step = field['default_value'].get('increment', default_step) options[CUSTOM_VALUE] = { 'label': tr('Custom'), 'value': custom_value, 'type': SINGLE_DYNAMIC, 'constraint': { 'min': min_value, 'max': max_value, 'step': step } } custom_fields = self.metadata.get('inasafe_fields', {}).get(field['key'], []) if field['key'] in self.metadata.get('inasafe_fields', {}): selected_option = FIELDS if isinstance(custom_fields, str): custom_fields = [custom_fields] options[FIELDS] = { 'label': field_label, 'value': custom_fields, 'type': MULTIPLE_DYNAMIC, 'constraint': {} } used_fields.extend(custom_fields) parameter = GroupSelectParameter() parameter.guid = field['key'] parameter.name = field['name'] parameter.options = options parameter.selected = selected_option parameter.help_text = field['help_text'] parameter.description = field['description'] self.parameters.append(parameter) self.parameter_container = ParameterContainer( parameters=self.parameters, extra_parameters=self.extra_parameters, vertical=False) self.parameter_container.setup_ui() constraints = self.field_group.get('constraints', {}) for key, value in list(constraints.items()): self.parameter_container.add_validator( validators[key], kwargs=value['kwargs'], validation_message=value['message']) self.parameter_layout.addWidget(self.parameter_container) default_ratio_help_text = tr( 'By default, InaSAFE will calculate the default ratio ' 'however users have the option to include this in the ' 'analysis report. If you do not want to see the default ' 'results in the report choose "do not report".') # Set move or copy if self.field_group.get('exclusive', False): # If exclusive, do not add used field. self.populate_field_list(excluded_fields=used_fields) # Use move action since it's exclusive self.field_list.setDefaultDropAction(Qt.MoveAction) # Just make sure that the signal is disconnected try: # noinspection PyUnresolvedReferences self.field_list.itemChanged.disconnect(self.drop_remove) except TypeError: pass # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can only map one field to one concept.') else: # If not exclusive, add all field. self.populate_field_list() # Use copy action since it's not exclusive self.field_list.setDefaultDropAction(Qt.CopyAction) # noinspection PyUnresolvedReferences self.field_list.itemChanged.connect( partial(self.drop_remove, field_list=self.field_list)) self.connect_drop_remove_parameter() # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can map one field to more than one concepts.') self.header_label.setText(header_text) def get_parameter_value(self): """Get parameter of the tab. :returns: Dictionary of parameters by type in this format: {'fields': {}, 'values': {}}. :rtype: dict """ parameters = self.parameter_container.get_parameters(True) field_parameters = {} value_parameters = {} for parameter in parameters: if parameter.selected_option_type() in [SINGLE_DYNAMIC, STATIC]: value_parameters[parameter.guid] = parameter.value elif parameter.selected_option_type() == MULTIPLE_DYNAMIC: field_parameters[parameter.guid] = parameter.value return {'fields': field_parameters, 'values': value_parameters} def update_footer(self): """Update footer when the field list change.""" field_item = self.field_list.currentItem() if not field_item: self.footer_label.setText('') return field_name = field_item.data(Qt.UserRole) field = self.layer.fields().field(field_name) index = self.layer.fields().lookupField(field_name) unique_values = list(self.layer.uniqueValues(index)) pretty_unique_values = ', '.join([str(v) for v in unique_values[:10]]) footer_text = tr('Field type: {0}\n').format(field.typeName()) footer_text += tr('Unique values: {0}').format(pretty_unique_values) self.footer_label.setText(footer_text) def connect_drop_remove_parameter(self): parameter_widgets = self.parameter_container.get_parameter_widgets() for parameter_widget in parameter_widgets: field_list = parameter_widget.widget().list_widget field_list.itemChanged.connect( partial(self.drop_remove, field_list=field_list)) @staticmethod def drop_remove(*args, **kwargs): """Action when we need to remove dropped item. :param *args: Position arguments. :type *args: list :param kwargs: Keywords arguments. :type kwargs: dict """ dropped_item = args[0] field_list = kwargs['field_list'] num_duplicate = 0 for i in range(field_list.count()): if dropped_item.text() == field_list.item(i).text(): num_duplicate += 1 if num_duplicate > 1: # Notes(IS): For some reason, removeItemWidget is not working. field_list.takeItem(field_list.row(dropped_item))
def onAbout(self): self.about_dlg = QWidget() vlayout = QVBoxLayout() l = QLabel(""" <h1>QGIS GML Application Schema Toolbox</h1> <h3>Version: {}</h3> <p>This plugin is a prototype aiming at experimenting with the manipulation of <b>Complex Features</b> streams.</p> <p>Two modes are available: <ul><li>A mode where the <b>initial XML hierarchical view</b> is preserved. In this mode, an XML instance is represented by a unique QGIS vector layer with a column that stores the XML subtree for each feature. Augmented tools are available to identify a feature or display the attribute table of the layer.</li> <li>A mode where the XML hierarchical data is first <b>converted to a relational database</b>. In this mode, the data is spread accross different QGIS layers. Links between tables are declared as QGIS relations and "relation reference" widgets. It then allows to use the standard QGIS attribute table (in "forms" mode) to navigate the relationel model.</li> </ul> <p>Custom Qt-based viewers can be run on XML elements of given types.</p> <p>Teams involved in the development of the current plugin: <ul> <li><a href="http://www.oslandia.com">Oslandia</a> (current version of the QGIS plugin, and first proof of concept)</li> <li><a href="http://www.spatialys.com">Spatialys</a> (GMLAS driver in OGR)</li> <li><a href="http://www.camptocamp.com">camptocamp</a> (former version of the plugin)</li> </ul> </p> <p>Funders involved: <ul> <li><a href="http://www.brgm.fr">BRGM</a></li> <li><a href="https://www.eea.europa.eu/">European Environment Agency</a> (Copernicus funding)</li> <li><b>The Association of Finnish Local and Regional Authorities</b> (through <a href="http://www.gispo.fi">Gispo.fi</a>)</li> </ul> </p> """.format(plugin_version())) l.setWordWrap(True) vlayout.addWidget(l) hlayout = QHBoxLayout() hlayout2 = QHBoxLayout() l2 = QLabel() l2.setPixmap( QPixmap(os.path.join(os.path.dirname(__file__), "logo_brgm.svg")).scaledToWidth( 200, Qt.SmoothTransformation)) l3 = QLabel() l3.setPixmap( QPixmap(os.path.join(os.path.dirname(__file__), "logo_eea.png")).scaledToWidth( 200, Qt.SmoothTransformation)) l4 = QLabel() l4.setPixmap( QPixmap( os.path.join(os.path.dirname(__file__), "logo_oslandia.png")).scaledToWidth( 150, Qt.SmoothTransformation)) l5 = QLabel() l5.setPixmap( QPixmap( os.path.join(os.path.dirname(__file__), "logo_spatialys.png")).scaledToWidth( 100, Qt.SmoothTransformation)) l6 = QLabel() l6.setPixmap( QPixmap(os.path.join(os.path.dirname(__file__), "logo_c2c.svg")).scaledToWidth( 100, Qt.SmoothTransformation)) hlayout.addWidget(l2) hlayout.addWidget(l3) vlayout.addLayout(hlayout) hlayout2.addWidget(l4) hlayout2.addWidget(l5) hlayout2.addWidget(l6) vlayout.addLayout(hlayout2) self.about_dlg.setLayout(vlayout) self.about_dlg.setWindowTitle(plugin_name()) self.about_dlg.setWindowModality(Qt.WindowModal) self.about_dlg.show() self.about_dlg.resize(600, 800)
class QmsSearchResultItemWidget(QWidget): def __init__(self, geoservice, image_ba, parent=None, extent_renderer=None): QWidget.__init__(self, parent) self.extent_renderer = extent_renderer self.layout = QHBoxLayout(self) self.layout.setContentsMargins(5, 10, 5, 10) self.setLayout(self.layout) self.service_icon = QLabel(self) self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.service_icon.resize(24, 24) qimg = QImage.fromData(image_ba) pixmap = QPixmap.fromImage(qimg) self.service_icon.setPixmap(pixmap) self.layout.addWidget(self.service_icon) self.service_desc_layout = QGridLayout(self) self.service_desc_layout.setSpacing(0) self.layout.addLayout(self.service_desc_layout) self.service_name = QLabel(self) self.service_name.setTextFormat(Qt.RichText) self.service_name.setWordWrap(True) self.service_name.setText(u" <strong> {} </strong>".format( geoservice.get('name', u""))) self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3) self.service_type = QLabel(self) self.service_type.setTextFormat(Qt.RichText) self.service_type.setWordWrap(True) self.service_type.setText(geoservice.get('type', u"").upper() + " ") self.service_desc_layout.addWidget(self.service_type, 1, 0) self.service_deteils = QLabel(self) self.service_deteils.setTextFormat(Qt.RichText) self.service_deteils.setWordWrap(True) self.service_deteils.setOpenExternalLinks(True) self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format( Client().geoservice_info_url(geoservice.get('id', u"")), self.tr('details'))) self.service_desc_layout.addWidget(self.service_deteils, 1, 1) self.service_report = QLabel(self) self.service_report.setTextFormat(Qt.RichText) self.service_report.setWordWrap(True) self.service_report.setOpenExternalLinks(True) self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format( Client().geoservice_report_url(geoservice.get('id', u"")), self.tr('report a problem'))) self.service_desc_layout.addWidget(self.service_report, 1, 2) self.service_desc_layout.setColumnStretch(2, 1) self.status_label = QLabel(self) self.status_label.setTextFormat(Qt.RichText) self.status_label.setText(u'\u2022') status = geoservice.get('cumulative_status', u'') if status == 'works': self.status_label.setStyleSheet("color: green; font-size: 30px") if status == 'failed': self.status_label.setStyleSheet("color: red; font-size: 30px") if status == 'problematic': self.status_label.setStyleSheet("color: yellow; font-size: 30px") self.layout.addWidget(self.status_label) self.addButton = QToolButton() self.addButton.setText(self.tr("Add")) self.addButton.clicked.connect(self.addToMap) self.layout.addWidget(self.addButton) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) self.geoservice = geoservice self.image_ba = image_ba def addToMap(self): try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) client = Client() client.set_proxy(*QGISSettings.get_qgis_proxy()) geoservice_info = client.get_geoservice_info(self.geoservice) ds = DataSourceSerializer.read_from_json(geoservice_info) add_layer_to_map(ds) CachedServices().add_service(self.geoservice, self.image_ba) except Exception as ex: plPrint(unicode(ex)) pass finally: QApplication.restoreOverrideCursor() def mouseDoubleClickEvent(self, event): self.addToMap() def enterEvent(self, event): extent = self.geoservice.get('extent', None) if self.extent_renderer and extent: if ';' in extent: extent = extent.split(';')[1] geom = QgsGeometry.fromWkt(extent) self.extent_renderer.show_feature(geom) def leaveEvent(self, event): if self.extent_renderer: self.extent_renderer.clear_feature()
class FieldMappingTab(QWidget, object): """Widget class for field mapping.""" def __init__(self, field_group=None, parent=None, iface=None): """Constructor.""" # Init from parent class QWidget.__init__(self, parent) # Attributes self.layer = None self.metadata = {} self.parent = parent self.iface = iface self.field_group = field_group self.setting = QSettings() # TODO(IS): Make dynamic # Main container self.main_layout = QVBoxLayout() # Inner layout self.header_layout = QHBoxLayout() self.content_layout = QHBoxLayout() self.footer_layout = QHBoxLayout() # Header self.header_label = QLabel() self.header_label.setWordWrap(True) # Content self.field_layout = QVBoxLayout() self.parameter_layout = QHBoxLayout() self.field_description = QLabel(tr('List of fields')) self.field_list = QListWidget() self.field_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.field_list.setDragDropMode(QAbstractItemView.DragDrop) self.field_list.setDefaultDropAction(Qt.MoveAction) self.field_list.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Expanding) # noinspection PyUnresolvedReferences self.field_list.itemSelectionChanged.connect(self.update_footer) # Footer self.footer_label = QLabel() self.footer_label.setWordWrap(True) # Parameters self.extra_parameters = [ (GroupSelectParameter, GroupSelectParameterWidget) ] self.parameters = [] self.parameter_container = None # Adding to layout self.header_layout.addWidget(self.header_label) self.field_layout.addWidget(self.field_description) self.field_layout.addWidget(self.field_list) self.field_layout.setSizeConstraint(QLayout.SetMaximumSize) self.content_layout.addLayout(self.field_layout) self.content_layout.addLayout(self.parameter_layout) self.footer_layout.addWidget(self.footer_label) self.main_layout.addLayout(self.header_layout) self.main_layout.addLayout(self.content_layout) self.main_layout.addLayout(self.footer_layout) self.setLayout(self.main_layout) def set_layer(self, layer, keywords=None): """Set layer and update UI accordingly. :param layer: A vector layer that has been already patched with metadata. :type layer: QgsVectorLayer :param keywords: Custom keyword for the layer. :type keywords: dict, None """ self.layer = layer if keywords is not None: self.metadata = keywords else: # Check if it has keywords if not hasattr(layer, 'keywords'): message = 'Layer {layer_name} does not have keywords.'.format( layer_name=layer.name()) raise KeywordNotFoundError(message) self.metadata = layer.keywords self.populate_parameter() def populate_field_list(self, excluded_fields=None): """Helper to add field of the layer to the list. :param excluded_fields: List of field that want to be excluded. :type excluded_fields: list """ # Populate fields list if excluded_fields is None: excluded_fields = [] self.field_list.clear() for field in self.layer.fields(): # Skip if it's excluded if field.name() in excluded_fields: continue # Skip if it's not number (float, int, etc) if field.type() not in qvariant_numbers: continue field_item = QListWidgetItem(self.field_list) field_item.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field.name()) field_item.setText(field.name()) self.field_list.addItem(field_item) def populate_parameter(self): """Helper to setup the parameter widget.""" used_fields = [] self.parameters = [] for field in self.field_group.get('fields', []): selected_option = DO_NOT_REPORT options = OrderedDict([ (DO_NOT_REPORT, { 'label': tr('Do not report'), 'value': None, 'type': STATIC, 'constraint': {} }), ]) # Example: count if field['absolute']: # Used in field options field_label = tr('Count fields') else: # Example: ratio # Used in field options field_label = tr('Ratio fields') global_default_value = get_inasafe_default_value_qsetting( self.setting, GLOBAL, field['key']) options[GLOBAL_DEFAULT] = { 'label': tr('Global default'), 'value': global_default_value, 'type': STATIC, 'constraint': {} } default_custom_value = get_inasafe_default_value_qsetting( self.setting, RECENT, field['key']) custom_value = self.metadata.get( 'inasafe_default_values', {}).get( field['key'], default_custom_value) if field['key'] in self.metadata.get( 'inasafe_default_values', {}): if custom_value == global_default_value: selected_option = GLOBAL_DEFAULT else: selected_option = CUSTOM_VALUE min_value = field['default_value'].get('min_value', 0) max_value = field['default_value'].get('max_value', 100) default_step = (max_value - min_value) / 100.0 step = field['default_value'].get('increment', default_step) options[CUSTOM_VALUE] = { 'label': tr('Custom'), 'value': custom_value, 'type': SINGLE_DYNAMIC, 'constraint': { 'min': min_value, 'max': max_value, 'step': step } } custom_fields = self.metadata.get('inasafe_fields', {}).get( field['key'], []) if field['key'] in self.metadata.get('inasafe_fields', {}): selected_option = FIELDS if isinstance(custom_fields, str): custom_fields = [custom_fields] options[FIELDS] = { 'label': field_label, 'value': custom_fields, 'type': MULTIPLE_DYNAMIC, 'constraint': {} } used_fields.extend(custom_fields) parameter = GroupSelectParameter() parameter.guid = field['key'] parameter.name = field['name'] parameter.options = options parameter.selected = selected_option parameter.help_text = field['help_text'] parameter.description = field['description'] self.parameters.append(parameter) self.parameter_container = ParameterContainer( parameters=self.parameters, extra_parameters=self.extra_parameters, vertical=False ) self.parameter_container.setup_ui() constraints = self.field_group.get('constraints', {}) for key, value in list(constraints.items()): self.parameter_container.add_validator( validators[key], kwargs=value['kwargs'], validation_message=value['message']) self.parameter_layout.addWidget(self.parameter_container) default_ratio_help_text = tr( 'By default, InaSAFE will calculate the default ratio ' 'however users have the option to include this in the ' 'analysis report. If you do not want to see the default ' 'results in the report choose "do not report".') # Set move or copy if self.field_group.get('exclusive', False): # If exclusive, do not add used field. self.populate_field_list(excluded_fields=used_fields) # Use move action since it's exclusive self.field_list.setDefaultDropAction(Qt.MoveAction) # Just make sure that the signal is disconnected try: # noinspection PyUnresolvedReferences self.field_list.itemChanged.disconnect(self.drop_remove) except TypeError: pass # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can only map one field to one concept.') else: # If not exclusive, add all field. self.populate_field_list() # Use copy action since it's not exclusive self.field_list.setDefaultDropAction(Qt.CopyAction) # noinspection PyUnresolvedReferences self.field_list.itemChanged.connect( partial(self.drop_remove, field_list=self.field_list)) self.connect_drop_remove_parameter() # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can map one field to more than one concepts.') self.header_label.setText(header_text) def get_parameter_value(self): """Get parameter of the tab. :returns: Dictionary of parameters by type in this format: {'fields': {}, 'values': {}}. :rtype: dict """ parameters = self.parameter_container.get_parameters(True) field_parameters = {} value_parameters = {} for parameter in parameters: if parameter.selected_option_type() in [SINGLE_DYNAMIC, STATIC]: value_parameters[parameter.guid] = parameter.value elif parameter.selected_option_type() == MULTIPLE_DYNAMIC: field_parameters[parameter.guid] = parameter.value return { 'fields': field_parameters, 'values': value_parameters } def update_footer(self): """Update footer when the field list change.""" field_item = self.field_list.currentItem() if not field_item: self.footer_label.setText('') return field_name = field_item.data(Qt.UserRole) field = self.layer.fields().field(field_name) index = self.layer.fields().lookupField(field_name) unique_values = list(self.layer.uniqueValues(index)) pretty_unique_values = ', '.join([str(v) for v in unique_values[:10]]) footer_text = tr('Field type: {0}\n').format(field.typeName()) footer_text += tr('Unique values: {0}').format(pretty_unique_values) self.footer_label.setText(footer_text) def connect_drop_remove_parameter(self): parameter_widgets = self.parameter_container.get_parameter_widgets() for parameter_widget in parameter_widgets: field_list = parameter_widget.widget().list_widget field_list.itemChanged.connect( partial(self.drop_remove, field_list=field_list)) @staticmethod def drop_remove(*args, **kwargs): """Action when we need to remove dropped item. :param *args: Position arguments. :type *args: list :param kwargs: Keywords arguments. :type kwargs: dict """ dropped_item = args[0] field_list = kwargs['field_list'] num_duplicate = 0 for i in range(field_list.count()): if dropped_item.text() == field_list.item(i).text(): num_duplicate += 1 if num_duplicate > 1: # Notes(IS): For some reason, removeItemWidget is not working. field_list.takeItem(field_list.row(dropped_item))
class MutantWidget(QWidget, Ui_Widget): def __init__(self, iface): self.hasqwt = has_qwt self.hasmpl = has_mpl self.haspqg = has_pyqtgraph self.layerMap = dict() self.statsChecked = False self.ymin = 0 self.ymax = 365 self.isActive = False self.mt_enabled = False # Statistics (>=1.9) self.statsSampleSize = 2500000 self.stats = {} # stats per layer self.layersSelected = [] self.layerBands = dict() self.iface = iface self.canvas = self.iface.mapCanvas() # self.legend = self.iface.legendInterface() self.legend = QgsProject.instance().layerTreeRoot() self.logger = logging.getLogger('.'.join( (__name__, self.__class__.__name__))) QWidget.__init__(self) self.setupUi(self) self.tabWidget.setEnabled(False) self.plotOnMove.setChecked(QSettings().value( 'plugins/mutant/mouseClick', False, type=bool)) self.leYMin.setText(str(self.ymin)) self.leYMax.setText(str(self.ymax)) self.tracker = TimeTracker(self, self.canvas) self.filter = ApplyFilter(self, self.canvas) if has_mpl: self.mpl_cust = MplSettings(self, self.canvas) # self.setupUi_plot() # don't setup plot until Graph(1) tab is clicked - workaround for bug # #7450 # qgis will still crash in some cases, but at least the tool can be # used in Table mode self.qwtPlot = None self.mplPlot = None self.mplLine = None self.plotLibSelector.currentIndexChanged.connect(self.change_plot) self.tabWidget.currentChanged.connect(self.tabWidgetChanged) self.layerSelection.currentIndexChanged.connect(self.update_layers) self.bandSelection.currentIndexChanged.connect(self.update_layers) self.selectionTable.cellChanged.connect(self.layerSelected) self.enableMTAnalysesCheckBox.toggled.connect( self.on_mt_analysis_toggled) self.selectionStringLineEdit.textChanged.connect(self.update_layers) self.yAutoCheckBox.toggled.connect(self.y_auto_toggle) self.toggleMutant.toggled.connect(self.catch_errors) self.exportPushButton.clicked.connect(self.export_values) # TODO Get Export from graph values # self.exportPushButton_2.clicked.connect(self.xxxx) self.registry = QgsProject.instance() self.registry.layersAdded.connect(self.catch_errors) self.registry.layersRemoved.connect(self.catch_errors) self.setupUi_plot() def catch_errors(self): if self.toggleMutant.isChecked(): layers = self.activeRasterLayers() if len(layers) == 0: if self.canvas.layerCount() > 0: text = self.tr("Mutant: No valid layers to display - " "add Rasterlayers") self.pop_messagebar(text) self.changeActive(False) else: text = self.tr("Mutant: No valid layers to display") self.pop_messagebar(text) self.changeActive(False) self.values = [] return else: return else: return def y_auto_toggle(self, state): # User has toggled automatic (default) y min/max values if state == 1: self.leYMin.setEnabled(False) self.leYMax.setEnabled(False) self.leYMin.setText(str(self.ymin)) self.leYMax.setText(str(self.ymax)) else: self.leYMin.setEnabled(True) self.leYMax.setEnabled(True) def pop_messagebar(self, text, d_time=5): if d_time == 0: self.iface.messageBar().pushWidget( self.iface.messageBar().createMessage(text), Qgis.Warning) else: self.iface.messageBar().pushWidget( self.iface.messageBar().createMessage(text), Qgis.Warning, d_time) def setupUi_plot(self): # plot self.plotLibSelector.setVisible(False) self.enableStatistics.setVisible(False) # stats by default because estimated are fast self.enableStatistics.setChecked(True) plot_count = 0 self.mplLine = None # make sure to invalidate when layers change if self.hasqwt: # Page 2 - qwt self.plotLibSelector.addItem('Qwt') plot_count += 1 # Setup Qwt Plot Area in Widget self.qwtPlot = QwtPlot(self.stackedWidget) self.qwtPlot.setAutoFillBackground(False) self.qwtPlot.setObjectName("qwtPlot") self.curve = QwtPlotCurve() self.curve.setSymbol( QwtSymbol(QwtSymbol.Ellipse, QBrush(Qt.white), QPen(Qt.red, 2), QSize(9, 9))) self.curve.attach(self.qwtPlot) # Size Policy ??? sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.qwtPlot.sizePolicy().hasHeightForWidth()) self.qwtPlot.setSizePolicy(sizePolicy) # Size Policy ??? self.qwtPlot.updateGeometry() self.stackedWidget.addWidget(self.qwtPlot) self.qwt_widgetnumber = self.stackedWidget.indexOf(self.qwtPlot) if self.hasmpl: # Page 3 - setup matplotlib self.plotLibSelector.addItem('matplotlib') # If matplotlib is the only one self.toggleInterpolation.setEnabled(True) self.toggleInterpolation.setVisible(True) plot_count += 1 self.mplBackground = None # http://www.scipy.org/Cookbook/Matplotlib/Animations self.mplFig = plt.Figure(facecolor='w', edgecolor='g', linewidth=0.0) self.mpl_subplot = self.mplFig.add_subplot(111) self.pltCanvas = FigureCanvasQTAgg(self.mplFig) self.pltCanvas.setParent(self.stackedWidget) self.pltCanvas.setAutoFillBackground(False) self.pltCanvas.setObjectName("mplPlot") self.mplPlot = self.pltCanvas self.mplPlot.updateGeometry() self.stackedWidget.addWidget(self.mplPlot) self.mpl_widgetnumber = self.stackedWidget.indexOf(self.mplPlot) if self.haspqg: # Page 3 - setup PyQtGraph self.plotLibSelector.addItem('PyQtGraph') plot_count += 1 # Setup PyQtGraph stuff pg.setConfigOption('background', 'w') pg.setConfigOption('foreground', 'k') self.pqg_axis = DateTimeAxis(orientation='bottom') self.pqg_plot_widget = pg.PlotWidget( parent=self.stackedWidget, axisItems={'bottom': self.pqg_axis}) self.pqg_plot_item = self.pqg_plot_widget.getPlotItem() self.pqg_plot_widget.updateGeometry() self.stackedWidget.addWidget(self.pqg_plot_widget) self.pqg_widgetnumber = self.stackedWidget.indexOf( self.pqg_plot_widget) # on zoom change do: self.pqg_plot_item.sigXRangeChanged.connect(self.refresh_ticks) if plot_count > 1: self.plotLibSelector.setEnabled(True) self.plotLibSelector.setVisible(True) self.plotLibSelector.setCurrentIndex(0) if self.hasqwt: self.plotLibSelector.setCurrentIndex(self.qwt_widgetnumber) elif self.hasmpl: self.plotLibSelector.setCurrentIndex(self.mpl_widgetnumber) else: self.plotLibSelector.setCurrentIndex(self.pqg_widgetnumber) self.change_plot() elif plot_count == 1: self.plotLibSelector.setCurrentIndex(0) self.change_plot() else: # can only be 0 if nothing else matched message_text = "Mutant cannot find any graphiclibrary for " \ "creating plots. Please install either Qwt >= 5.0 " \ ",matplotlib >= 1.0 or PyQtGraph >= 0.9.8!" self.plot_message = QLabel(message_text) self.plot_message.setWordWrap(True) self.stackedWidget.addWidget(self.plot_message) self.pop_messagebar(message_text) def change_plot(self): if self.stackedWidget.count() > 1: if self.plotLibSelector.currentText() == 'Qwt': self.stackedWidget.setCurrentIndex(self.qwt_widgetnumber) self.toggleInterpolation.setDisabled(True) self.toggleInterpolation.setVisible(False) elif self.plotLibSelector.currentText() == 'matplotlib': self.stackedWidget.setCurrentIndex(self.mpl_widgetnumber) self.toggleInterpolation.setEnabled(True) self.toggleInterpolation.setVisible(True) self.mpl_subplot.clear() elif self.plotLibSelector.currentText() == 'PyQtGraph': self.stackedWidget.setCurrentIndex(self.pqg_widgetnumber) self.toggleInterpolation.setDisabled(True) self.toggleInterpolation.setVisible(False) self.pqg_plot_widget.clear() elif self.stackedWidget.count() == 1: self.stackedWidget.setCurrentIndex(0) else: self.stackedWidget.setCurrentIndex(-1) def keyPressEvent(self, e): if (e.modifiers() == Qt.ControlModifier or e.modifiers() == Qt.MetaModifier) and e.key() == Qt.Key_C: items = '' for rec in range(self.valueTable.rowCount()): items += '"' + self.valueTable.item( rec, 0).text() + '",' + self.valueTable.item( rec, 1).text() + "\n" if not items == '': clipboard = QApplication.clipboard() clipboard.setText(items) else: QWidget.keyPressEvent(self, e) def changeActive(self, active, gui=True): if self.isActive == active: return self.isActive = active if active: self.toggleMutant.setCheckState(Qt.Checked) self.canvas.layersChanged.connect(self.invalidatePlot) if not self.plotOnMove.isChecked(): self.canvas.xyCoordinates.connect(self.printValue) else: self.toggleMutant.setCheckState(Qt.Unchecked) self.canvas.layersChanged.disconnect(self.invalidatePlot) if self.plotOnMove.isChecked(): self.canvas.xyCoordinates.disconnect(self.printValue) if gui: self.tabWidget.setEnabled(active) if active: self.labelStatus.setText(self.tr("Mutant is enabled!")) # FIXME: Only on Options Tab? if self.tabWidget.currentIndex() == 2: self.update_layers() else: self.labelStatus.setText(self.tr("")) # use this to clear plot when deactivated # self.values=[] # self.showValues() def activeRasterLayers(self, index=None): layers = [] allLayers = [] if not index: index = self.layerSelection.currentIndex() if index == 0: # visible layers allLayers = self.canvas.layers() elif index == 1 or index == 3: # All layers | by selection string allLayers = [ltl.layer() for ltl in self.legend.findLayers()] elif index == 2: # Manual selection for layer in [ltl.layer() for ltl in self.legend.findLayers()]: if layer.id() in self.layersSelected: allLayers.append(layer) for layer in allLayers: if index == 3: # by selection string # Check if the layer name matches our filter and skip it if it # doesn't if not self.name_matches_filter(layer.name()): continue if layer is not None and layer.isValid() and \ layer.type() == QgsMapLayer.RasterLayer and \ layer.dataProvider() and \ (layer.dataProvider().capabilities() & QgsRasterDataProvider.IdentifyValue): layers.append(layer) return layers def activeBandsForRaster(self, layer): activeBands = [] if self.bandSelection.currentIndex() == 1 and layer.renderer(): activeBands = layer.renderer().usesBands() elif self.bandSelection.currentIndex() == 2: if layer.bandCount() == 1: activeBands = [1] else: activeBands = self.layerBands[layer.id()] if ( layer.id() in self.layerBands) else [] else: activeBands = list(range(1, layer.bandCount() + 1)) return activeBands def printValue(self, position): if debug > 0: print(position) if not position: return if self.tabWidget.currentIndex() == 2: return if debug > 0: print("%d active rasters, %d canvas layers" % (len(self.activeRasterLayers()), self.canvas.layerCount())) layers = self.activeRasterLayers() self.labelStatus.setText( self.tr('Coordinate:') + ' (%f, %f)' % (position.x(), position.y())) need_extremum = (self.tabWidget.currentIndex() == 1 ) # if plot is shown # count the number of required rows and remember the raster layers nrow = 0 rasterlayers = [] layersWOStatistics = [] for layer in layers: nrow += layer.bandCount() rasterlayers.append(layer) # check statistics for each band if need_extremum: for i in range(1, layer.bandCount() + 1): has_stats = self.get_statistics(layer, i) is not None if not layer.id() in self.layerMap and not has_stats \ and not layer in layersWOStatistics: layersWOStatistics.append(layer) if layersWOStatistics and not self.statsChecked: self.calculateStatistics(layersWOStatistics) irow = 0 self.values = [] self.ymin = 1e38 self.ymax = -1e38 mapCanvasSrs = self.iface.mapCanvas().mapSettings().destinationCrs() # TODO - calculate the min/max values only once, # instead of every time!!! # And keep them in a dict() with key=layer.id() counter = 0 for layer in rasterlayers: layer_name = str(layer.name()) layer_srs = layer.crs() pos = position # if given no position, get dummy values if position is None: pos = QgsPoint(0, 0) # transform points if needed elif not mapCanvasSrs == layer_srs: srsTransform = QgsCoordinateTransform(mapCanvasSrs, layer_srs) try: pos = srsTransform.transform(position) except QgsCsException as err: continue if True: if not layer.dataProvider(): continue ident = None if position is not None: canvas = self.iface.mapCanvas() # first test if point is within map layer extent # maintain same behaviour as in 1.8 and print out of extent if not layer.dataProvider().extent().contains(pos): ident = dict() for iband in range(1, layer.bandCount() + 1): ident[iband] = str(self.tr('out of extent')) # we can only use context if layer is not projected elif layer.dataProvider().crs() != \ canvas.mapSettings().destinationCrs(): ident = layer.dataProvider().identify( pos, QgsRaster.IdentifyFormatValue).results() else: extent = canvas.extent() width = round(extent.width() / canvas.mapUnitsPerPixel()) height = round(extent.height() / canvas.mapUnitsPerPixel()) extent = canvas.mapSettings().mapToLayerCoordinates( layer, extent) ident = layer.dataProvider().identify( pos, QgsRaster.IdentifyFormatValue, canvas.extent(), width, height).results() if not len(ident) > 0: continue # if given no position, set values to 0 if position is None and ident is not None and iter( ident.keys()) is not None: for key in ident.keys(): ident[key] = layer.dataProvider().noDataValue(key) # bands displayed depends on cbxBands (all / active / selected) activeBands = self.activeBandsForRaster(layer) for iband in activeBands: # loop over the active bands layer_name_with_band = layer_name if ident is not None and len(ident) > 1: layer_name_with_band += ' ' + layer.bandName(iband) if not ident or iband not in ident: bandvalue = "?" else: bandvalue = ident[iband] if bandvalue is None: bandvalue = "no data" # different x-Axis depending on if we want to use time or # not if self.mt_enabled: layer_time = self.tracker.get_time_for_layer(layer) if layer_time is None: continue else: # pyqtgraph enabled convert date to epoch graphlib = self.plotLibSelector.currentText() if graphlib == 'PyQtGraph': layer_time = time.mktime( layer_time.timetuple()) # overwrite tup = (layer_name_with_band, layer_time, str(bandvalue)) else: tup = (layer_name_with_band, counter + 1, str(bandvalue)) self.values.append(tup) if need_extremum: # estimated statistics stats = self.get_statistics(layer, iband) if stats: self.ymin = min(self.ymin, stats.minimumValue) self.ymax = max(self.ymax, stats.maximumValue) counter += 1 # Update the ymin, ymax line edits if required if self.yAutoCheckBox.isChecked(): self.leYMin.setText(str(self.ymin)) self.leYMax.setText(str(self.ymax)) self.values.sort(key=operator.itemgetter(1)) if len(self.values) == 0: self.labelStatus.setText(self.tr("No valid bands to display")) self.showValues(position) def showValues(self, position): if self.tabWidget.currentIndex() == 1: if len(self.values) == 0: # FIXME don't plot if there is no data to plot... return else: self.plot() else: self.printInTable(position) def export_values(self): path = QFileDialog.getSaveFileName(self, 'Save File', '', 'CSV(*.csv)') if path != "": with open(str(path), 'wb') as stream: writer = csv.writer(stream) for row in range(self.valueTable.rowCount()): rowdata = [] for column in range(self.valueTable.columnCount()): item = self.valueTable.item(row, column) if item is not None: rowdata.append(str(item.text()).encode('utf8')) else: rowdata.append('') writer.writerow(rowdata) def calculateStatistics(self, layersWOStatistics): self.invalidatePlot(False) self.statsChecked = True layernames = [] for layer in layersWOStatistics: if not layer.id() in self.layerMap: layernames.append(layer.name()) if len(layernames) != 0: if not self.enableStatistics.isChecked(): for layer in layersWOStatistics: self.layerMap[layer.id()] = True return else: print('ERROR, no layers to get stats for') save_state = self.isActive self.changeActive(False, False) # deactivate # calculate statistics for layer in layersWOStatistics: if not layer.id() in self.layerMap: self.layerMap[layer.id()] = True for i in range(1, layer.bandCount() + 1): self.get_statistics(layer, i, True) if save_state: self.changeActive(True, False) # activate if necessary # get cached statistics for layer and band or None if not calculated def get_statistics(self, layer, bandNo, force=False): if layer in self.stats: if bandNo in self.stats[layer]: return self.stats[layer][bandNo] else: self.stats[layer] = {} if force or \ layer.dataProvider().hasStatistics(bandNo, QgsRasterBandStats.Min | QgsRasterBandStats.Min, QgsRectangle(), self.statsSampleSize): self.stats[layer][bandNo] = \ layer.dataProvider().bandStatistics(bandNo, QgsRasterBandStats.Min | QgsRasterBandStats.Min, QgsRectangle(), self.statsSampleSize) return self.stats[layer][bandNo] return None def printInTable(self, position): self.valueTable.clearContents() # set table widget row count self.valueTable.setRowCount(len(self.values)) posX = position.x() posY = position.y() irow = 0 for layername, xval, value in self.values: if self.valueTable.item(irow, 0) is None: # create the item self.valueTable.setItem(irow, 0, QTableWidgetItem()) self.valueTable.setItem(irow, 1, QTableWidgetItem()) self.valueTable.setItem(irow, 2, QTableWidgetItem()) self.valueTable.setItem(irow, 3, QTableWidgetItem()) self.valueTable.setItem(irow, 4, QTableWidgetItem()) self.valueTable.item(irow, 0).setText(layername) self.valueTable.item(irow, 3).setText(str(posX)) self.valueTable.item(irow, 4).setText(str(posY)) if self.mt_enabled: graphlib = self.plotLibSelector.currentText() if graphlib == 'PyQtGraph': date = datetime.datetime.fromtimestamp(xval) self.valueTable.item(irow, 2).setText(str(date)) else: self.valueTable.item(irow, 2).setText(str(xval)) # else: # self.valueTable.item(irow, 2).setText('') if value == 'no data' or value == 'out of extent': self.valueTable.item(irow, 1).setText(value) else: value = float(value) if self.cbxDigits.isChecked(): try: x = str(self.spinDigits.value()) y = "{:." + x + "f}" value = y.format(value) except ValueError: pass self.valueTable.item(irow, 1).setData(Qt.EditRole, value) irow += 1 def refresh_ticks(self): # At this point the X extent has been changed (e.g. zoom) and we need # to redraw ticks and associated labels major_tick_times = [] # define label width as minimum label distance readable label_width = 40 # First determine what visible x range we are looking at view_min_x = self.pqg_plot_item.getViewBox().viewRange()[0][0] view_max_x = self.pqg_plot_item.getViewBox().viewRange()[0][1] min_date_axis = datetime.datetime.fromtimestamp(view_min_x) view_range = view_max_x - view_min_x # Determine the current width of the plot in px rect_bound = self.pqg_plot_item.viewGeometry() width = rect_bound.width() major_label_count = (width - label_width) // label_width major_label_spacing = view_range // ( major_label_count * 3600.0 * 24 * 365.25) # In major tick units min_tick_to_label_int = int( datetime.datetime.strftime(min_date_axis, '%Y')) + 1 major_label_spacing_delta = view_range / major_label_count min_tick_to_label_stamp = ( datetime.datetime(min_tick_to_label_int, 1, 1) - datetime.datetime(1970, 1, 1)).total_seconds() major_tick_times.append( (int(min_tick_to_label_stamp), str( datetime.datetime.fromtimestamp( min_tick_to_label_stamp).strftime('%Y')))) next_tick_to_label_int = int( (datetime.datetime(min_tick_to_label_int, 1, 1) - datetime.datetime(1970, 1, 1)).total_seconds()) next_tick_to_label_stamp = min_tick_to_label_stamp while True: next_tick_to_label_int += int(major_label_spacing_delta) next_tick_to_label_stamp += major_label_spacing_delta if next_tick_to_label_int > int(view_max_x): break major_tick_times.append( (next_tick_to_label_int, str( datetime.datetime.fromtimestamp( next_tick_to_label_stamp).strftime('%Y')))) # An experiment # ticks = [ # [(631152000.34, '1990'), (788918400, '1995')], # [(662688000, '1991'),(694224000.46, '1992'), # (725846400, '1993'), (757382400, '1994')] # ] self.pqg_axis.setTicks([major_tick_times]) def plot(self): data_values = [] x_values = [] do_filter = self.toggleFilter.isChecked() do_interpolation = self.toggleInterpolation.isChecked() if self.hasqwt or self.hasmpl or self.haspqg: for layername, xval, value in self.values: x_values.append(xval) try: data_values.append(float(value)) except ValueError: data_values.append(None) # instead to not be plotted, be aware of min() # calculation in plotting range = affects graphs (check # there? if not data_values: data_values = [0] if self.yAutoCheckBox.isChecked(): ymin = self.ymin ymax = self.ymax else: # Beware the user may not have entered a number try: ymin = float(self.leYMin.text()) ymax = float(self.leYMax.text()) except ValueError: message = 'Valuetool: Please enter Numbers!' self.pop_messagebar(message) return # Qwt Plot if self.hasqwt and (self.plotLibSelector.currentText() == 'Qwt'): self.qwtPlot.setAxisMaxMinor(QwtPlot.xBottom, 0) # self.qwtPlot.setAxisMaxMajor(QwtPlot.xBottom,0) self.qwtPlot.setAxisScale(QwtPlot.xBottom, 1, len(self.values)) # self.qwtPlot.setAxisScale(QwtPlot.yLeft, self.ymin, self.ymax) self.qwtPlot.setAxisScale(QwtPlot.yLeft, ymin, ymax) try: qwtx, qwtydata = list( zip(*[ x for x in zip(x_values, data_values) if x[1] is not None ])) except ValueError: return self.curve.setSamples(list(range(1, len(qwtydata) + 1)), qwtydata) self.qwtPlot.replot() self.qwtPlot.setVisible(len(qwtydata) > 0) # matplotlib Plot elif self.hasmpl and (self.plotLibSelector.currentText() == 'matplotlib'): # don't clear to draw another row of data self.mpl_subplot.clear() self.mpl_cust.mpl_setup() # If Multi-temporal Analysis enabled set xAxis away from Standard # 1 to values to dates. # Plot code from here xv = np.asarray(x_values) dv = np.asarray(data_values) dvd = dv.astype(np.double) datav_mask = np.isfinite(dvd) if do_interpolation: xaxis = xv[datav_mask] yaxis = dvd[datav_mask] else: xaxis = x_values yaxis = data_values self.mpl_subplot.plot_date(xaxis, yaxis, linestyle='-', xdate=self.mt_enabled, ydate=False, marker='o', markersize=4, color='k', markerfacecolor='b', markeredgecolor='b') if self.mt_enabled: plt.xticks(rotation='vertical') self.mpl_cust.mpl_date_settings(x_values, ymin, ymax) else: self.mpl_cust.mpl_value_settings(x_values, ymin, ymax) if do_filter: derived_x, derived_y = self.filter.smooth(xaxis, yaxis) self.mpl_subplot.plot_date(derived_x, derived_y, linestyle='-', xdate=self.mt_enabled, ydate=False, marker='x', markersize=2, color='r', markerfacecolor='r', markeredgecolor='r') self.mplFig.canvas.draw() # PyQtGraph Plot elif self.haspqg and (self.plotLibSelector.currentText() == 'PyQtGraph'): # clear on plot - don't clear if additional data should be added self.pqg_plot_widget.clear() # clean canvas on call # self.pqg_plot_item.clear() # clear item # self.pqg_plot_widget.scene().removeItem(legend) self.pqg_plot_item.setYRange(ymin, ymax) style_normal = Qt.SolidLine # Qt.DashLine, Qt.DotLine, Qt.DashDotLine, Qt.DashDotDotLine, Qt.CustomDashLine style_filter = Qt.SolidLine # filter None values out of input data try: pgxaxis, pgyaxis = list( zip(*[ x for x in zip(x_values, data_values) if x[1] is not None ])) except ValueError: return self.pqg_plot_widget.plot(pgxaxis, pgyaxis, name='data', symbol='o', pen=pg.mkPen(color='k', width=1, style=style_normal)) if do_filter: derived_x, derived_y = self.filter.smooth(pgxaxis, pgyaxis) self.pqg_plot_widget.plot(derived_x, derived_y, name='filter', symbol='x', pen=pg.mkPen(color='r', width=1, style=style_filter)) def invalidatePlot(self, replot=True): if self.tabWidget.currentIndex() == 2: self.update_layers() if not self.isActive: return self.statsChecked = False if self.mplLine is not None: del self.mplLine self.mplLine = None # update empty plot if replot and self.tabWidget.currentIndex() == 1: # self.values=[] self.printValue(None) def resizeEvent(self, event): self.invalidatePlot() def tabWidgetChanged(self): if self.tabWidget.currentIndex() == 2: self.update_layers() def on_mt_analysis_toggled(self, new_state): if new_state == 1: self.mt_enabled = True if self.haspqg: self.pqg_axis.set_time_enabled(True) if self.hasqwt and self.plotLibSelector.currentText() == 'Qwt': message = 'Mutant: There is currently no support using Date ' \ 'values while using the Qwt plotlibrary' self.pop_messagebar(message, 0) self.tracker.enable_selection() self.priorityLabel.setEnabled(True) self.extractionPriorityListWidget.setEnabled(True) self.patternLabel.setEnabled(True) self.patternLineEdit.setEnabled(True) self.writeMetaDataCheckBox.setEnabled(True) self.labelStatus.setText( self.tr("Multi-temporal analysis " "enabled!")) self.cutFirst.setEnabled(True) self.dateLength.setEnabled(True) self.sampleLineEdit.setEnabled(True) self.sampleLabel.setEnabled(True) self.tracker.refresh_tracker() # Only call when mt_enabled else: self.mt_enabled = False if self.haspqg: self.pqg_axis.set_time_enabled(False) self.priorityLabel.setEnabled(False) self.extractionPriorityListWidget.setEnabled(False) self.patternLabel.setEnabled(False) self.patternLineEdit.setEnabled(False) self.writeMetaDataCheckBox.setEnabled(False) self.labelStatus.setText(self.tr("")) self.cutFirst.setEnabled(False) self.dateLength.setEnabled(False) self.sampleLineEdit.setEnabled(False) self.sampleLabel.setEnabled(False) self.tracker.disable_selection() def name_matches_filter(self, name): selection_string = self.selectionStringLineEdit.text() return fnmatch.fnmatchcase(name, selection_string) # update active layers in table def update_layers(self): if self.tabWidget.currentIndex() != 2: return if self.layerSelection.currentIndex() == 3: # by selection string self.selectionStringLineEdit.setEnabled(True) else: self.selectionStringLineEdit.setEnabled(False) if self.layerSelection.currentIndex() == 0: # visible layers layers = self.activeRasterLayers(0) elif self.layerSelection.currentIndex() == 3: # by selection string layers = self.activeRasterLayers(3) else: layers = self.activeRasterLayers(1) # All layers self.selectionTable.blockSignals(True) self.selectionTable.clearContents() self.selectionTable.setRowCount(len(layers)) self.selectionTable.horizontalHeader().resizeSection(0, 20) self.selectionTable.horizontalHeader().resizeSection(2, 20) j = 0 for layer in layers: item = QTableWidgetItem() item.setFlags(item.flags() | Qt.ItemIsUserCheckable) if self.layerSelection.currentIndex() != 2: item.setFlags(item.flags() & ~Qt.ItemIsEnabled) item.setCheckState(Qt.Checked) else: # manual selection if layer.id() in self.layersSelected: item.setCheckState(Qt.Checked) else: item.setCheckState(Qt.Unchecked) self.selectionTable.setItem(j, 0, item) item = QTableWidgetItem(layer.name()) item.setData(Qt.UserRole, layer.id()) self.selectionTable.setItem(j, 1, item) activeBands = self.activeBandsForRaster(layer) button = QToolButton() button.setIcon(QIcon(':/plugins/mutant/img/bands.jpg')) # button.setIconSize(QtCore.QSize(400, 400)) button.setPopupMode(QToolButton.InstantPopup) group = QActionGroup(button) group.setExclusive(False) group.triggered.connect(self.bandSelected) if self.bandSelection.currentIndex( ) == 2 and layer.bandCount() > 1: menu = QMenu() menu.installEventFilter(self) for iband in range(1, layer.bandCount() + 1): action = QAction(str(layer.bandName(iband)), group) action.setData([layer.id(), iband, j, False]) action.setCheckable(True) action.setChecked(iband in activeBands) menu.addAction(action) if layer.bandCount() > 1: action = QAction(str(self.tr("All")), group) action.setData([layer.id(), -1, j, True]) action.setCheckable(False) menu.addAction(action) action = QAction(str(self.tr("None")), group) action.setData([layer.id(), -1, j, False]) action.setCheckable(False) menu.addAction(action) button.setMenu(menu) else: button.setEnabled(False) self.selectionTable.setCellWidget(j, 2, button) item = QTableWidgetItem(str(activeBands)) item.setToolTip(str(activeBands)) self.selectionTable.setItem(j, 3, item) j += 1 self.selectionTable.blockSignals(False) # slot for when active layer selection has changed def layerSelected(self, row, column): if column != 0: return self.layersSelected = [] for i in range(0, self.selectionTable.rowCount()): item = self.selectionTable.item(i, 0) layer_id = self.selectionTable.item(i, 1).data(Qt.UserRole) if item and item.checkState() == Qt.Checked: self.layersSelected.append(layer_id) elif layer_id in self.layersSelected: self.layersSelected.remove(layer_id) # slot for when active band selection has changed def bandSelected(self, action): layer_id = action.data()[0] layerBand = action.data()[1] j = action.data()[2] toggleAll = action.data()[3] activeBands = self.layerBands[layer_id] if ( layer_id in self.layerBands) else [] # special actions All/None if layerBand == -1: for layer in [ltl.layer() for ltl in self.legend.findLayers()]: if layer.id() == layer_id: if toggleAll: activeBands = list(range(1, layer.bandCount() + 1)) else: activeBands = [] # toggle all band# actions group = action.parent() if group and not isinstance(group, QActionGroup): group = None if group: group.blockSignals(True) for a in group.actions(): if a.isCheckable(): a.setChecked(toggleAll) group.blockSignals(False) # any Band# action else: if action.isChecked(): activeBands.append(layerBand) else: if layerBand in activeBands: activeBands.remove(layerBand) activeBands.sort() self.layerBands[layer_id] = activeBands # update UI item = QTableWidgetItem(str(activeBands)) item.setToolTip(str(activeBands)) self.selectionTable.setItem(j, 3, item) # event filter for band selection menu, do not close after toggling each # band def eventFilter(self, obj, event): if event.type() in [QEvent.MouseButtonRelease]: if isinstance(obj, QMenu): if obj.activeAction(): if not obj.activeAction().menu(): # if the selected action does not have a submenu eat the event, but trigger the function obj.activeAction().trigger() return True return super(MutantWidget, self).eventFilter(obj, event) def shouldPrintValues(self): return self.isVisible() and not self.visibleRegion().isEmpty() and \ self.isActive and self.tabWidget.currentIndex() != 2 def toolMoved(self, position): if self.shouldPrintValues() and not self.plotOnMove.isChecked(): self.printValue( self.canvas.getCoordinateTransform().toMapCoordinates( position)) def toolPressed(self, position): if self.shouldPrintValues() and self.plotOnMove.isChecked(): self.printValue( self.canvas.getCoordinateTransform().toMapCoordinates( position))
class GroupSelectParameterWidget(GenericParameterWidget): """Widget class for Group Select Parameter.""" def __init__(self, parameter, parent=None): """Constructor. :param parameter: A GroupSelectParameter object. :type parameter: GroupSelectParameter """ QWidget.__init__(self, parent) self._parameter = parameter # Store spin box self.spin_boxes = {} # Create elements # Label (name) self.label = QLabel(self._parameter.name) # Layouts self.main_layout = QVBoxLayout() self.input_layout = QVBoxLayout() # _inner_input_layout must be filled with widget in the child class self.inner_input_layout = QVBoxLayout() self.radio_button_layout = QGridLayout() # Create radio button group self.input_button_group = QButtonGroup() # List widget self.list_widget = QListWidget() self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_widget.setDragDropMode(QAbstractItemView.DragDrop) self.list_widget.setDefaultDropAction(Qt.MoveAction) self.list_widget.setEnabled(False) self.list_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) for i, key in enumerate(self._parameter.options): value = self._parameter.options[key] radio_button = QRadioButton(value.get('label')) self.radio_button_layout.addWidget(radio_button, i, 0) if value.get('type') == SINGLE_DYNAMIC: percentage_spin_box = PercentageSpinBox(self) self.radio_button_layout.addWidget(percentage_spin_box, i, 1) percentage_spin_box.setValue(value.get('value', 0)) step = percentage_spin_box.singleStep() if step > 1: precision = 0 else: precision = len(str(step).split('.')[1]) if precision > 3: precision = 3 percentage_spin_box.setDecimals(precision) self.spin_boxes[key] = percentage_spin_box # Enable spin box depends on the selected option if self._parameter.selected == key: percentage_spin_box.setEnabled(True) else: percentage_spin_box.setEnabled(False) elif value.get('type') == STATIC: static_value = value.get('value', 0) if static_value is not None: self.radio_button_layout.addWidget( QLabel(str(static_value * 100) + ' %'), i, 1) elif value.get('type') == MULTIPLE_DYNAMIC: if self._parameter.selected == key: self.list_widget.setEnabled(True) else: self.list_widget.setEnabled(False) self.input_button_group.addButton(radio_button, i) if self._parameter.selected == key: radio_button.setChecked(True) # Help text self.help_label = QLabel(self._parameter.help_text) self.help_label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) self.help_label.setWordWrap(True) self.help_label.setAlignment(Qt.AlignTop) self.inner_input_layout.addLayout(self.radio_button_layout) self.inner_input_layout.addWidget(self.list_widget) # Put elements into layouts self.input_layout.addWidget(self.label) self.input_layout.addLayout(self.inner_input_layout) self.help_layout = QVBoxLayout() self.help_layout.addWidget(self.help_label) self.main_layout.addLayout(self.input_layout) self.main_layout.addLayout(self.help_layout) self.setLayout(self.main_layout) self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) # Update list widget self.update_list_widget() # Connect signal # noinspection PyUnresolvedReferences self.input_button_group.buttonClicked.connect( self.radio_buttons_clicked) def get_parameter(self): """Obtain list parameter object from the current widget state. :returns: A DefaultValueParameter from the current state of widget :rtype: DefaultValueParameter """ # Set value for each key for key, value in list(self._parameter.options.items()): if value.get('type') == STATIC: continue elif value.get('type') == SINGLE_DYNAMIC: new_value = self.spin_boxes.get(key).value() self._parameter.set_value_for_key(key, new_value) elif value.get('type') == MULTIPLE_DYNAMIC: # Need to iterate through all items items = [] for index in range(self.list_widget.count()): items.append(self.list_widget.item(index)) new_value = [i.text() for i in items] self._parameter.set_value_for_key(key, new_value) # Get selected radio button radio_button_checked_id = self.input_button_group.checkedId() # No radio button checked, then default value = None if radio_button_checked_id == -1: self._parameter.selected = None else: self._parameter.selected = list( self._parameter.options.keys())[radio_button_checked_id] return self._parameter def update_list_widget(self): """Update list widget when radio button is clicked.""" # Get selected radio button radio_button_checked_id = self.input_button_group.checkedId() # No radio button checked, then default value = None if radio_button_checked_id > -1: selected_dict = list( self._parameter.options.values())[radio_button_checked_id] if selected_dict.get('type') == MULTIPLE_DYNAMIC: for field in selected_dict.get('value'): # Update list widget field_item = QListWidgetItem(self.list_widget) field_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field) field_item.setText(field) self.list_widget.addItem(field_item) def radio_buttons_clicked(self): """Handler when selected radio button changed.""" # Disable all spin boxes for spin_box in list(self.spin_boxes.values()): spin_box.setEnabled(False) # Disable list widget self.list_widget.setEnabled(False) # Get selected radio button radio_button_checked_id = self.input_button_group.checkedId() if radio_button_checked_id > -1: selected_value = list( self._parameter.options.values())[radio_button_checked_id] if selected_value.get('type') == MULTIPLE_DYNAMIC: # Enable list widget self.list_widget.setEnabled(True) elif selected_value.get('type') == SINGLE_DYNAMIC: selected_key = list( self._parameter.options.keys())[radio_button_checked_id] self.spin_boxes[selected_key].setEnabled(True) def select_radio_button(self, key): """Helper to select a radio button with key. :param key: The key of the radio button. :type key: str """ key_index = list(self._parameter.options.keys()).index(key) radio_button = self.input_button_group.button(key_index) radio_button.click()
class QmsSearchResultItemWidget(QWidget): def __init__(self, geoservice, image_ba, parent=None, extent_renderer=None): QWidget.__init__(self, parent) self.extent_renderer = extent_renderer self.layout = QHBoxLayout(self) self.layout.setContentsMargins(5, 10, 5, 10) self.setLayout(self.layout) self.service_icon = QLabel(self) self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.service_icon.resize(24, 24) qimg = QImage.fromData(image_ba) pixmap = QPixmap.fromImage(qimg) self.service_icon.setPixmap(pixmap) self.layout.addWidget(self.service_icon) self.service_desc_layout = QGridLayout(self) self.service_desc_layout.setSpacing(0) self.layout.addLayout(self.service_desc_layout) self.service_name = QLabel(self) self.service_name.setTextFormat(Qt.RichText) self.service_name.setWordWrap(True) self.service_name.setText(u" <strong> {} </strong>".format(geoservice.get('name', u""))) self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3) self.service_type = QLabel(self) self.service_type.setTextFormat(Qt.RichText) self.service_type.setWordWrap(True) self.service_type.setText(geoservice.get('type', u"").upper() + " ") self.service_desc_layout.addWidget(self.service_type, 1, 0) self.service_deteils = QLabel(self) self.service_deteils.setTextFormat(Qt.RichText) self.service_deteils.setWordWrap(True) self.service_deteils.setOpenExternalLinks(True) self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format( Client().geoservice_info_url(geoservice.get('id', u"")), self.tr('details') )) self.service_desc_layout.addWidget(self.service_deteils, 1, 1) self.service_report = QLabel(self) self.service_report.setTextFormat(Qt.RichText) self.service_report.setWordWrap(True) self.service_report.setOpenExternalLinks(True) self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format( Client().geoservice_report_url(geoservice.get('id', u"")), self.tr('report a problem') )) self.service_desc_layout.addWidget(self.service_report, 1, 2) self.service_desc_layout.setColumnStretch(2, 1) self.status_label = QLabel(self) self.status_label.setTextFormat(Qt.RichText) self.status_label.setText(u'\u2022') status = geoservice.get('cumulative_status', u'') if status == 'works': self.status_label.setStyleSheet("color: green; font-size: 30px") if status == 'failed': self.status_label.setStyleSheet("color: red; font-size: 30px") if status == 'problematic': self.status_label.setStyleSheet("color: yellow; font-size: 30px") self.layout.addWidget(self.status_label) self.addButton = QToolButton() self.addButton.setText(self.tr("Add")) self.addButton.clicked.connect(self.addToMap) self.layout.addWidget(self.addButton) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) self.geoservice = geoservice self.image_ba = image_ba def addToMap(self): try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) client = Client() client.set_proxy(*QGISSettings.get_qgis_proxy()) geoservice_info = client.get_geoservice_info(self.geoservice) ds = DataSourceSerializer.read_from_json(geoservice_info) add_layer_to_map(ds) CachedServices().add_service(self.geoservice, self.image_ba) except Exception as ex: plPrint(unicode(ex)) pass finally: QApplication.restoreOverrideCursor() def mouseDoubleClickEvent(self, event): self.addToMap() def enterEvent(self, event): extent = self.geoservice.get('extent', None) if self.extent_renderer and extent: if ';' in extent: extent = extent.split(';')[1] geom = QgsGeometry.fromWkt(extent) self.extent_renderer.show_feature(geom) def leaveEvent(self, event): if self.extent_renderer: self.extent_renderer.clear_feature()
class PlanetOrderBundleWidget(QFrame): selectionChanged = pyqtSignal() def __init__(self, bundleid, name, description, udm, can_harmonize, rectified): super().__init__() self.bundleid = bundleid self.name = name self.description = description self.udm = udm self.can_harmonize = can_harmonize self.rectified = rectified layout = QVBoxLayout() hlayout = QHBoxLayout() hlayout.setMargin(0) self.labelName = QLabel(f"<b>{name}</b>") hlayout.addWidget(self.labelName) hlayout.addStretch() self.chkSelected = QCheckBox() self.chkSelected.stateChanged.connect(self.checkStateChanged) hlayout.addWidget(self.chkSelected) layout.addLayout(hlayout) self.labelDescription = QLabel(description) self.labelDescription.setWordWrap(True) layout.addWidget(self.labelDescription) hlayouttype = QHBoxLayout() hlayouttype.setMargin(0) self.radioTiff = QRadioButton("GeoTIFF") self.radioTiff.setChecked(True) self.radioTiff.toggled.connect(self.selectionChanged.emit) hlayouttype.addWidget(self.radioTiff) self.radioNitf = QRadioButton("NITF") self.radioNitf.toggled.connect(self.selectionChanged.emit) hlayouttype.addWidget(self.radioNitf) hlayouttype.addStretch() layout.addLayout(hlayouttype) if udm: hlayoutudm = QHBoxLayout() hlayoutudm.setMargin(0) self.labelUdm = IconLabel("UDM2", UDM_ICON) hlayoutudm.addWidget(self.labelUdm) hlayoutudm.addStretch() layout.addLayout(hlayoutudm) self.setFrameStyle(QFrame.Panel | QFrame.Raised) self.setLayout(layout) self.checkStateChanged() def checkStateChanged(self): self.radioTiff.setEnabled(self.chkSelected.isChecked()) self.radioNitf.setEnabled(self.chkSelected.isChecked()) self.labelName.setEnabled(self.chkSelected.isChecked()) self.labelDescription.setEnabled(self.chkSelected.isChecked()) if self.udm: self.labelUdm.setEnabled(self.chkSelected.isChecked()) self.selectionChanged.emit() def selected(self): return self.chkSelected.isChecked() def setSelected(self, selected, emit=False): if not emit: self.blockSignals(True) self.chkSelected.setChecked(selected) self.blockSignals(False) def filetype(self): if self.radioTiff.isChecked(): return "GeoTIFF" else: return "NITF"
class GroupSelectParameterWidget(GenericParameterWidget): """Widget class for Group Select Parameter.""" def __init__(self, parameter, parent=None): """Constructor. :param parameter: A GroupSelectParameter object. :type parameter: GroupSelectParameter """ QWidget.__init__(self, parent) self._parameter = parameter # Store spin box self.spin_boxes = {} # Create elements # Label (name) self.label = QLabel(self._parameter.name) # Layouts self.main_layout = QVBoxLayout() self.input_layout = QVBoxLayout() # _inner_input_layout must be filled with widget in the child class self.inner_input_layout = QVBoxLayout() self.radio_button_layout = QGridLayout() # Create radio button group self.input_button_group = QButtonGroup() # List widget self.list_widget = QListWidget() self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_widget.setDragDropMode(QAbstractItemView.DragDrop) self.list_widget.setDefaultDropAction(Qt.MoveAction) self.list_widget.setEnabled(False) self.list_widget.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Expanding) for i, key in enumerate(self._parameter.options): value = self._parameter.options[key] radio_button = QRadioButton(value.get('label')) self.radio_button_layout.addWidget(radio_button, i, 0) if value.get('type') == SINGLE_DYNAMIC: percentage_spin_box = PercentageSpinBox(self) self.radio_button_layout.addWidget(percentage_spin_box, i, 1) percentage_spin_box.setValue(value.get('value', 0)) step = percentage_spin_box.singleStep() if step > 1: precision = 0 else: precision = len(str(step).split('.')[1]) if precision > 3: precision = 3 percentage_spin_box.setDecimals(precision) self.spin_boxes[key] = percentage_spin_box # Enable spin box depends on the selected option if self._parameter.selected == key: percentage_spin_box.setEnabled(True) else: percentage_spin_box.setEnabled(False) elif value.get('type') == STATIC: static_value = value.get('value', 0) if static_value is not None: self.radio_button_layout.addWidget( QLabel(str(static_value * 100) + ' %'), i, 1) elif value.get('type') == MULTIPLE_DYNAMIC: if self._parameter.selected == key: self.list_widget.setEnabled(True) else: self.list_widget.setEnabled(False) self.input_button_group.addButton(radio_button, i) if self._parameter.selected == key: radio_button.setChecked(True) # Help text self.help_label = QLabel(self._parameter.help_text) self.help_label.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Expanding) self.help_label.setWordWrap(True) self.help_label.setAlignment(Qt.AlignTop) self.inner_input_layout.addLayout(self.radio_button_layout) self.inner_input_layout.addWidget(self.list_widget) # Put elements into layouts self.input_layout.addWidget(self.label) self.input_layout.addLayout(self.inner_input_layout) self.help_layout = QVBoxLayout() self.help_layout.addWidget(self.help_label) self.main_layout.addLayout(self.input_layout) self.main_layout.addLayout(self.help_layout) self.setLayout(self.main_layout) self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) # Update list widget self.update_list_widget() # Connect signal # noinspection PyUnresolvedReferences self.input_button_group.buttonClicked.connect( self.radio_buttons_clicked) def get_parameter(self): """Obtain list parameter object from the current widget state. :returns: A DefaultValueParameter from the current state of widget :rtype: DefaultValueParameter """ # Set value for each key for key, value in list(self._parameter.options.items()): if value.get('type') == STATIC: continue elif value.get('type') == SINGLE_DYNAMIC: new_value = self.spin_boxes.get(key).value() self._parameter.set_value_for_key(key, new_value) elif value.get('type') == MULTIPLE_DYNAMIC: # Need to iterate through all items items = [] for index in range(self.list_widget.count()): items.append(self.list_widget.item(index)) new_value = [i.text() for i in items] self._parameter.set_value_for_key(key, new_value) # Get selected radio button radio_button_checked_id = self.input_button_group.checkedId() # No radio button checked, then default value = None if radio_button_checked_id == -1: self._parameter.selected = None else: self._parameter.selected = list(self._parameter.options.keys())[ radio_button_checked_id] return self._parameter def update_list_widget(self): """Update list widget when radio button is clicked.""" # Get selected radio button radio_button_checked_id = self.input_button_group.checkedId() # No radio button checked, then default value = None if radio_button_checked_id > -1: selected_dict = list(self._parameter.options.values())[ radio_button_checked_id] if selected_dict.get('type') == MULTIPLE_DYNAMIC: for field in selected_dict.get('value'): # Update list widget field_item = QListWidgetItem(self.list_widget) field_item.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field) field_item.setText(field) self.list_widget.addItem(field_item) def radio_buttons_clicked(self): """Handler when selected radio button changed.""" # Disable all spin boxes for spin_box in list(self.spin_boxes.values()): spin_box.setEnabled(False) # Disable list widget self.list_widget.setEnabled(False) # Get selected radio button radio_button_checked_id = self.input_button_group.checkedId() if radio_button_checked_id > -1: selected_value = list(self._parameter.options.values())[ radio_button_checked_id] if selected_value.get('type') == MULTIPLE_DYNAMIC: # Enable list widget self.list_widget.setEnabled(True) elif selected_value.get('type') == SINGLE_DYNAMIC: selected_key = list(self._parameter.options.keys())[ radio_button_checked_id] self.spin_boxes[selected_key].setEnabled(True) def select_radio_button(self, key): """Helper to select a radio button with key. :param key: The key of the radio button. :type key: str """ key_index = list(self._parameter.options.keys()).index(key) radio_button = self.input_button_group.button(key_index) radio_button.click()