def on_load_base_layer(self): # look for base layers in the config layer_config = get_layer_config() dlg = QDialog() vbox = QVBoxLayout() list_widget = QListWidget() button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) vbox.addWidget(list_widget) vbox.addWidget(button_box) dlg.setWindowTitle("Select a base layer to load") dlg.setLayout(vbox) # populate the list widget for (uri, provider), cfg in layer_config.items(): layer_name = cfg.get( "layer_name", "Unnamed layer ({}, {})".format(uri, provider)) list_item = QListWidgetItem() list_item.setText(layer_name) list_item.setData(Qt.UserRole, (uri, provider)) list_widget.addItem(list_item) button_box.rejected.connect(dlg.reject) button_box.accepted.connect(dlg.accept) if dlg.exec_(): item = list_widget.currentItem() if item: uri, provider = item.data(Qt.UserRole) self.iface.addVectorLayer(uri, item.text(), provider)
def _setupUI(self): self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumHeight(180) self.main_horizontal_layout = QHBoxLayout(self) italic_font = QFont() italic_font.setItalic(True) # deselected widget self.deselected_widget = QListWidget(self) self._set_list_widget_defaults(self.deselected_widget) deselected_label = QLabel() deselected_label.setText('Deselected') deselected_label.setAlignment(Qt.AlignCenter) deselected_label.setFont(italic_font) deselected_v_layout = QVBoxLayout() deselected_v_layout.addWidget(deselected_label) deselected_v_layout.addWidget(self.deselected_widget) # selected widget self.selected_widget = QListWidget(self) self._set_list_widget_defaults(self.selected_widget) selected_label = QLabel() selected_label.setText('Selected') selected_label.setAlignment(Qt.AlignCenter) selected_label.setFont(italic_font) selected_v_layout = QVBoxLayout() selected_v_layout.addWidget(selected_label) selected_v_layout.addWidget(self.selected_widget) # buttons self.buttons_vertical_layout = QVBoxLayout() self.buttons_vertical_layout.setContentsMargins(0, -1, 0, -1) self.select_all_btn = SmallQPushButton('>>') self.deselect_all_btn = SmallQPushButton('<<') self.select_btn = SmallQPushButton('>') self.deselect_btn = SmallQPushButton('<') self.select_btn.setToolTip('Add the selected items') self.deselect_btn.setToolTip('Remove the selected items') self.select_all_btn.setToolTip('Add all') self.deselect_all_btn.setToolTip('Remove all') # add buttons spacer_label = QLabel() # pragmatic way to create a spacer with # the same height of the labels on top # of the lists, in order to align the # buttons with the lists. self.buttons_vertical_layout.addWidget(spacer_label) self.buttons_vertical_layout.addWidget(self.select_btn) self.buttons_vertical_layout.addWidget(self.deselect_btn) self.buttons_vertical_layout.addWidget(self.select_all_btn) self.buttons_vertical_layout.addWidget(self.deselect_all_btn) # add sub widgets self.main_horizontal_layout.addLayout(deselected_v_layout) self.main_horizontal_layout.addLayout(self.buttons_vertical_layout) self.main_horizontal_layout.addLayout(selected_v_layout)
def initGui(self): layout = QVBoxLayout() buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Close) self.filterBox = QLineEdit() self.filterBox.setPlaceholderText( "[enter text or date in dd/mm/yyyy format to filter history]") self.filterBox.textChanged.connect(self.filterCommits) self.list = QListWidget() self.list.setAlternatingRowColors(True) self.list.setSelectionMode(QAbstractItemView.SingleSelection) self.list.setSelectionBehavior(QAbstractItemView.SelectRows) log = self.repo.log(until=self.until, path=self.path, limit=100) for commit in log: item = CommitListItem(commit) self.list.addItem(item) layout.addWidget(self.filterBox) layout.addWidget(self.list) layout.addWidget(buttonBox) self.setLayout(layout) buttonBox.accepted.connect(self.okPressed) buttonBox.rejected.connect(self.cancelPressed) self.resize(500, 400) self.setWindowTitle("Select commit")
def createCellWidget(self, qmlDict, attr, count): """ Creates specific widgets for each attribute, which can be a QCombobox, a QLineEdit or a QListWidget. """ if attr in qmlDict: enableIgnoreOption = False #case the type is dict the cell widget must be a combobox if isinstance(qmlDict[attr],dict): comboItem = DsgCustomComboBox() comboItem.addItems(sorted(qmlDict[attr].keys())) self.attributeTableWidget.setCellWidget(count, 1, comboItem) #case the type is tuple the cell widget must be a listwidget if isinstance(qmlDict[attr],tuple): (table, filterKeys) = qmlDict[attr] #getting the value relation dictionary used to make the listwidget valueRelation = self.makeValueRelationDict(table, filterKeys) list = QListWidget() for key in list(valueRelation.keys()): listItem = QListWidgetItem(key) listItem.setCheckState(Qt.Unchecked) list.addItem(listItem) self.attributeTableWidget.setCellWidget(count, 1, list) #this is the normal case, a simple lineedit else: textItem = QLineEdit() self.attributeTableWidget.setCellWidget(count, 1, textItem) enableIgnoreOption = True #insert here aditional parameters self.createAditionalParameters(count, enableIgnoreOption)
def __init__(self, parent, layout_object): super().__init__(parent, layout_object) self.plot_item = layout_object self.message_bar = None vl = QVBoxLayout() vl.setContentsMargins(0, 0, 0, 0) plot_tools_layout = QHBoxLayout() plot_add_button = QPushButton() plot_add_button.setIcon(GuiUtils.get_icon('symbologyAdd.svg')) plot_add_button.setToolTip('Add a new plot') plot_tools_layout.addWidget(plot_add_button) plot_add_button.clicked.connect(self.add_plot) plot_remove_button = QPushButton() plot_remove_button.setIcon(GuiUtils.get_icon('symbologyRemove.svg')) plot_remove_button.setToolTip('Remove selected plot') plot_tools_layout.addWidget(plot_remove_button) plot_remove_button.clicked.connect(self.remove_plot) plot_duplicate_button = QPushButton() plot_duplicate_button.setIcon( GuiUtils.get_icon('mActionDuplicateLayer.svg')) plot_duplicate_button.setToolTip('Duplicates the selected plot') plot_tools_layout.addWidget(plot_duplicate_button) plot_duplicate_button.clicked.connect(self.duplicate_plot) plot_move_up_button = QPushButton() plot_move_up_button.setIcon(GuiUtils.get_icon('mActionArrowUp.svg')) plot_move_up_button.setToolTip('Move selected plot up') plot_tools_layout.addWidget(plot_move_up_button) plot_move_up_button.clicked.connect(self.move_up_plot) plot_move_down_button = QPushButton() plot_move_down_button.setIcon( GuiUtils.get_icon('mActionArrowDown.svg')) plot_move_down_button.setToolTip('Move selected plot down') plot_tools_layout.addWidget(plot_move_down_button) plot_move_down_button.clicked.connect(self.move_down_plot) vl.addLayout(plot_tools_layout) self.plot_list = QListWidget() self.plot_list.setSelectionMode(QListWidget.SingleSelection) self.plot_list.doubleClicked.connect(self.show_properties) vl.addWidget(self.plot_list) self.populate_plot_list() plot_properties_button = QPushButton(self.tr('Setup Selected Plot')) vl.addWidget(plot_properties_button) plot_properties_button.clicked.connect(self.show_properties) self.panel = None self.setPanelTitle(self.tr('Plot Properties')) self.item_properties_widget = QgsLayoutItemPropertiesWidget( self, layout_object) vl.addWidget(self.item_properties_widget) self.setLayout(vl)
def createEditor(self, parent, option, index): """ Creates a custom editor to edit value relation data """ # special combobox for field type if index.column() == self.column: list = QListWidget(parent) for item in self.itemsDict: listItem = QListWidgetItem(item) listItem.setCheckState(Qt.Unchecked) list.addItem(listItem) return list return QItemDelegate.createEditor(self, parent, option, index)
def initWindow(self): self.addButton = QPushButton("Hinzufügen", self) self.closeButton = QPushButton("Schließen", self) self.listWidget = QListWidget(self) self.listWidget.move(50, 50) self.listWidget.resize(250, 350) self.addButton.move(100, 410) self.addButton.clicked.connect(self.add) self.closeButton.move(220, 410) self.closeButton.clicked.connect(self.closing) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height)
def __init__(self, viewer, feature_id, feature_name, config_list, config): QDialog.__init__(self) self.__viewer = viewer self.__feature_id = feature_id self.__feature_name = feature_name self.__config_list = config_list self.__config = config vbox = QVBoxLayout() btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn.accepted.connect(self.accept) btn.rejected.connect(self.reject) self.__list = QListWidget() self.__list.setSelectionMode(QAbstractItemView.ExtendedSelection) hbox = QHBoxLayout() lbl = QLabel("Sub selection") self.__sub_selection_combo = QComboBox() self.__sub_selection_combo.setEnabled(False) hbox.addWidget(lbl) hbox.addWidget(self.__sub_selection_combo) from_elsewhere_btn = QPushButton("Select another station") self.__title_label = QLabel() hbox2 = QHBoxLayout() hbox2.addWidget(self.__title_label) hbox2.addWidget(from_elsewhere_btn) vbox.addLayout(hbox2) vbox.addWidget(self.__list) vbox.addLayout(hbox) vbox.addWidget(btn) self.__list.itemSelectionChanged.connect(self.on_selection_changed) self.__sub_selection_combo.currentIndexChanged[str].connect( self.on_combo_changed) from_elsewhere_btn.clicked.connect(self.on_from_elsewhere_clicked) self.setLayout(vbox) self.setWindowTitle("Choose the data to add") self.resize(400, 200) self._populate_list() self.set_title(feature_name)
def __init__(self, parent, tree, name, value, action=None): QTreeWidgetItem.__init__(self, parent) self.parent = parent self.tree = tree self.name = name self._value = value self.combo = None self.list = None self.setText(0, name) widget = None if isinstance(value, QgsColorButton): widget = value elif isinstance(value, bool): if value: self.setCheckState(1, Qt.Checked) else: self.setCheckState(1, Qt.Unchecked) elif isinstance(value, tuple): self.combo = QComboBox() self.combo.setSizeAdjustPolicy(0) for option in value: self.combo.addItem(option) widget = self.combo elif isinstance(value, list): self.list = QListWidget() self.list.setSizeAdjustPolicy(0) self.list.setSelectionMode(QListWidget.MultiSelection) for option in value: self.list.addItem(option) widget = self.list else: self.setText(1, unicode(value)) if action: layout = QHBoxLayout() layout.setMargin(0) if widget: layout.addWidget(widget) button = QToolButton() button.setDefaultAction(action) button.setText(action.text()) layout.addWidget(button) layout.addStretch(1) widget = QWidget() widget.setLayout(layout) if widget: self.tree.setItemWidget(self, 1, widget)
def __init__(self, electorate_registry: LinzElectoralDistrictRegistry, parent=None): super().__init__(parent) self.electorate_registry = electorate_registry self.setWindowTitle(self.tr('Deprecate Electorate')) layout = QVBoxLayout() self.search = QgsFilterLineEdit() self.search.setShowSearchIcon(True) self.search.setPlaceholderText( self.tr('Search for {}').format( electorate_registry.type_string_sentence())) self.search.textChanged.connect(self.filter_changed) layout.addWidget(self.search) request = QgsFeatureRequest() request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes([ electorate_registry.source_field_index, electorate_registry.title_field_index, electorate_registry.deprecated_field_index ]) self.list = QListWidget() for f in electorate_registry.source_layer.getFeatures(request): title = f[electorate_registry.title_field_index] code = f[electorate_registry.source_field_index] deprecated = f[electorate_registry.deprecated_field_index] if deprecated: title = '*' + title item = QListWidgetItem(title) item.setData(Qt.UserRole, code) self.list.addItem(item) layout.addWidget(self.list, 10) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(button_box) button_box.rejected.connect(self.reject) button_box.accepted.connect(self.accept) self.setLayout(layout) self.list.itemDoubleClicked.connect(self.accept)
def __init__(self, viewer, features, config_list, config): QDialog.__init__(self) self.__viewer = viewer self.__features = features self.__config_list = config_list self.__config = config vbox = QVBoxLayout() btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn.accepted.connect(self.accept) btn.rejected.connect(self.reject) self.__list = QListWidget() self.__list.setSelectionMode(QAbstractItemView.ExtendedSelection) hbox = QHBoxLayout() lbl = QLabel("Sub selection") self.__sub_selection_combo = QComboBox() self.__sub_selection_combo.setEnabled(False) hbox.addWidget(lbl) hbox.addWidget(self.__sub_selection_combo) self.__title_label = QLabel() hbox2 = QHBoxLayout() hbox2.addWidget(self.__title_label) vbox.addLayout(hbox2) vbox.addWidget(self.__list) vbox.addLayout(hbox) vbox.addWidget(btn) self.__list.itemSelectionChanged.connect(self.on_selection_changed) self.__sub_selection_combo.currentIndexChanged[str].connect( self.on_combo_changed) self.setLayout(vbox) self.setWindowTitle("Choose the data to add") self.resize(400, 200) self._populate_list() self.set_title(",".join([ feature[self.__config["name_column"]] for feature in self.__features ]))
class listview(QDialog): name = "class" def __init__(self, table): super().__init__() self.table = table self.title = "Hinzufügen" self.top = 600 self.left = 200 self.width = 350 self.height = 450 self.initWindow() def initWindow(self): self.addButton = QPushButton("Hinzufügen", self) self.closeButton = QPushButton("Schließen", self) self.listWidget = QListWidget(self) self.listWidget.move(50, 50) self.listWidget.resize(250, 350) self.addButton.move(100, 410) self.addButton.clicked.connect(self.add) self.closeButton.move(220, 410) self.closeButton.clicked.connect(self.closing) self.setWindowTitle(self.title) self.setGeometry(self.top, self.left, self.width, self.height) def fill(self): self.listWidget.clear() if self.table.missingattr != []: self.listWidget.addItems(self.table.missingattr) self.show() def add(self): print([li.text() for li in self.listWidget.selectedItems()]) self.table.add( [li.text() for li in self.listWidget.selectedItems()]) self.fill() print("ok") def closing(self): self.close()
def __init__(self, scenario_registry: ScenarioRegistry, parent=None): """ Constructor for ScenarioSelectionDialog :param scenario_registry: linked scenario registry :param parent: parent widget """ super().__init__(parent) self.scenario_registry = scenario_registry self.setWindowTitle(self.tr('Select Current Scenario')) layout = QVBoxLayout() self.search = QgsFilterLineEdit() self.search.setShowSearchIcon(True) self.search.setPlaceholderText(self.tr('Search for scenario')) self.search.textChanged.connect(self.filter_changed) layout.addWidget(self.search) self.list = QListWidget() for title, scenario_id in scenario_registry.scenario_titles().items(): item = QListWidgetItem(title) item.setData(Qt.UserRole, scenario_id) self.list.addItem(item) layout.addWidget(self.list, 10) button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(button_box) button_box.rejected.connect(self.reject) button_box.accepted.connect(self.accept) self.setLayout(layout) self.list.itemDoubleClicked.connect( self.accept) # select last scenario by default if self.list.count() > 0: self.list.item(self.list.count() - 1).setSelected(True)
def __init__(self, dockwidget, parent, params): QDialog.__init__(self, parent) main_lay = QVBoxLayout(self) self.dockwidget = dockwidget self.params = params self.setWindowTitle('Tags editor') # Top frame self.fra_top = QFrame() fra_top_lay = QVBoxLayout(self.fra_top) self.lst_main = QListWidget(self) self.btn_add = QPushButton('Add tag') self.btn_add.clicked.connect(self.add_tag) self.btn_remove = QPushButton('Remove tag') self.btn_remove.clicked.connect(self.remove_tag) fra_top_lay.addWidget(self.lst_main) fra_top_lay.addWidget(self.btn_add) fra_top_lay.addWidget(self.btn_remove) # Bottom frame self.fra_bottom = QFrame() fra_bottom_lay = QHBoxLayout(self.fra_bottom) btb_main = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btb_main.accepted.connect(self.ok) btb_main.rejected.connect(self.reject) fra_bottom_lay.addWidget(btb_main) # Main main_lay.addWidget(self.fra_top) main_lay.addWidget(self.fra_bottom) self.initialize()
def __init__(self, parent, mono=False): super().__init__(parent) self.mono = mono if self.mono: return self.mlist = QListWidget(self) self.line_edit = ComplexLineEdit(self) self.clear() self.line_edit.setReadOnly(True) self.line_edit.installEventFilter(self) self.setModel(self.mlist.model()) self.setView(self.mlist) self.view().setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setLineEdit(self.line_edit) # NOTE: this is necessary to handle the case in which an item in the # list is clicked to its right part, outside the text self.activated.connect(self.itemClicked)
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 )
class DataSelector(QDialog): def __init__(self, viewer, features, config_list, config): QDialog.__init__(self) self.__viewer = viewer self.__features = features self.__config_list = config_list self.__config = config vbox = QVBoxLayout() btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btn.accepted.connect(self.accept) btn.rejected.connect(self.reject) self.__list = QListWidget() self.__list.setSelectionMode(QAbstractItemView.ExtendedSelection) hbox = QHBoxLayout() lbl = QLabel("Sub selection") self.__sub_selection_combo = QComboBox() self.__sub_selection_combo.setEnabled(False) hbox.addWidget(lbl) hbox.addWidget(self.__sub_selection_combo) self.__title_label = QLabel() hbox2 = QHBoxLayout() hbox2.addWidget(self.__title_label) vbox.addLayout(hbox2) vbox.addWidget(self.__list) vbox.addLayout(hbox) vbox.addWidget(btn) self.__list.itemSelectionChanged.connect(self.on_selection_changed) self.__sub_selection_combo.currentIndexChanged[str].connect( self.on_combo_changed) self.setLayout(vbox) self.setWindowTitle("Choose the data to add") self.resize(400, 200) self._populate_list() self.set_title(",".join([ feature[self.__config["name_column"]] for feature in self.__features ])) def set_title(self, title): self.__title_label.setText("Station(s): {}".format(title)) def _populate_list(self): self.__list.clear() for cfg in self.__config_list: if cfg["type"] in ("cumulative", "instantaneous"): # check number of features for this station if cfg.get("feature_filter_type") == "unique_data_from_values": # get unique filter values layerid = cfg["source"] data_l = QgsProject.instance().mapLayers()[layerid] values = set() for feature in self.__features: feature_id = feature[self.__config["id_column"]] req = QgsFeatureRequest() req.setFilterExpression("{}={}".format( cfg["feature_ref_column"], feature_id)) values.update([ f[cfg["feature_filter_column"]] for f in data_l.getFeatures(req) ]) cfg.set_filter_unique_values(sorted(list(values))) item = QListWidgetItem(cfg["name"]) item.setData(Qt.UserRole, cfg) self.__list.addItem(item) def accept(self): for feature in self.__features: self.__load_feature(feature) def __load_feature(self, feature): # FIXME this code too similar to main_dialog.load_plots # FIXME find a way to factor feature_id = feature[self.__config["id_column"]] feature_name = feature[self.__config["name_column"]] for item in self.__list.selectedItems(): # now add the selected configuration cfg = item.data(Qt.UserRole) if cfg["type"] in ("cumulative", "instantaneous", "continuous"): layerid = cfg["source"] data_l = QgsProject.instance().mapLayers()[layerid] req = QgsFeatureRequest() filter_expr = "{}='{}'".format(cfg["feature_ref_column"], feature_id) req.setFilterExpression(filter_expr) title = cfg["name"] if cfg.get_filter_value(): filter_expr += " and {}='{}'".format( cfg["feature_filter_column"], cfg.get_filter_value()) title = cfg.get_filter_value() else: title = cfg["name"] f = None # test if the layer actually contains data for f in data_l.getFeatures(req): break if f is None: return if cfg["type"] == "instantaneous": uom = cfg.get_uom() data = LayerData(data_l, cfg["event_column"], cfg["value_column"], filter_expression=filter_expr, uom=uom) uom = data.uom() self.__viewer.add_data_cell(data, title, uom, station_name=feature_name, config=cfg) self.__viewer.add_scale() if cfg["type"] == "continuous": uom = cfg.get_uom() fids = [f.id() for f in data_l.getFeatures(req)] data = FeatureData( data_l, cfg["values_column"], feature_ids=fids, x_start_fieldname=cfg["start_measure_column"], x_delta_fieldname=cfg["interval_column"]) self.__viewer.add_data_cell(data, title, uom, station_name=feature_name, config=cfg) elif cfg["type"] == "cumulative": self.__viewer.add_histogram( data_l, filter_expression=filter_expr, column_mapping={ f: cfg[f] for f in ("min_event_column", "max_event_column", "value_column") }, title=title, config=cfg, station_name=feature_name) elif cfg["type"] == "image": self.__viewer.add_imagery_from_db(cfg, feature_id) QDialog.accept(self) def on_selection_changed(self): self.__sub_selection_combo.clear() self.__sub_selection_combo.setEnabled(False) for item in self.__list.selectedItems(): cfg = item.data(Qt.UserRole) for v in cfg.get_filter_unique_values(): self.__sub_selection_combo.addItem(v) if cfg.get_filter_value(): self.__sub_selection_combo.setCurrentIndex( self.__sub_selection_combo.findText( cfg.get_filter_value())) self.__sub_selection_combo.setEnabled(True) return def on_combo_changed(self, text): for item in self.__list.selectedItems(): cfg = item.data(Qt.UserRole) cfg.set_filter_value(text) item.setData(Qt.UserRole, cfg) return
def __init__(self): QListWidget.__init__(self)
def __init__(self, parent, scope=None, xml_doc=None, md=None): super(MetadadoSNIMar, self).__init__(parent) if scope is None: self.scope = SCOPES.get_code_representation(md.hierarchy) else: self.scope = scope self.current_index = 0 self.widgetStalker = {} if platform.system() != "Linux": font = QFont() font.setFamily(u"Segoe UI Symbol") self.setFont(font) self.sidelist = QListWidget(self) self.sidelist.setMinimumWidth(150) self.sidelist.setMaximumWidth(150) self.sidelist.setWordWrap(True) self.sidelist.setTextElideMode(Qt.ElideNone) self.sidelist.setIconSize(QSize(25, 25)) self.sidelist.clicked.connect(self.list_clicked) index = 0 if self.scope == SCOPES.SERVICES: tabs = cons.TABLIST_SERVICES else: tabs = cons.TABLIST_CDG_SERIES for tab_element in tabs: bufWidget = QListWidgetItem( qgui.QIcon(':/resourcesFolder/icons/' + tab_element[1]), tab_element[0]) self.widgetStalker[tab_element[2]] = { "widget": bufWidget, "missingFields": set(), "incompleteEntries": set() } bufWidget.setSizeHint(QSize(150, 50)) if platform.system() != "Linux": font = QFont() font.setFamily(u"Segoe UI Symbol") bufWidget.setFont(font) self.sidelist.insertItem(index, bufWidget) index += 1 self.widgetstack = QStackedWidget(self) # Setup metadata stuff self.xml_doc = xml_doc self.is_new_file = True if xml_doc is None else False self.md = md self.codelist = self.parent().codelists self.helps = self.parent().helps self.orgs = self.parent().orgs f = open( os.path.join(pluginDirectory('EditorMetadadosMarswInforbiomares'), 'resourcesFolder/stylesheet.qtcss')) self.sytlesheet = f.read() for btn in self.findChildren(QPushButton): btn.setStyleSheet(self.sytlesheet) btn.setFocusPolicy(Qt.NoFocus) self.reference_systems_list = self.parent().reference_systems tab_list = [] # Setup snimarEditorController self.identification = snimarEditorController.IdentificationWidget( self, self.scope) tab_list.append(self.identification) if self.scope == SCOPES.SERVICES: self.operations = snimarEditorController.ServiceOperationsWidget( self) tab_list.append(self.operations) self.keywords = snimarEditorController.KeywordsWidget(self, self.scope) tab_list.append(self.keywords) self.geographicinfo = snimarEditorController.GeographicInfoWidget( self, self.scope) tab_list.append(self.geographicinfo) self.temporalinfo = snimarEditorController.TemporalInfoWidget( self, self.scope) tab_list.append(self.temporalinfo) self.quality = snimarEditorController.QualityWidget(self, self.scope) tab_list.append(self.quality) self.restrictions = snimarEditorController.RestrictionsWidget( self, self.scope) tab_list.append(self.restrictions) self.distribution = snimarEditorController.DistributionWidget( self, self.scope) tab_list.append(self.distribution) self.metadata = snimarEditorController.MetadataWidget(self) tab_list.append(self.metadata) self.setupUi() if not self.is_new_file: # Setup data self.identification.set_data(self.md) if self.scope == SCOPES.SERVICES: self.operations.set_data(md) self.temporalinfo.set_data(self.md) self.keywords.set_data(self.md) self.metadata.set_data(self.md) self.distribution.set_data(self.md) self.restrictions.set_data(self.md) self.quality.set_data(self.md) self.geographicinfo.set_data(self.md)
class MetadadoSNIMar(QWidget): def __init__(self, parent, scope=None, xml_doc=None, md=None): super(MetadadoSNIMar, self).__init__(parent) if scope is None: self.scope = SCOPES.get_code_representation(md.hierarchy) else: self.scope = scope self.current_index = 0 self.widgetStalker = {} if platform.system() != "Linux": font = QFont() font.setFamily(u"Segoe UI Symbol") self.setFont(font) self.sidelist = QListWidget(self) self.sidelist.setMinimumWidth(150) self.sidelist.setMaximumWidth(150) self.sidelist.setWordWrap(True) self.sidelist.setTextElideMode(Qt.ElideNone) self.sidelist.setIconSize(QSize(25, 25)) self.sidelist.clicked.connect(self.list_clicked) index = 0 if self.scope == SCOPES.SERVICES: tabs = cons.TABLIST_SERVICES else: tabs = cons.TABLIST_CDG_SERIES for tab_element in tabs: bufWidget = QListWidgetItem( qgui.QIcon(':/resourcesFolder/icons/' + tab_element[1]), tab_element[0]) self.widgetStalker[tab_element[2]] = { "widget": bufWidget, "missingFields": set(), "incompleteEntries": set() } bufWidget.setSizeHint(QSize(150, 50)) if platform.system() != "Linux": font = QFont() font.setFamily(u"Segoe UI Symbol") bufWidget.setFont(font) self.sidelist.insertItem(index, bufWidget) index += 1 self.widgetstack = QStackedWidget(self) # Setup metadata stuff self.xml_doc = xml_doc self.is_new_file = True if xml_doc is None else False self.md = md self.codelist = self.parent().codelists self.helps = self.parent().helps self.orgs = self.parent().orgs f = open( os.path.join(pluginDirectory('EditorMetadadosMarswInforbiomares'), 'resourcesFolder/stylesheet.qtcss')) self.sytlesheet = f.read() for btn in self.findChildren(QPushButton): btn.setStyleSheet(self.sytlesheet) btn.setFocusPolicy(Qt.NoFocus) self.reference_systems_list = self.parent().reference_systems tab_list = [] # Setup snimarEditorController self.identification = snimarEditorController.IdentificationWidget( self, self.scope) tab_list.append(self.identification) if self.scope == SCOPES.SERVICES: self.operations = snimarEditorController.ServiceOperationsWidget( self) tab_list.append(self.operations) self.keywords = snimarEditorController.KeywordsWidget(self, self.scope) tab_list.append(self.keywords) self.geographicinfo = snimarEditorController.GeographicInfoWidget( self, self.scope) tab_list.append(self.geographicinfo) self.temporalinfo = snimarEditorController.TemporalInfoWidget( self, self.scope) tab_list.append(self.temporalinfo) self.quality = snimarEditorController.QualityWidget(self, self.scope) tab_list.append(self.quality) self.restrictions = snimarEditorController.RestrictionsWidget( self, self.scope) tab_list.append(self.restrictions) self.distribution = snimarEditorController.DistributionWidget( self, self.scope) tab_list.append(self.distribution) self.metadata = snimarEditorController.MetadataWidget(self) tab_list.append(self.metadata) self.setupUi() if not self.is_new_file: # Setup data self.identification.set_data(self.md) if self.scope == SCOPES.SERVICES: self.operations.set_data(md) self.temporalinfo.set_data(self.md) self.keywords.set_data(self.md) self.metadata.set_data(self.md) self.distribution.set_data(self.md) self.restrictions.set_data(self.md) self.quality.set_data(self.md) self.geographicinfo.set_data(self.md) def setupUi(self): self.widgetstack.addWidget(self.identification) if self.scope == SCOPES.SERVICES: self.widgetstack.addWidget(self.operations) self.widgetstack.addWidget(self.keywords) self.widgetstack.addWidget(self.geographicinfo) self.widgetstack.addWidget(self.temporalinfo) self.widgetstack.addWidget(self.quality) self.widgetstack.addWidget(self.restrictions) self.widgetstack.addWidget(self.distribution) self.widgetstack.addWidget(self.metadata) self.grid = QGridLayout(self) self.grid.addWidget(self.sidelist, 0, 0, 1, 1) self.grid.addWidget(self.widgetstack, 0, 1, 1, 1) self.setLayout(self.grid) self.widgetstack.setCurrentIndex(0) @qcore.pyqtSlot() def list_clicked(self): index = self.sidelist.currentRow() if index != self.current_index: self.widgetstack.setCurrentIndex(index) self.current_index = index def get_tab_data(self, md): if self.scope != SCOPES.SERVICES: md.identification = snimarProfileModel.MD_DataIdentification() else: md.serviceidentification = snimarProfileModel.SV_ServiceIdentification( ) self.identification.get_data(md) if self.scope == SCOPES.SERVICES: self.operations.get_data(md) self.keywords.get_data(md) self.geographicinfo.get_data(md) self.temporalinfo.get_data(md) self.quality.get_data(md) self.restrictions.get_data(md) self.distribution.get_data(md) self.metadata.get_data(md) # ------------------------------------------------------------------------ # Validation STUFF # ------------------------------------------------------------------------ def is_doc_Snimar_Valid(self): for x in list(self.widgetStalker.values()): if len(x["missingFields"]) > 0 or len(x["incompleteEntries"]) > 0: return False return True def register_mandatory_missingfield(self, widgetName, fieldName): self.widgetStalker[widgetName]["missingFields"].add( fieldName.replace(u'\u26a0', '').strip()) self.widgetStalker[widgetName]["widget"].setToolTip( self.genToolTip(widgetName)) self.widgetStalker[widgetName]["widget"].setForeground( QColor(cons.ERROR_COLOR)) self.widgetStalker[widgetName]["widget"].setText( self.widgetStalker[widgetName]["widget"].text().replace( u'\u26a0', '') + u'\u26a0') def unregister_mandatory_missingfield(self, widgetName, fieldName): self.widgetStalker[widgetName]["missingFields"].discard(fieldName) if len(self.widgetStalker[widgetName] ["incompleteEntries"]) != 0 or len( self.widgetStalker[widgetName]["missingFields"]) != 0: self.widgetStalker[widgetName]["widget"].setText( self.widgetStalker[widgetName]["widget"].text().replace( u'\u26a0', '') + u'\u26a0') else: self.widgetStalker[widgetName]["widget"].setForeground( QColor("black")) self.widgetStalker[widgetName]["widget"].setText( self.widgetStalker[widgetName]["widget"].text().replace( u'\u26a0', '')) self.widgetStalker[widgetName]["widget"].setToolTip( self.genToolTip(widgetName)) def register_incomplete_entries(self, widgetName, fieldName): self.widgetStalker[widgetName]["incompleteEntries"].add( fieldName.replace(u'\u26a0', '').strip()) self.widgetStalker[widgetName]["widget"].setToolTip( self.genToolTip(widgetName)) self.widgetStalker[widgetName]["widget"].setForeground( QColor(cons.ERROR_COLOR)) self.widgetStalker[widgetName]["widget"].setText( self.widgetStalker[widgetName]["widget"].text().replace( u'\u26a0', '') + u'\u26a0') def unregister_incomplete_entries(self, widgetName, fieldName): self.widgetStalker[widgetName]["incompleteEntries"].discard(fieldName) if len(self.widgetStalker[widgetName] ["incompleteEntries"]) != 0 or len( self.widgetStalker[widgetName]["missingFields"]) != 0: self.widgetStalker[widgetName]["widget"].setText( self.widgetStalker[widgetName]["widget"].text().replace( u'\u26a0', '') + u'\u26a0') else: self.widgetStalker[widgetName]["widget"].setForeground( QColor("black")) self.widgetStalker[widgetName]["widget"].setText( self.widgetStalker[widgetName]["widget"].text().replace( u'\u26a0', '')) self.widgetStalker[widgetName]["widget"].setToolTip( self.genToolTip(widgetName)) def genToolTip(self, widgetName): tooltip = "" if len(self.widgetStalker[widgetName]["missingFields"]) > 0: tooltip += u"Campos Obrigatórios\nem falta:\n-" + "\n-".join( self.widgetStalker[widgetName]["missingFields"]) if len(self.widgetStalker[widgetName]["missingFields"]) > 0 and len( self.widgetStalker[widgetName]["incompleteEntries"]) > 0: tooltip += u"\n---------------------\n" if len(self.widgetStalker[widgetName]["incompleteEntries"]) > 0: tooltip += u"Campos Incompletos\Incorrectos:\n-" + "\n-".join( self.widgetStalker[widgetName]["incompleteEntries"]) tooltip += u"\n---------------------\n" return tooltip + u"\nA Conformidade diz respeito\n" \ u"as obrigações de formato " \ u"\ne completude do documento.\n" \ u"A validade do conteúdo é da\n" \ u"inteira responsabilidade\n" \ u"do utilizador. "
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 PlotLayoutItemWidget(QgsLayoutItemBaseWidget): """ Configuration widget for layout plot items """ def __init__(self, parent, layout_object): super().__init__(parent, layout_object) self.plot_item = layout_object self.message_bar = None vl = QVBoxLayout() vl.setContentsMargins(0, 0, 0, 0) plot_tools_layout = QHBoxLayout() plot_add_button = QPushButton() plot_add_button.setIcon(GuiUtils.get_icon('symbologyAdd.svg')) plot_add_button.setToolTip('Add a new plot') plot_tools_layout.addWidget(plot_add_button) plot_add_button.clicked.connect(self.add_plot) plot_remove_button = QPushButton() plot_remove_button.setIcon(GuiUtils.get_icon('symbologyRemove.svg')) plot_remove_button.setToolTip('Remove selected plot') plot_tools_layout.addWidget(plot_remove_button) plot_remove_button.clicked.connect(self.remove_plot) plot_duplicate_button = QPushButton() plot_duplicate_button.setIcon( GuiUtils.get_icon('mActionDuplicateLayer.svg')) plot_duplicate_button.setToolTip('Duplicates the selected plot') plot_tools_layout.addWidget(plot_duplicate_button) plot_duplicate_button.clicked.connect(self.duplicate_plot) plot_move_up_button = QPushButton() plot_move_up_button.setIcon(GuiUtils.get_icon('mActionArrowUp.svg')) plot_move_up_button.setToolTip('Move selected plot up') plot_tools_layout.addWidget(plot_move_up_button) plot_move_up_button.clicked.connect(self.move_up_plot) plot_move_down_button = QPushButton() plot_move_down_button.setIcon( GuiUtils.get_icon('mActionArrowDown.svg')) plot_move_down_button.setToolTip('Move selected plot down') plot_tools_layout.addWidget(plot_move_down_button) plot_move_down_button.clicked.connect(self.move_down_plot) vl.addLayout(plot_tools_layout) self.plot_list = QListWidget() self.plot_list.setSelectionMode(QListWidget.SingleSelection) self.plot_list.doubleClicked.connect(self.show_properties) vl.addWidget(self.plot_list) self.populate_plot_list() plot_properties_button = QPushButton(self.tr('Setup Selected Plot')) vl.addWidget(plot_properties_button) plot_properties_button.clicked.connect(self.show_properties) self.panel = None self.setPanelTitle(self.tr('Plot Properties')) self.item_properties_widget = QgsLayoutItemPropertiesWidget( self, layout_object) vl.addWidget(self.item_properties_widget) self.setLayout(vl) def populate_plot_list(self): """ Clears and re-populates the plot list widget. The currently selection is retained """ selected_index = self.plot_list.currentRow() self.plot_list.clear() for setting in self.plot_item.plot_settings: plot_type = setting.plot_type if setting.plot_type is not None else '(not set)' legend_title = ('[' + setting.properties.get('name') + ']') \ if setting.properties.get('name', '') != '' else '' self.plot_list.addItem(plot_type + ' ' + legend_title) # select index within range [0, len(plot_settings)-1] selected_index = max( 0, min(len(self.plot_item.plot_settings) - 1, selected_index)) self.plot_list.setCurrentRow(selected_index, QItemSelectionModel.SelectCurrent) def add_plot(self): """ Adds a new plot and updates the plot list and the plot item """ self.plot_item.add_plot() self.populate_plot_list() self.plot_item.refresh() def duplicate_plot(self): """ Duplicates an existing plot and updates the plot list and the plot item """ selected_plot_index = self.plot_list.currentRow() if selected_plot_index < 0: return self.plot_item.duplicate_plot(selected_plot_index) self.populate_plot_list() self.plot_item.refresh() def remove_plot(self): """ Removes the selected plot and updates the plot list and the plot item """ selected_index = self.plot_list.currentRow() if selected_index < 0: return self.plot_item.remove_plot(selected_index) self.populate_plot_list() self.plot_item.refresh() def move_up_plot(self): """ Moves the selected plot up and updates the plot list and the plot item """ selected_index = self.plot_list.currentRow() if selected_index <= 0: return item = self.plot_item.plot_settings.pop(selected_index) self.plot_item.plot_settings.insert(selected_index - 1, item) self.plot_list.setCurrentRow(selected_index - 1, QItemSelectionModel.SelectCurrent) self.populate_plot_list() self.plot_item.refresh() def move_down_plot(self): """ Moves the selected plot down and updates the plot list and the plot item """ selected_index = self.plot_list.currentRow() if selected_index >= len(self.plot_item.plot_settings) - 1: return item = self.plot_item.plot_settings.pop(selected_index) self.plot_item.plot_settings.insert(selected_index + 1, item) self.plot_list.setCurrentRow(selected_index + 1, QItemSelectionModel.SelectCurrent) self.populate_plot_list() self.plot_item.refresh() def show_properties(self): """ Shows the plot properties panel """ selected_plot_index = self.plot_list.currentRow() if selected_plot_index < 0: return self.panel = DataPlotlyPanelWidget( mode=DataPlotlyPanelWidget.MODE_LAYOUT, message_bar=self.message_bar) # not quite right -- we ideally want to also add the source layer scope into the context given by plot item, # but that causes a hard lock in the Python GIL (because PyQt doesn't release the GIL when creating the menu # for the property override buttons). Nothing much we can do about that here (or in QGIS, # it's a Python/PyQt limitation) self.panel.registerExpressionContextGenerator(self.plot_item) self.panel.set_print_layout(self.plot_item.layout()) self.panel.linked_map_combo.blockSignals(True) self.panel.linked_map_combo.setItem(self.plot_item.linked_map) self.panel.linked_map_combo.blockSignals(False) self.panel.linked_map_combo.itemChanged.connect( self.linked_map_changed) self.panel.set_settings( self.plot_item.plot_settings[selected_plot_index]) # self.panel.set_settings(self.layoutItem().plot_settings) self.openPanel(self.panel) self.panel.widgetChanged.connect(self.update_item_settings) self.panel.panelAccepted.connect(self.set_item_settings) def update_item_settings(self): """ Updates the plot item without dismissing the properties panel """ if not self.panel: return self.plot_item.set_plot_settings(self.plot_list.currentRow(), self.panel.get_settings()) self.populate_plot_list() self.plot_item.update() def set_item_settings(self): """ Updates the plot item based on the settings from the properties panel """ if not self.panel: return self.plot_item.set_plot_settings(self.plot_list.currentRow(), self.panel.get_settings()) self.populate_plot_list() self.panel = None self.plot_item.update() def linked_map_changed(self, linked_map): """ Triggered when the linked map is changed """ self.plot_item.set_linked_map(linked_map) self.plot_item.update() def setNewItem(self, item): # pylint: disable=missing-docstring if item.type() != ITEM_TYPE: return False self.plot_item = item self.item_properties_widget.setItem(item) self.populate_plot_list() if self.panel is not None: self.panel.set_settings(self.plot_item.plot_settings[0]) self.panel.linked_map_combo.blockSignals(True) self.panel.linked_map_combo.setItem(self.plot_item.linked_map) self.panel.linked_map_combo.blockSignals(False) return True def setDesignerInterface(self, iface): # pylint: disable=missing-docstring super().setDesignerInterface(iface) self.message_bar = iface.messageBar() if self.panel: self.panel.message_bar = self.message_bar
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 __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)
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 GraphDialog(QDialog): edit_patterns = 0 edit_curves = 1 titles = {edit_patterns: 'Pattern editor', edit_curves: 'Curve editor'} labels = {edit_patterns: 'Patterns', edit_curves: 'Curves'} def __init__(self, dockwidget, parent, params, edit_type): QDialog.__init__(self, parent) main_lay = QVBoxLayout(self) self.dockwidget = dockwidget self.params = params self.edit_type = edit_type self.x_label = '' self.y_label = '' self.setMinimumWidth(600) self.setMinimumHeight(400) self.setWindowTitle(self.titles[edit_type]) # TODO: softcode self.setWindowModality(QtCore.Qt.ApplicationModal) self.current = None self.current_saved = False # File self.lbl_file = QLabel('File:') self.fra_file = QFrame() self.fra_file.setContentsMargins(0, 0, 0, 0) fra_file_lay = QHBoxLayout(self.fra_file) if edit_type == self.edit_patterns: self.txt_file = QLineEdit(self.params.patterns_file) elif edit_type == self.edit_curves: self.txt_file = QLineEdit(self.params.curves_file) self.txt_file.setReadOnly(True) self.txt_file.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) self.txt_file.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) fra_file_lay.addWidget(self.txt_file) self.btn_file = QPushButton('Change') # TODO: softcode self.btn_file.clicked.connect(self.import_file) fra_file_lay.addWidget(self.btn_file) fra_file_lay.setContentsMargins(0, 0, 0, 0) self.lbl_list = QLabel(self.labels[edit_type]) self.lst_list = QListWidget() self.lst_list.currentItemChanged.connect(self.list_item_changed) # Form self.fra_form = QFrame() fra_form1_lay = QFormLayout(self.fra_form) fra_form1_lay.setContentsMargins(0, 0, 0, 0) fra_form1_lay.addRow(self.lbl_list, self.lst_list) # Buttons self.fra_buttons = QFrame() fra_buttons_lay = QHBoxLayout(self.fra_buttons) fra_buttons_lay.setContentsMargins(0, 0, 0, 0) if self.edit_type == self.edit_patterns: ele_name = 'pattern' elif self.edit_type == self.edit_curves: ele_name = 'curve' self.btn_new = QPushButton('New ' + ele_name) # TODO: softcode self.btn_new.clicked.connect(self.new_element) fra_buttons_lay.addWidget(self.btn_new) self.btn_import = QPushButton('Import ' + ele_name + 's') # TODO: softcode self.btn_import.clicked.connect(self.import_file) fra_buttons_lay.addWidget(self.btn_import) self.btn_save = QPushButton('Save current ' + ele_name) # TODO: softcode self.btn_save.clicked.connect(self.save) fra_buttons_lay.addWidget(self.btn_save) self.btn_del = QPushButton('Delete current ' + ele_name) # TODO: softcode self.btn_del.clicked.connect(self.del_item) fra_buttons_lay.addWidget(self.btn_del) # ID self.lbl_id = QLabel('ID:') self.txt_id = QLineEdit() self.txt_id.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.MinimumExpanding) self.lbl_desc = QLabel('Desc.:') self.txt_desc = QLineEdit() self.fra_id = QFrame() fra_id_lay = QHBoxLayout(self.fra_id) fra_id_lay.addWidget(self.lbl_id) fra_id_lay.addWidget(self.txt_id) fra_id_lay.addWidget(self.lbl_desc) fra_id_lay.addWidget(self.txt_desc) # Table form self.table = QTableWidget(self) self.rows_nr = 24 self.cols_nr = 2 self.table.setRowCount(self.rows_nr) self.table.setColumnCount(self.cols_nr) self.table.verticalHeader().setVisible(False) # Initialize empty table self.clear_table() self.table.itemChanged.connect(self.data_changed) self.fra_table = QFrame() fra_table_lay = QVBoxLayout(self.fra_table) fra_table_lay.setContentsMargins(0, 0, 0, 0) if edit_type == self.edit_curves: self.fra_pump_type = QFrame() fra_pump_type_lay = QFormLayout(self.fra_pump_type) self.lbl_pump_type = QLabel('Curve type:') # TODO: softcode self.cbo_pump_type = QComboBox() for key, name in Curve.type_names.items(): self.cbo_pump_type.addItem(name, key) fra_pump_type_lay.addRow(self.lbl_pump_type, self.cbo_pump_type) fra_table_lay.addWidget(self.fra_pump_type) self.cbo_pump_type.activated.connect(self.cbo_pump_type_activated) fra_table_lay.addWidget(self.table) self.btn_add_row = QPushButton('Add row') self.btn_add_row.clicked.connect(self.add_row) fra_table_lay.addWidget(self.btn_add_row) # Graph canvas self.fra_graph = QFrame() self.static_canvas = StaticMplCanvas(self.fra_graph, width=5, height=4, dpi=100) fra_graph_lay = QVBoxLayout(self.fra_graph) fra_graph_lay.addWidget(self.static_canvas) # Top frame self.fra_top = QFrame() fra_top_lay = QVBoxLayout(self.fra_top) fra_top_lay.addWidget(self.fra_form) fra_top_lay.addWidget(self.fra_id) fra_top_lay.addWidget(self.fra_buttons) # Bottom frame self.fra_bottom = QFrame() fra_bottom_lay = QHBoxLayout(self.fra_bottom) fra_bottom_lay.addWidget(self.fra_table) fra_bottom_lay.addWidget(self.fra_graph) # Main main_lay.addWidget(self.fra_top) main_lay.addWidget(self.fra_bottom) # Get existing patterns/curves self.need_to_update_graph = False if self.edit_type == self.edit_patterns: for pattern_id, pattern in self.params.patterns.items(): self.lst_list.addItem(pattern.id) elif self.edit_type == self.edit_curves: for curve_id, curve in self.params.curves.items(): self.lst_list.addItem(curve.id) if self.lst_list.count() > 0: self.lst_list.setCurrentRow(0) self.txt_id.setEnabled(True) self.txt_desc.setEnabled(True) self.btn_save.setEnabled(True) self.btn_del.setEnabled(True) self.table.setEnabled(True) self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) else: self.txt_id.setEnabled(False) self.txt_desc.setEnabled(False) self.btn_save.setEnabled(False) self.btn_del.setEnabled(False) self.table.setEnabled(False) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.new_dialog = None self.need_to_update_graph = True def cbo_pump_type_activated(self): self.update_table_headers() self.update_graph() def add_row(self): row_pos = self.table.rowCount() self.table.insertRow(row_pos) col = 0 item = QTableWidgetItem(str(row_pos)) if self.edit_type == self.edit_patterns: self.table.setItem(row_pos, col, item) item.setFlags(QtCore.Qt.ItemIsSelectable) def setVisible(self, bool): QDialog.setVisible(self, bool) self.update_table_headers() self.update_graph() def list_item_changed(self): p_index = self.lst_list.currentRow() flags = Qt.ItemFlags() flags != Qt.ItemIsEnabled # Clear table self.clear_table() self.need_to_update_graph = False if p_index >= 0: self.table.setRowCount(0) if self.edit_type == self.edit_patterns: self.current = self.params.patterns[ self.lst_list.currentItem().text()] for v in range(len(self.current.values)): row_pos = self.table.rowCount() self.table.insertRow(row_pos) item = QTableWidgetItem(str(v)) item.setFlags(flags) self.table.setItem(v, 0, item) self.table.setItem( v, 1, QTableWidgetItem(str(self.current.values[v]))) elif self.edit_type == self.edit_curves: self.current = self.params.curves[ self.lst_list.currentItem().text()] for v in range(len(self.current.xs)): row_pos = self.table.rowCount() self.table.insertRow(row_pos) self.table.setItem( v, 0, QTableWidgetItem(str(self.current.xs[v]))) self.table.setItem( v, 1, QTableWidgetItem(str(self.current.ys[v]))) curve_type = self.current.type self.cbo_pump_type.setCurrentIndex(curve_type) # Update GUI self.txt_id.setText(self.current.id) self.txt_desc.setText(self.current.desc) self.update_table_headers() # Update graph self.need_to_update_graph = True self.update_graph() else: # No curves self.txt_id.setText('') self.txt_desc.setText('') # Update table and chart self.need_to_update_graph = False for v in range(self.table.columnCount()): self.table.setItem(v, 1, QTableWidgetItem('')) self.need_to_update_graph = True self.update_graph() def import_file(self): config_file = ConfigFile(Parameters.config_file_path) directory = None if self.edit_type == GraphDialog.edit_curves: directory = self.params.last_curves_dir elif self.edit_type == GraphDialog.edit_patterns: directory = self.params.last_patterns_dir if directory is None: directory = self.params.last_project_dir file_path, __ = QFileDialog.getOpenFileName(self, 'Select file', directory, 'Files (*.txt *.inp)') if file_path is None or file_path == '': return else: if self.edit_type == GraphDialog.edit_patterns: # Save patterns file path in configuration file config_file.set_patterns_file_path(file_path) Parameters.patterns_file = file_path elif self.edit_type == GraphDialog.edit_curves: # Save curve file path in configuration file config_file.set_curves_file_path(file_path) Parameters.curves_file = file_path self.read(file_path) def read(self, file_path): self.lst_list.clear() if self.edit_type == self.edit_patterns: InpFile.read_patterns(self.params, file_path) for pattern_id, pattern in self.params.patterns.items(): # desc = ' (' + pattern.desc + ')' if pattern.desc is not None else '' self.lst_list.addItem(pattern.id) self.params.patterns[pattern.id] = pattern elif self.edit_type == self.edit_curves: InpFile.read_curves(self.params, file_path) for curve_id, curve in self.params.curves.items(): # desc = ' (' + curve.desc + ')' if curve.desc is not None else '' self.lst_list.addItem(curve.id) self.params.curves[curve.id] = curve if self.lst_list.count() > 0: self.lst_list.setCurrentRow(0) def new_element(self): old_ids = [] if self.edit_type == self.edit_patterns: for pattern in self.params.patterns.values(): old_ids.append(pattern.id) elif self.edit_type == self.edit_curves: for curve in self.params.curves.values(): old_ids.append(curve.id) self.new_dialog = NewIdDialog(self, old_ids) self.new_dialog.exec_() new_id = self.new_dialog.get_newid() description = self.new_dialog.get_description() if new_id is None or description is None: return if self.edit_type == self.edit_patterns: new_pattern = Pattern(new_id, description) self.params.patterns[new_pattern.id] = new_pattern self.lst_list.addItem(new_pattern.id) elif self.edit_type == self.edit_curves: curve_type = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) new_curve = Curve(new_id, curve_type, desc=description) self.params.curves[new_curve.id] = new_curve self.lst_list.addItem(new_curve.id) self.lst_list.setCurrentRow(self.lst_list.count() - 1) self.txt_id.setText(new_id) self.txt_desc.setText(description) # Clear table self.clear_table() self.static_canvas.axes.clear() self.txt_id.setEnabled(True) self.txt_desc.setEnabled(True) self.btn_save.setEnabled(True) self.btn_del.setEnabled(True) self.table.setEnabled(True) self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) def save(self): self.need_to_update_graph = False # Check for ID if not self.txt_id.text(): QMessageBox.warning( self, Parameters.plug_in_name, u'Please specify the ID.', # TODO: softcode QMessageBox.Ok) return if self.edit_type == GraphDialog.edit_patterns: values = [] for row in range(self.table.rowCount()): item = self.table.item(row, 1) if item is not None and item.text() != '': values.append(self.from_item_to_val(item)) else: values.append('0') pattern = Pattern(self.txt_id.text(), self.txt_desc.text(), values) old_patterns = self.params.patterns old_patterns[pattern.id] = pattern self.params.patterns = old_patterns self.lst_list.currentItem().setText(pattern.id) elif self.edit_type == GraphDialog.edit_curves: # Check for ID unique xs = [] ys = [] for row in range(self.table.rowCount()): item_x = self.table.item(row, 0) item_y = self.table.item(row, 1) if item_x.text().strip() != '' and item_y.text().strip() != '': xs.append(self.from_item_to_val(item_x)) ys.append(self.from_item_to_val(item_y)) curve_type = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) curve = Curve(self.txt_id.text(), curve_type, self.txt_desc.text()) for v in range(len(xs)): curve.append_xy(xs[v], ys[v]) old_curves = self.params.curves old_curves[curve.id] = curve self.params.curves = old_curves self.lst_list.currentItem().setText(curve.id) # Update GUI self.dockwidget.update_curves_combo() # self.read() self.need_to_update_graph = True def clear_table(self): self.need_to_update_graph = False for r in range(self.table.rowCount()): self.table.setItem(r, 0, QTableWidgetItem(None)) self.table.setItem(r, 1, QTableWidgetItem(None)) for row in range(self.rows_nr): for col in range(self.cols_nr): if self.edit_type == self.edit_patterns: if col == 0: item = QTableWidgetItem(str(row)) self.table.setItem(row, col, item) item.setFlags(QtCore.Qt.ItemIsSelectable) # elif col == 1 and row == 0: # item = QTableWidgetItem(str(1)) # self.table.setItem(row, col, item) # item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) # elif self.edit_type == self.edit_curves: # if row == 0: # item = QTableWidgetItem(str(0)) # self.table.setItem(row, 0, item) # item = QTableWidgetItem(str(1)) # self.table.setItem(row, 1, item) # item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) self.need_to_update_graph = True def del_item(self): selected_row = self.lst_list.currentRow() name = self.lst_list.currentItem().text() if selected_row < 0: return self.lst_list.takeItem(selected_row) if self.lst_list.count() == 0: self.txt_id.setEnabled(False) self.txt_desc.setEnabled(False) self.btn_save.setEnabled(False) self.btn_del.setEnabled(False) self.table.setEnabled(False) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) if self.edit_type == GraphDialog.edit_curves: del self.params.curves[name] # Update GUI self.dockwidget.update_curves_combo() elif self.edit_type == GraphDialog.edit_patterns: del self.params.patterns[name] # Update GUI self.dockwidget.update_patterns_combo() def data_changed(self): if self.need_to_update_graph: self.update_graph() def update_table_headers(self): if self.edit_type == self.edit_patterns: self.x_label = 'Time period' self.y_label = 'Multiplier' elif self.edit_type == self.edit_curves: cbo_data = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) if cbo_data == Curve.type_efficiency: self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Efficiency ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' if cbo_data == Curve.type_headloss: self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Headloss ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' if cbo_data == Curve.type_pump: self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Head ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' if cbo_data == Curve.type_volume: self.x_label = 'Height ' + '[' + self.params.options.flow_units + ']' self.y_label = 'Volume ' + '[' + self.params.options.units_deltaz[ self.params.options.units] + ']' self.table.setHorizontalHeaderLabels([self.x_label, self.y_label]) # TODO: softcode def update_graph(self): if not self.need_to_update_graph: return xs = [] ys = [] for row in range(self.table.rowCount()): item = self.table.item(row, 0) x = self.from_item_to_val(item) item = self.table.item(row, 1) y = self.from_item_to_val(item) if x is not None: xs.append(float(x)) if y is not None: ys.append(float(y)) if len(xs) == 0 or len(ys) == 0: self.static_canvas.clear() return xys_t = list(zip(xs, ys)) xys_t.sort() xys = list(zip(*xys_t)) xs = xys[0] ys = xys[1] if self.edit_type == self.edit_patterns: y_axis_label = 'Mult. avg.: ' + '{0:.2f}'.format( (numpy.average(ys))) self.static_canvas.draw_bars_graph( ys, time_period=self.params.times.pattern_timestep, y_axes_label=y_axis_label) elif self.edit_type == self.edit_curves: # Account for different types of curves cbo_data = self.cbo_pump_type.itemData( self.cbo_pump_type.currentIndex()) series_length = min(len(xs), len(ys)) # Need to account for different types of curves if cbo_data == Curve.type_efficiency or cbo_data == Curve.type_headloss or cbo_data == Curve.type_volume: self.static_canvas.draw_line_graph(xs[:series_length], ys[:series_length], self.x_label, self.y_label) elif cbo_data == Curve.type_pump: if series_length == 1 or series_length == 3: if series_length == 1: # 3 curve points curve_xs = [0, xs[0], xs[0] * 2] curve_ys = [ys[0] * 1.33, ys[0], 0] # y = a * x^2 + b * x + c elif series_length == 3: # 3 curve points curve_xs = [xs[0], xs[1], xs[2]] curve_ys = [ys[0], ys[1], ys[2]] (a, b, c) = numpy.polyfit(curve_xs, curve_ys, 2) # Create a few interpolated values interp_xs = [] interp_ys = [] n_vals = 30 for v in range(n_vals + 1): x = (curve_xs[2] - curve_xs[0]) / n_vals * v interp_xs.append(x) y = a * x**2 + b * x + c interp_ys.append(y) self.static_canvas.draw_line_graph(interp_xs, interp_ys, self.x_label, self.y_label) else: self.static_canvas.draw_line_graph(xs[:series_length], ys[:series_length], self.x_label, self.y_label) def from_item_to_val(self, item): if item is None: value = None else: value = item.text() try: value = float(value) value = max(value, 0) except: value = None return value
class StepKwMultiClassifications(WizardStep, FORM_CLASS): """InaSAFE Wizard Step Multi Classifications.""" def __init__(self, parent=None): """Constructor for the tab. :param parent: widget to use as parent (Wizard Dialog). :type parent: QWidget """ WizardStep.__init__(self, parent) self.exposures = [] self.exposure_labels = [] self.exposure_combo_boxes = [] self.exposure_edit_buttons = [] self.mode = CHOOSE_MODE self.layer_purpose = None self.layer_mode = None # Store the current representative state of the UI. # self.classifications = {} self.value_maps = {} self.thresholds = {} # Temporary attributes self.threshold_classes = OrderedDict() self.active_exposure = None self.list_unique_values = None self.tree_mapping_widget = None # GUI, good for testing self.save_button = None self.restore_default_button = None # Has default threshold # Trick for EQ raster for population #3853 self.use_default_thresholds = False # Index of the special case exposure classification self.special_case_index = None def is_ready_to_next_step(self): """Check if the step is complete. :returns: True if new step may be enabled. :rtype: bool """ # Still editing if self.mode == EDIT_MODE: return False for combo_box in self.exposure_combo_boxes: # Enable if there is one that has classification if combo_box.currentIndex() > 0: return True # Trick for EQ raster for population #3853 if self.use_default_thresholds: return True return False def get_next_step(self): """Find the proper step when user clicks the Next button. :returns: The step to be switched to. :rtype: WizardStep instance or None """ if self.layer_purpose != layer_purpose_aggregation: subcategory = self.parent.step_kw_subcategory.\ selected_subcategory() else: subcategory = {'key': None} if is_raster_layer(self.parent.layer): return self.parent.step_kw_source # Check if it can go to inasafe field step inasafe_fields = get_non_compulsory_fields( self.layer_purpose['key'], subcategory['key']) if not skip_inasafe_field(self.parent.layer, inasafe_fields): return self.parent.step_kw_inasafe_fields # Check if it can go to inasafe default field step default_inasafe_fields = get_fields( self.layer_purpose['key'], subcategory['key'], replace_null=True, in_group=False ) if default_inasafe_fields: return self.parent.step_kw_default_inasafe_fields # Any other case return self.parent.step_kw_source def set_wizard_step_description(self): """Set the text for description.""" subcategory = self.parent.step_kw_subcategory.selected_subcategory() field = self.parent.step_kw_field.selected_fields() is_raster = is_raster_layer(self.parent.layer) if is_raster: if self.layer_mode == layer_mode_continuous: text_label = multiple_continuous_hazard_classifications_raster else: text_label = multiple_classified_hazard_classifications_raster # noinspection PyAugmentAssignment text_label = text_label % ( subcategory['name'], self.layer_purpose['name']) else: if self.layer_mode == layer_mode_continuous: text_label = multiple_continuous_hazard_classifications_vector else: text_label = multiple_classified_hazard_classifications_vector # noinspection PyAugmentAssignment text_label = text_label % ( subcategory['name'], self.layer_purpose['name'], field) self.multi_classifications_label.setText(text_label) def setup_left_panel(self): """Setup the UI for left panel. Generate all exposure, combobox, and edit button. """ hazard = self.parent.step_kw_subcategory.selected_subcategory() left_panel_heading = QLabel(tr('Classifications')) left_panel_heading.setFont(big_font) self.left_layout.addWidget(left_panel_heading) inner_left_layout = QGridLayout() row = 0 for exposure in exposure_all: special_case = False if not setting('developer_mode'): # Filter out unsupported exposure for the hazard if exposure in hazard['disabled_exposures']: # Remove from the storage if the exposure is disabled if self.layer_mode == layer_mode_continuous: if exposure['key'] in self.thresholds: self.thresholds.pop(exposure['key']) else: if exposure['key'] in self.value_maps: self.value_maps.pop(exposure['key']) continue # Trick for EQ raster for population #3853 if exposure == exposure_population and hazard == hazard_earthquake: if is_raster_layer(self.parent.layer): if self.layer_mode == layer_mode_continuous: self.use_default_thresholds = True special_case = True # Set classification for EQ Raster for Population self.thresholds[exposure_population['key']] = { earthquake_mmi_scale['key']: { 'classes': default_classification_thresholds( earthquake_mmi_scale), 'active': True } } # Add label # Hazard on Exposure Classifications label = tr( '{hazard_name} on {exposure_name} Classifications').format( hazard_name=hazard['name'], exposure_name=exposure['name'] ) exposure_label = QLabel(label) # Add combo box exposure_combo_box = QComboBox() hazard_classifications = hazard.get('classifications') exposure_combo_box.addItem(tr('No classifications')) exposure_combo_box.setItemData( 0, None, Qt.UserRole) current_index = 0 i = 0 # Iterate through all available hazard classifications for hazard_classification in hazard_classifications: # Skip if the classification is not for the exposure if 'exposures' in hazard_classification: if exposure not in hazard_classification['exposures']: continue exposure_combo_box.addItem(hazard_classification['name']) exposure_combo_box.setItemData( i + 1, hazard_classification, Qt.UserRole) if self.layer_mode == layer_mode_continuous: current_hazard_classifications = self.thresholds.get( exposure['key']) else: current_hazard_classifications = self.value_maps.get( exposure['key']) if current_hazard_classifications: current_hazard_classification = \ current_hazard_classifications.get( hazard_classification['key']) if current_hazard_classification: is_active = current_hazard_classification.get('active') if is_active: current_index = i + 1 i += 1 # Set current classification exposure_combo_box.setCurrentIndex(current_index) # Add edit button exposure_edit_button = QPushButton(tr('Edit')) # For special case. Raster EQ on Population. if special_case: mmi_index = exposure_combo_box.findText( earthquake_mmi_scale['name']) exposure_combo_box.setCurrentIndex(mmi_index) exposure_combo_box.setEnabled(False) exposure_edit_button.setEnabled(False) tool_tip_message = tr( 'InaSAFE use default classification for Raster Earthquake ' 'hazard on population.') exposure_label.setToolTip(tool_tip_message) exposure_combo_box.setToolTip(tool_tip_message) exposure_edit_button.setToolTip(tool_tip_message) else: if current_index == 0: # Disable if there is no classification chosen. exposure_edit_button.setEnabled(False) exposure_edit_button.clicked.connect( partial( self.edit_button_clicked, edit_button=exposure_edit_button, exposure_combo_box=exposure_combo_box, exposure=exposure)) exposure_combo_box.currentIndexChanged.connect( partial( self.classifications_combo_box_changed, exposure=exposure, exposure_combo_box=exposure_combo_box, edit_button=exposure_edit_button)) # Arrange in layout inner_left_layout.addWidget(exposure_label, row, 0) inner_left_layout.addWidget(exposure_combo_box, row, 1) inner_left_layout.addWidget(exposure_edit_button, row, 2) # Adding to step's attribute self.exposures.append(exposure) self.exposure_combo_boxes.append(exposure_combo_box) self.exposure_edit_buttons.append(exposure_edit_button) self.exposure_labels.append(label) if special_case: self.special_case_index = len(self.exposures) - 1 row += 1 self.left_layout.addLayout(inner_left_layout) # To push the inner_left_layout up self.left_layout.addStretch(1) # noinspection PyUnusedLocal def edit_button_clicked(self, edit_button, exposure_combo_box, exposure): """Method to handle when an edit button is clicked. :param edit_button: The edit button. :type edit_button: QPushButton :param exposure_combo_box: The combo box of the exposure, contains list of classifications. :type exposure_combo_box: QComboBox :param exposure: Exposure definition. :type exposure: dict """ # Note(IS): Do not change the text of edit button for now until we # have better behaviour. classification = self.get_classification(exposure_combo_box) if self.mode == CHOOSE_MODE: # Change mode self.mode = EDIT_MODE # Set active exposure self.active_exposure = exposure # Disable all edit button for exposure_edit_button in self.exposure_edit_buttons: exposure_edit_button.setEnabled(False) # Except one that was clicked # edit_button.setEnabled(True) # Disable all combo box for exposure_combo_box in self.exposure_combo_boxes: exposure_combo_box.setEnabled(False) # Change the edit button to cancel # edit_button.setText(tr('Cancel')) # Clear right panel clear_layout(self.right_layout) # Show edit threshold or value mapping if self.layer_mode == layer_mode_continuous: self.setup_thresholds_panel(classification) else: self.setup_value_mapping_panels(classification) self.add_buttons(classification) elif self.mode == EDIT_MODE: # Behave the same as cancel button clicked. self.cancel_button_clicked() self.parent.pbnNext.setEnabled(self.is_ready_to_next_step()) def show_current_state(self): """Setup the UI for QTextEdit to show the current state.""" right_panel_heading = QLabel(tr('Status')) right_panel_heading.setFont(big_font) right_panel_heading.setSizePolicy( QSizePolicy.Maximum, QSizePolicy.Maximum) self.right_layout.addWidget(right_panel_heading) message = m.Message() if self.layer_mode == layer_mode_continuous: title = tr('Thresholds') else: title = tr('Value maps') message.add(m.Heading(title, **INFO_STYLE)) for i in range(len(self.exposures)): message.add(m.Text(self.exposure_labels[i])) classification = self.get_classification( self.exposure_combo_boxes[i]) if self.layer_mode == layer_mode_continuous: thresholds = self.thresholds.get(self.exposures[i]['key']) if not thresholds or not classification: message.add(m.Paragraph(tr('No classifications set.'))) continue table = m.Table( style_class='table table-condensed table-striped') header = m.Row() header.add(m.Cell(tr('Class name'))) header.add(m.Cell(tr('Minimum'))) header.add(m.Cell(tr('Maximum'))) table.add(header) classes = classification.get('classes') # Sort by value, put the lowest first classes = sorted(classes, key=lambda k: k['value']) for the_class in classes: threshold = thresholds[classification['key']]['classes'][ the_class['key']] row = m.Row() row.add(m.Cell(the_class['name'])) row.add(m.Cell(threshold[0])) row.add(m.Cell(threshold[1])) table.add(row) else: value_maps = self.value_maps.get(self.exposures[i]['key']) if not value_maps or not classification: message.add(m.Paragraph(tr('No classifications set.'))) continue table = m.Table( style_class='table table-condensed table-striped') header = m.Row() header.add(m.Cell(tr('Class name'))) header.add(m.Cell(tr('Value'))) table.add(header) classes = classification.get('classes') # Sort by value, put the lowest first classes = sorted(classes, key=lambda k: k['value']) for the_class in classes: value_map = value_maps[classification['key']][ 'classes'].get(the_class['key'], []) row = m.Row() row.add(m.Cell(the_class['name'])) row.add(m.Cell(', '.join([str(v) for v in value_map]))) table.add(row) message.add(table) # status_text_edit = QTextBrowser(None) status_text_edit = QWebView(None) status_text_edit.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Ignored) status_text_edit.page().mainFrame().setScrollBarPolicy( Qt.Horizontal, Qt.ScrollBarAlwaysOff) html_string = html_header() + message.to_html() + html_footer() status_text_edit.setHtml(html_string) self.right_layout.addWidget(status_text_edit) def set_widgets(self): """Set widgets on the Multi classification step.""" self.clear() self.layer_mode = self.parent.step_kw_layermode.selected_layermode() self.layer_purpose = self.parent.step_kw_purpose.selected_purpose() self.set_current_state() # Set the step description self.set_wizard_step_description() # Set the left panel self.setup_left_panel() # Set the right panel, for the beginning show the viewer self.show_current_state() def clear(self): """Clear current state.""" self.exposures = [] self.exposure_labels = [] self.exposure_combo_boxes = [] self.exposure_edit_buttons = [] self.mode = CHOOSE_MODE self.layer_purpose = None self.layer_mode = None self.special_case_index = None self.value_maps = {} self.thresholds = {} # Temporary attributes self.threshold_classes = OrderedDict() self.active_exposure = None self.list_unique_values = None self.tree_mapping_widget = None clear_layout(self.left_layout) clear_layout(self.right_layout) def get_current_state(self): """Obtain current classification and value map / threshold.""" def clean_state(dictionary): """Clean dictionary from bad value. :param dictionary: Dictionary of value maps or thresholds. :type dictionary: dict :returns: Clean state. :rtype: dict """ clean_dictionary = { k: v for k, v in list(dictionary.items()) if isinstance(v, dict)} return clean_dictionary if self.layer_mode == layer_mode_continuous: output = {'thresholds': clean_state(self.thresholds)} key = 'thresholds' else: output = {'value_maps': clean_state(self.value_maps)} key = 'value_maps' # Clean non existing hazard class key empty_exposure_classifications = [] for the_exposure, the_hazard_classifications in list( output[key].items()): for the_hazard_classification in list(the_hazard_classifications. keys()): invalid_classifications = [] if not definition(the_hazard_classification): invalid_classifications.append( the_hazard_classification) for invalid_classification in invalid_classifications: the_hazard_classifications.pop(invalid_classification) if not the_hazard_classifications: empty_exposure_classifications.append(the_exposure) for empty_exposure_classification in empty_exposure_classifications: output[key].pop(empty_exposure_classification) return output @staticmethod def get_classification(combo_box): """Helper to obtain the classification from a combo box. :param combo_box: A classification combo box. :type combo_box: QComboBox. :returns: Classification definitions. :rtype: dict """ return combo_box.itemData(combo_box.currentIndex(), Qt.UserRole) 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 add_buttons(self, classification): """Helper to setup 3 buttons. :param classification: The current classification. :type classification: dict """ # Note(IS): Until we have good behaviour, we will disable cancel # button. # Add 3 buttons: Restore default, Cancel, Save # Restore default button, only for continuous layer (with threshold) if self.layer_mode == layer_mode_continuous['key']: self.restore_default_button = QPushButton(tr('Restore Default')) self.restore_default_button.clicked.connect(partial( self.restore_default_button_clicked, classification=classification)) # Cancel button # cancel_button = QPushButton(tr('Cancel')) # cancel_button.clicked.connect(self.cancel_button_clicked) # Save button self.save_button = QPushButton(tr('Save')) self.save_button.clicked.connect( partial(self.save_button_clicked, classification=classification)) button_layout = QHBoxLayout() button_layout.addStretch(1) button_layout.addWidget(self.restore_default_button) button_layout.addWidget(self.save_button) button_layout.setStretch(0, 3) button_layout.setStretch(1, 1) button_layout.setStretch(2, 1) # button_layout.setStretch(3, 1) self.right_layout.addLayout(button_layout) 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 ) # noinspection PyMethodMayBeStatic def update_dragged_item_flags(self, item): """Fix the drop flag after the item is dropped. Check if it looks like an item dragged from QListWidget to QTreeWidget and disable the drop flag. For some reasons the flag is set when dragging. :param item: Item which is dragged. :type item: QTreeWidgetItem .. note:: This is a slot executed when the item change. """ if int(item.flags() & Qt.ItemIsDropEnabled) \ and int(item.flags() & Qt.ItemIsDragEnabled): item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled) @staticmethod def populate_classified_values( unassigned_values, assigned_values, default_classes, list_unique_values, tree_mapping_widget): """Populate lstUniqueValues and treeClasses.from the parameters. :param unassigned_values: List of values that haven't been assigned to a class. It will be put in list_unique_values. :type unassigned_values: list :param assigned_values: Dictionary with class as the key and list of value as the value of the dictionary. It will be put in tree_mapping_widget. :type assigned_values: dict :param default_classes: Default classes from unit. :type default_classes: list :param list_unique_values: List Widget for unique values :type list_unique_values: QListWidget :param tree_mapping_widget: Tree Widget for classifying. :type tree_mapping_widget: QTreeWidget """ # Populate the unique values list list_unique_values.clear() list_unique_values.setSelectionMode( QAbstractItemView.ExtendedSelection) for value in unassigned_values: value_as_string = value is not None and str(value) or 'NULL' list_item = QListWidgetItem(list_unique_values) list_item.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) list_item.setData(Qt.UserRole, value) list_item.setText(value_as_string) list_unique_values.addItem(list_item) # Populate assigned values tree tree_mapping_widget.clear() bold_font = QFont() bold_font.setItalic(True) bold_font.setBold(True) bold_font.setWeight(75) tree_mapping_widget.invisibleRootItem().setFlags( Qt.ItemIsEnabled) for default_class in default_classes: # Create branch for class tree_branch = QTreeWidgetItem(tree_mapping_widget) tree_branch.setFlags( Qt.ItemIsDropEnabled | Qt.ItemIsEnabled) tree_branch.setExpanded(True) tree_branch.setFont(0, bold_font) if 'name' in default_class: default_class_name = default_class['name'] else: default_class_name = default_class['key'] tree_branch.setText(0, default_class_name) tree_branch.setData(0, Qt.UserRole, default_class['key']) if 'description' in default_class: tree_branch.setToolTip(0, default_class['description']) # Assign known values for value in assigned_values[default_class['key']]: string_value = value is not None and str(value) or 'NULL' tree_leaf = QTreeWidgetItem(tree_branch) tree_leaf.setFlags( Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) tree_leaf.setData(0, Qt.UserRole, value) tree_leaf.setText(0, string_value) def cancel_button_clicked(self): """Action for cancel button clicked.""" # Change mode self.mode = CHOOSE_MODE # Enable all edit buttons and combo boxes for i in range(len(self.exposures)): if i == self.special_case_index: self.exposure_edit_buttons[i].setEnabled(False) self.exposure_combo_boxes[i].setEnabled(False) continue if self.get_classification(self.exposure_combo_boxes[i]): self.exposure_edit_buttons[i].setEnabled(True) else: self.exposure_edit_buttons[i].setEnabled(False) # self.exposure_edit_buttons[i].setText(tr('Edit')) self.exposure_combo_boxes[i].setEnabled(True) # Clear right panel clear_layout(self.right_layout) # Show current state self.show_current_state() # Unset active exposure self.active_exposure = None self.parent.pbnNext.setEnabled(self.is_ready_to_next_step()) def save_button_clicked(self, classification): """Action for save button clicked. :param classification: The classification that being edited. :type classification: dict """ # Save current edit if self.layer_mode == layer_mode_continuous: thresholds = self.get_threshold() classification_class = { 'classes': thresholds, 'active': True } if self.thresholds.get(self.active_exposure['key']): # Set other class to not active for current_classification in list(self.thresholds.get( self.active_exposure['key']).values()): current_classification['active'] = False else: self.thresholds[self.active_exposure['key']] = {} self.thresholds[self.active_exposure['key']][ classification['key']] = classification_class else: value_maps = self.get_value_map() classification_class = { 'classes': value_maps, 'active': True } if self.value_maps.get(self.active_exposure['key']): # Set other class to not active for current_classification in list(self.value_maps.get( self.active_exposure['key']).values()): current_classification['active'] = False else: self.value_maps[self.active_exposure['key']] = {} self.value_maps[self.active_exposure['key']][ classification['key']] = classification_class # Back to choose mode self.cancel_button_clicked() def restore_default_button_clicked(self, classification): """Action for restore default button clicked. It will set the threshold with default value. :param classification: The classification that being edited. :type classification: dict """ # Obtain default value class_dict = {} for the_class in classification.get('classes'): class_dict[the_class['key']] = { 'numeric_default_min': the_class['numeric_default_min'], 'numeric_default_max': the_class['numeric_default_max'], } # Set for all threshold for key, value in list(self.threshold_classes.items()): value[0].setValue(class_dict[key]['numeric_default_min']) value[1].setValue(class_dict[key]['numeric_default_max']) def get_threshold(self): """Return threshold based on current state.""" value_map = dict() for key, value in list(self.threshold_classes.items()): value_map[key] = [ value[0].value(), value[1].value(), ] return value_map def get_value_map(self): """Obtain the value-to-class mapping set by user. :returns: The complete mapping as a dict of lists. :rtype: dict """ value_map = {} tree_clone = self.tree_mapping_widget.invisibleRootItem().clone() for tree_branch in tree_clone.takeChildren(): value_list = [] for tree_leaf in tree_branch.takeChildren(): value_list += [tree_leaf.data(0, Qt.UserRole)] if value_list: value_map[tree_branch.data(0, Qt.UserRole)] = value_list return value_map def set_current_state(self): """"Helper to set the state of the step from current keywords.""" if not self.thresholds: self.thresholds = self.parent.get_existing_keyword('thresholds') if not self.value_maps: self.value_maps = self.parent.get_existing_keyword('value_maps') def classifications_combo_box_changed( self, index, exposure, exposure_combo_box, edit_button): """Action when classification combo box changed. :param index: The index of the combo box. :type index: int :param exposure: The exposure associated with the combo box. :type exposure: dict :param exposure_combo_box: Combo box for the classification. :type exposure_combo_box: QComboBox :param edit_button: The edit button associate with combo box. :type edit_button: QPushButton """ # Disable button if it's no classification edit_button.setEnabled(bool(index)) classification = self.get_classification(exposure_combo_box) self.activate_classification(exposure, classification) clear_layout(self.right_layout) self.show_current_state() self.parent.pbnNext.setEnabled(self.is_ready_to_next_step()) # Open edit panel directly edit_button.click() def activate_classification(self, exposure, classification=None): """Set active to True for classification for the exposure. If classification = None, all classification set active = False. :param exposure: Exposure definition. :type exposure: dict :param classification: Classification definition. :type classification: dict """ if self.layer_mode == layer_mode_continuous: selected_unit = self.parent.step_kw_unit.selected_unit()['key'] target = self.thresholds.get(exposure['key']) if target is None: self.thresholds[exposure['key']] = {} target = self.thresholds.get(exposure['key']) else: selected_unit = None target = self.value_maps.get(exposure['key']) if target is None: self.value_maps[exposure['key']] = {} target = self.value_maps.get(exposure['key']) if classification is not None: if classification['key'] not in target: if self.layer_mode == layer_mode_continuous: default_classes = default_classification_thresholds( classification, selected_unit) target[classification['key']] = { 'classes': default_classes, 'active': True } else: # Set classes to empty, since we haven't mapped anything target[classification['key']] = { 'classes': {}, 'active': True } return for classification_key, value in list(target.items()): if classification is None: value['active'] = False continue if classification_key == classification['key']: value['active'] = True else: value['active'] = False @property def step_name(self): """Get the human friendly name for the wizard step. :returns: The name of the wizard step. :rtype: str """ return tr('Multi Classification Step') def help_content(self): """Return the content of help for this step wizard. We only needs to re-implement this method in each wizard step. :returns: A message object contains help. :rtype: m.Message """ message = m.Message() message.add(m.Paragraph(tr( 'In this wizard step: {step_name}, you will be able to set the ' 'classification that you will use per exposure type. You can also ' 'set the threshold or value map for each classification.' ).format(step_name=self.step_name))) return message
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 ScenarioSelectionDialog(QDialog): """ A dialog used for selecting from available scenarios """ def __init__(self, scenario_registry: ScenarioRegistry, parent=None): """ Constructor for ScenarioSelectionDialog :param scenario_registry: linked scenario registry :param parent: parent widget """ super().__init__(parent) self.scenario_registry = scenario_registry self.setWindowTitle(self.tr('Select Current Scenario')) layout = QVBoxLayout() self.search = QgsFilterLineEdit() self.search.setShowSearchIcon(True) self.search.setPlaceholderText(self.tr('Search for scenario')) self.search.textChanged.connect(self.filter_changed) layout.addWidget(self.search) self.list = QListWidget() for title, scenario_id in scenario_registry.scenario_titles().items(): item = QListWidgetItem(title) item.setData(Qt.UserRole, scenario_id) self.list.addItem(item) layout.addWidget(self.list, 10) button_box = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(button_box) button_box.rejected.connect(self.reject) button_box.accepted.connect(self.accept) self.setLayout(layout) self.list.itemDoubleClicked.connect( self.accept) # select last scenario by default if self.list.count() > 0: self.list.item(self.list.count() - 1).setSelected(True) def set_selected_scenario(self, scenario): """ Sets the scenario selected in the dialog :param scenario: scenario to select """ for i in range(self.list.count()): if self.list.item(i).data(Qt.UserRole) == scenario: self.list.item(i).setSelected(True) return def selected_scenario(self): """ Returns the scenario selected in the dialog """ if self.list.selectedItems(): return self.list.selectedItems()[0].data(Qt.UserRole) return None def filter_changed(self, filter_text): """ Handles search filter changes """ for i in range(self.list.count()): item = self.list.item(i) item.setHidden(filter_text.upper() not in item.text().upper())
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 __init__(self, dockwidget, parent, params, edit_type): QDialog.__init__(self, parent) main_lay = QVBoxLayout(self) self.dockwidget = dockwidget self.params = params self.edit_type = edit_type self.x_label = '' self.y_label = '' self.setMinimumWidth(600) self.setMinimumHeight(400) self.setWindowTitle(self.titles[edit_type]) # TODO: softcode self.setWindowModality(QtCore.Qt.ApplicationModal) self.current = None self.current_saved = False # File self.lbl_file = QLabel('File:') self.fra_file = QFrame() self.fra_file.setContentsMargins(0, 0, 0, 0) fra_file_lay = QHBoxLayout(self.fra_file) if edit_type == self.edit_patterns: self.txt_file = QLineEdit(self.params.patterns_file) elif edit_type == self.edit_curves: self.txt_file = QLineEdit(self.params.curves_file) self.txt_file.setReadOnly(True) self.txt_file.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) self.txt_file.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum) fra_file_lay.addWidget(self.txt_file) self.btn_file = QPushButton('Change') # TODO: softcode self.btn_file.clicked.connect(self.import_file) fra_file_lay.addWidget(self.btn_file) fra_file_lay.setContentsMargins(0, 0, 0, 0) self.lbl_list = QLabel(self.labels[edit_type]) self.lst_list = QListWidget() self.lst_list.currentItemChanged.connect(self.list_item_changed) # Form self.fra_form = QFrame() fra_form1_lay = QFormLayout(self.fra_form) fra_form1_lay.setContentsMargins(0, 0, 0, 0) fra_form1_lay.addRow(self.lbl_list, self.lst_list) # Buttons self.fra_buttons = QFrame() fra_buttons_lay = QHBoxLayout(self.fra_buttons) fra_buttons_lay.setContentsMargins(0, 0, 0, 0) if self.edit_type == self.edit_patterns: ele_name = 'pattern' elif self.edit_type == self.edit_curves: ele_name = 'curve' self.btn_new = QPushButton('New ' + ele_name) # TODO: softcode self.btn_new.clicked.connect(self.new_element) fra_buttons_lay.addWidget(self.btn_new) self.btn_import = QPushButton('Import ' + ele_name + 's') # TODO: softcode self.btn_import.clicked.connect(self.import_file) fra_buttons_lay.addWidget(self.btn_import) self.btn_save = QPushButton('Save current ' + ele_name) # TODO: softcode self.btn_save.clicked.connect(self.save) fra_buttons_lay.addWidget(self.btn_save) self.btn_del = QPushButton('Delete current ' + ele_name) # TODO: softcode self.btn_del.clicked.connect(self.del_item) fra_buttons_lay.addWidget(self.btn_del) # ID self.lbl_id = QLabel('ID:') self.txt_id = QLineEdit() self.txt_id.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.MinimumExpanding) self.lbl_desc = QLabel('Desc.:') self.txt_desc = QLineEdit() self.fra_id = QFrame() fra_id_lay = QHBoxLayout(self.fra_id) fra_id_lay.addWidget(self.lbl_id) fra_id_lay.addWidget(self.txt_id) fra_id_lay.addWidget(self.lbl_desc) fra_id_lay.addWidget(self.txt_desc) # Table form self.table = QTableWidget(self) self.rows_nr = 24 self.cols_nr = 2 self.table.setRowCount(self.rows_nr) self.table.setColumnCount(self.cols_nr) self.table.verticalHeader().setVisible(False) # Initialize empty table self.clear_table() self.table.itemChanged.connect(self.data_changed) self.fra_table = QFrame() fra_table_lay = QVBoxLayout(self.fra_table) fra_table_lay.setContentsMargins(0, 0, 0, 0) if edit_type == self.edit_curves: self.fra_pump_type = QFrame() fra_pump_type_lay = QFormLayout(self.fra_pump_type) self.lbl_pump_type = QLabel('Curve type:') # TODO: softcode self.cbo_pump_type = QComboBox() for key, name in Curve.type_names.items(): self.cbo_pump_type.addItem(name, key) fra_pump_type_lay.addRow(self.lbl_pump_type, self.cbo_pump_type) fra_table_lay.addWidget(self.fra_pump_type) self.cbo_pump_type.activated.connect(self.cbo_pump_type_activated) fra_table_lay.addWidget(self.table) self.btn_add_row = QPushButton('Add row') self.btn_add_row.clicked.connect(self.add_row) fra_table_lay.addWidget(self.btn_add_row) # Graph canvas self.fra_graph = QFrame() self.static_canvas = StaticMplCanvas(self.fra_graph, width=5, height=4, dpi=100) fra_graph_lay = QVBoxLayout(self.fra_graph) fra_graph_lay.addWidget(self.static_canvas) # Top frame self.fra_top = QFrame() fra_top_lay = QVBoxLayout(self.fra_top) fra_top_lay.addWidget(self.fra_form) fra_top_lay.addWidget(self.fra_id) fra_top_lay.addWidget(self.fra_buttons) # Bottom frame self.fra_bottom = QFrame() fra_bottom_lay = QHBoxLayout(self.fra_bottom) fra_bottom_lay.addWidget(self.fra_table) fra_bottom_lay.addWidget(self.fra_graph) # Main main_lay.addWidget(self.fra_top) main_lay.addWidget(self.fra_bottom) # Get existing patterns/curves self.need_to_update_graph = False if self.edit_type == self.edit_patterns: for pattern_id, pattern in self.params.patterns.items(): self.lst_list.addItem(pattern.id) elif self.edit_type == self.edit_curves: for curve_id, curve in self.params.curves.items(): self.lst_list.addItem(curve.id) if self.lst_list.count() > 0: self.lst_list.setCurrentRow(0) self.txt_id.setEnabled(True) self.txt_desc.setEnabled(True) self.btn_save.setEnabled(True) self.btn_del.setEnabled(True) self.table.setEnabled(True) self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) else: self.txt_id.setEnabled(False) self.txt_desc.setEnabled(False) self.btn_save.setEnabled(False) self.btn_del.setEnabled(False) self.table.setEnabled(False) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.new_dialog = None self.need_to_update_graph = True
class TreeSettingItem(QTreeWidgetItem): def __init__(self, parent, tree, name, value, action=None): QTreeWidgetItem.__init__(self, parent) self.parent = parent self.tree = tree self.name = name self._value = value self.combo = None self.list = None self.setText(0, name) widget = None if isinstance(value, QgsColorButton): widget = value elif isinstance(value, bool): if value: self.setCheckState(1, Qt.Checked) else: self.setCheckState(1, Qt.Unchecked) elif isinstance(value, tuple): self.combo = QComboBox() self.combo.setSizeAdjustPolicy(0) for option in value: self.combo.addItem(option) widget = self.combo elif isinstance(value, list): self.list = QListWidget() self.list.setSizeAdjustPolicy(0) self.list.setSelectionMode(QListWidget.MultiSelection) for option in value: self.list.addItem(option) widget = self.list else: self.setText(1, unicode(value)) if action: layout = QHBoxLayout() layout.setMargin(0) if widget: layout.addWidget(widget) button = QToolButton() button.setDefaultAction(action) button.setText(action.text()) layout.addWidget(button) layout.addStretch(1) widget = QWidget() widget.setLayout(layout) if widget: self.tree.setItemWidget(self, 1, widget) def setValue(self, value): if isinstance(value, bool): if value: self.setCheckState(1, Qt.Checked) else: self.setCheckState(1, Qt.Unchecked) elif self.combo: index = self.combo.findText(value) if index != -1: self.combo.setCurrentIndex(index) else: self.setText(1, str(value)) def value(self): if isinstance(self._value, bool): return self.checkState(1) == Qt.Checked elif isinstance(self._value, (int, float)): return float(self.text(1)) elif isinstance(self._value, tuple): return self.combo.currentText() else: return self.text(1)
class DeprecateElectorateDialog(QDialog): """ A dialog used for selecting electorates to deprecate (or un-deprecate) :param district_registry: associated registry of available districts to show """ def __init__(self, electorate_registry: LinzElectoralDistrictRegistry, parent=None): super().__init__(parent) self.electorate_registry = electorate_registry self.setWindowTitle(self.tr('Deprecate Electorate')) layout = QVBoxLayout() self.search = QgsFilterLineEdit() self.search.setShowSearchIcon(True) self.search.setPlaceholderText( self.tr('Search for {}').format( electorate_registry.type_string_sentence())) self.search.textChanged.connect(self.filter_changed) layout.addWidget(self.search) request = QgsFeatureRequest() request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes([ electorate_registry.source_field_index, electorate_registry.title_field_index, electorate_registry.deprecated_field_index ]) self.list = QListWidget() for f in electorate_registry.source_layer.getFeatures(request): title = f[electorate_registry.title_field_index] code = f[electorate_registry.source_field_index] deprecated = f[electorate_registry.deprecated_field_index] if deprecated: title = '*' + title item = QListWidgetItem(title) item.setData(Qt.UserRole, code) self.list.addItem(item) layout.addWidget(self.list, 10) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) layout.addWidget(button_box) button_box.rejected.connect(self.reject) button_box.accepted.connect(self.accept) self.setLayout(layout) self.list.itemDoubleClicked.connect(self.accept) def selected_district(self): """ Returns the electorate selected in the dialog """ if self.list.selectedItems(): return self.list.selectedItems()[0].data(Qt.UserRole) return None def filter_changed(self, filter_text): """ Handles search filter changes """ for i in range(self.list.count()): item = self.list.item(i) item.setHidden(filter_text.upper() not in item.text().upper())
class TagsDialog(QDialog): def __init__(self, dockwidget, parent, params): QDialog.__init__(self, parent) main_lay = QVBoxLayout(self) self.dockwidget = dockwidget self.params = params self.setWindowTitle('Tags editor') # Top frame self.fra_top = QFrame() fra_top_lay = QVBoxLayout(self.fra_top) self.lst_main = QListWidget(self) self.btn_add = QPushButton('Add tag') self.btn_add.clicked.connect(self.add_tag) self.btn_remove = QPushButton('Remove tag') self.btn_remove.clicked.connect(self.remove_tag) fra_top_lay.addWidget(self.lst_main) fra_top_lay.addWidget(self.btn_add) fra_top_lay.addWidget(self.btn_remove) # Bottom frame self.fra_bottom = QFrame() fra_bottom_lay = QHBoxLayout(self.fra_bottom) btb_main = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) btb_main.accepted.connect(self.ok) btb_main.rejected.connect(self.reject) fra_bottom_lay.addWidget(btb_main) # Main main_lay.addWidget(self.fra_top) main_lay.addWidget(self.fra_bottom) self.initialize() def initialize(self): for tag_name in self.params.tag_names: self.lst_main.insertItem(self.lst_main.count(), QListWidgetItem(tag_name, self.lst_main)) def ok(self): tag_names = [] for r in range(self.lst_main.count()): tag_names.append(self.lst_main.item(r).text()) self.params.tag_names = tag_names self.setVisible(False) def reject(self): self.setVisible(False) def add_tag(self): tag_name_dialog = TagNameDialog(self.dockwidget, self) tag_name_dialog.exec_() tag_name = tag_name_dialog.get_tag_name() if tag_name is not None: current_row = self.lst_main.currentRow() if current_row is None: current_row = self.lst_main.count() self.lst_main.insertItem(current_row, QListWidgetItem(tag_name, self.lst_main)) def remove_tag(self): sel_items = self.lst_main.selectedItems() for sel_item in sel_items: self.lst_main.takeItem(self.lst_main.row(sel_item))