Esempio n. 1
0
class DataSourceSelectDialog(base, ui):
    """
    Reusable dialog for selecting a map layer source based on the QGIS browser.
    Allows for selection of disk based layers, together with layers from database
    and online providers (such as Oracle/Postgres/etc)
    """
    def __init__(self, layer_name, original_uri, layer_type, parent=None):
        super().__init__(parent)

        self.setupUi(self)
        self.setWindowTitle("Select Source for {}".format(layer_name))
        QgsGui.enableAutoGeometryRestore(self)

        # in case browser panel isn't open, we need to force initialize the model now
        iface.browserModel().initialize()

        self.browser_proxy_model = QgsBrowserProxyModel(self)
        self.browser_proxy_model.setBrowserModel(iface.browserModel())
        self.browser_proxy_model.setFilterByLayerType(True)
        self.browser_proxy_model.setLayerType(layer_type)
        self.mBrowserTreeView.setHeaderHidden(True)
        self.mBrowserTreeView.setModel(self.browser_proxy_model)
        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
        self.mBrowserTreeView.clicked.connect(self.on_layer_selected)
        self.uri = None
        self.description_label = None
        self.setDescription("Original source: {}".format(original_uri))

    def setDescription(self, description):
        """
        Sets the description to show in the dialog
        """
        if description:
            if not self.description_label:
                self.description_label = QLabel()
                self.description_label.setWordWrap(True)
                self.description_label.setMargin(4)
                self.verticalLayout.insertWidget(1, self.description_label)
            self.description_label.setText(description)
        else:
            if self.description_label:
                self.verticalLayout.removeWidget(self.description_label)
                self.description_label.deleteLater()
                self.description_label = None

    def on_layer_selected(self, index):
        """
        Triggered on selecting a layer
        """
        is_layer_compatible = False
        self.uri = QgsMimeDataUtils.Uri()
        if index.isValid():
            item = self.browser_proxy_model.dataItem(index)
            if item:
                if issubclass(item.__class__, QgsLayerItem):
                    is_layer_compatible = True
                    self.uri = item.mimeUri()

        self.buttonBox.button(
            QDialogButtonBox.Ok).setEnabled(is_layer_compatible)
Esempio n. 2
0
 def addLayer(self, geometryType=None, crs=None):
     layer = self.toMapLayer(geometryType, crs)
     layers = QgsProject.instance().addMapLayers([layer])
     if len(layers) != 1:
         QgsMessageLog.logMessage(self.tr("{layer} is an invalid layer - not loaded").format(layer=layer.publicSource()))
         msgLabel = QLabel(self.tr("{layer} is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info.").format(layer=layer.publicSource()), self.mainWindow.infoBar)
         msgLabel.setWordWrap(True)
         msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show)
         msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_)
         self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, Qgis.Warning))
Esempio n. 3
0
    def update_history_view(self):
        """Update the history view."""
        historic_folder = query_historic()
        files = os.listdir(historic_folder)

        self.dialog.list_historic.clear()

        for file in files[::-1]:
            file_path = join(historic_folder, file)
            with open(file_path, encoding='utf8') as json_file:
                data = json.load(json_file, object_hook=as_enum)
            name = data['file_name']

            item = QListWidgetItem(self.dialog.list_historic)
            self.dialog.list_historic.addItem(item)

            group = QFrame()
            group.setFrameStyle(QFrame.StyledPanel)
            group.setStyleSheet('QFrame { margin: 3px; }')
            group.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            hbox = QHBoxLayout()
            vbox = QVBoxLayout()
            label_name = QLabel(name)
            label_name.setStyleSheet('font-weight: bold;')
            label_name.setWordWrap(True)
            vbox.addWidget(label_name)
            for label in data['description']:
                if not label:
                    label = tr('No description')
                real_label = QLabel(label)
                real_label.setWordWrap(True)
                vbox.addWidget(real_label)
            hbox.addItem(vbox)
            button_run = QPushButton()
            button_save = QPushButton()
            button_run.setIcon(QIcon(QgsApplication.iconPath("mActionStart.svg")))
            button_save.setIcon(QIcon(QgsApplication.iconPath("mActionFileSave.svg")))
            button_run.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            button_save.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            button_run.setToolTip(tr('Run the query'))
            button_save.setToolTip(tr('Save this query in a new preset'))
            hbox.addWidget(button_run)
            hbox.addWidget(button_save)
            group.setLayout(hbox)

            # Actions on click
            run = partial(self.run_saved_query, data)
            button_run.clicked.connect(run)
            save = partial(self.save_history_preset, data)
            button_save.clicked.connect(save)

            item.setSizeHint(group.minimumSizeHint())
            self.dialog.list_historic.setItemWidget(item, group)
Esempio n. 4
0
 def show_error(self, error_text):
     self.lstSearchResult.clear()
     new_widget = QLabel()
     new_widget.setTextFormat(Qt.RichText)
     new_widget.setOpenExternalLinks(True)
     new_widget.setWordWrap(True)
     new_widget.setText(
         u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>"
         .format(self.tr('Error'), error_text))
     new_item = QListWidgetItem(self.lstSearchResult)
     new_item.setSizeHint(new_widget.sizeHint())
     self.lstSearchResult.addItem(new_item)
     self.lstSearchResult.setItemWidget(new_item, new_widget)
Esempio n. 5
0
	def createWidgets(self):

		vlayout = QVBoxLayout()

		lbl = QLabel(
			"A column labeled 'ID' with unique increasing numbers for every row will be "\
			"added to the output table automatically. In addition to this column it is also "\
			"possible to copy one of the columns of the source table to the output table "\
			"(tip: if a row identifying column is copied this can later be used for transferring "\
			"more data from source table to the new table if necessary).")
		lbl.setWordWrap(True);
		vlayout.addWidget(lbl)

		vlayout.addSpacing(20)

		self._copyCheck = WidgetEnableCheckBox("Copy column from source table")
		self.regProp("copy_column_enabled", WizProp(self._copyCheck, False))
		vlayout.addWidget(self._copyCheck)

		glayout = QGridLayout()
		glayout.setColumnMinimumWidth(0, 20)

		lbl = QLabel(
			"The selected column of the source table will be added to the output table "\
			"(possibly with a new name). For every object in the output table the value of "\
			"its source object will be copied to this column.")
		lbl.setWordWrap(True);
		self._copyCheck.addWidget(lbl)
		glayout.addWidget(lbl, 0, 1, 1, 3)

		lbl = QLabel("Column in source table")
		self._copyCheck.addWidget(lbl)
		glayout.addWidget(lbl, 1, 1)
		self._sourceCombo = QComboBox()
		self.regProp("copy_column_in", WizProp(self._sourceCombo, ""))
		self._copyCheck.addWidget(self._sourceCombo)
		glayout.addWidget(self._sourceCombo, 1, 2)

		lbl = QLabel("Column in output table")
		self._copyCheck.addWidget(lbl)
		glayout.addWidget(lbl, 2, 1)
		self._outputEdit = QLineEdit()
		self.regProp("copy_column_out", WizProp(self._outputEdit, ""))
		self._copyCheck.addWidget(self._outputEdit)
		glayout.addWidget(self._outputEdit, 2, 2)

		vlayout.addLayout(glayout)

		vlayout.addStretch(1)

		self.setLayout(vlayout)
Esempio n. 6
0
 def addLayer(self):
     table = self.currentTable()
     if table is not None:
         layer = table.toMapLayer()
         layers = QgsMapLayerRegistry.instance().addMapLayers([layer])
         if len(layers) != 1:
             QgsMessageLog.logMessage(
                 self.tr("%1 is an invalid layer - not loaded").replace("%1", layer.publicSource()))
             msgLabel = QLabel(self.tr(
                 "%1 is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info.").replace(
                 "%1", layer.publicSource()), self.mainWindow.infoBar)
             msgLabel.setWordWrap(True)
             msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show)
             msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_)
             self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, QgsMessageBar.WARNING))
Esempio n. 7
0
    def setup_default_preset(self):
        """Setup the display of presets"""
        preset_folder = resources_path('map_preset')
        folders = os.listdir(preset_folder)

        for folder_name in folders:
            file_path = join(preset_folder, folder_name, folder_name + '.json')
            with open(file_path, encoding='utf8') as json_file:
                data = json.load(json_file, object_hook=as_enum)

            item = QListWidgetItem(self.dialog.list_default_mp)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
                          | Qt.ItemIsEnabled)
            self.dialog.list_default_mp.addItem(item)

            widget = QFrame()
            widget.setFrameStyle(QFrame.StyledPanel)
            widget.setStyleSheet('QFrame { margin: 3px; };')
            widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            hbox = QHBoxLayout()
            vbox = QVBoxLayout()
            picture = QLabel()
            icon_path = resources_path('map_preset', folder_name,
                                       folder_name + '_icon.png')
            if not os.path.isfile(icon_path):
                icon_path = resources_path('icons', 'QuickOSM.svg')
            icon = QPixmap(icon_path)
            icon.scaled(QSize(150, 250), Qt.KeepAspectRatio)
            picture.setPixmap(icon)
            picture.setStyleSheet(
                'max-height: 150px; max-width: 250px; margin-right: 50px;')
            hbox.addWidget(picture)
            title = QLabel(data['file_name'])
            title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
            title.setStyleSheet('font: bold 20px; margin-bottom: 25px;')
            vbox.addWidget(title)
            for label in data['description']:
                if not label:
                    label = tr('No description')
                real_label = QLabel(label)
                real_label.setWordWrap(True)
                vbox.addWidget(real_label)
            hbox.addItem(vbox)
            widget.setLayout(hbox)

            item.setSizeHint(widget.minimumSizeHint())
            self.dialog.list_default_mp.setItemWidget(item, widget)
Esempio n. 8
0
 def _create_labels(self):
     for i in range(len(self.steps)):
         if i != 0:
             spacer = QSpacerItem(
                 self.label_spacing_width,
                 0,
                 QSizePolicy.Expanding,
                 QSizePolicy.Minimum,
             )
             self.layout_labels.addItem(spacer)
         label = QLabel(self.steps[i])
         label.font_size = 11
         label.setWordWrap(True)
         label.setAlignment(Qt.AlignCenter)
         label.setFixedWidth(self.label_width)
         self.layout_labels.addWidget(label)
         self.widgets[i].append(label)
    def populate_functions_dlg(self, dialog, result):

        status = False
        for group, function in result['fields'].items():
            if len(function) != 0:
                dialog.setWindowTitle(function[0]['alias'])
                dialog.txt_info.setText(str(function[0]['descript']))
                if str(function[0]['isparametric']) in ('false', 'False',
                                                        False, 'None', None,
                                                        'null'):
                    self.is_paramtetric = False
                    self.control_isparametric(dialog)
                    self.load_settings_values(dialog, function)
                    if str(function[0]['isnotparammsg']) is not None:
                        layout = dialog.findChild(QGridLayout,
                                                  'grl_option_parameters')
                        if layout is None:
                            status = True
                            break
                        label = QLabel()
                        label.setWordWrap(True)
                        label.setText("Info: " +
                                      str(function[0]['isnotparammsg']))
                        layout.addWidget(label, 0, 0)
                    status = True
                    break
                if not function[0]['input_params']['featureType']:
                    dialog.grb_input_layer.setVisible(False)
                    dialog.grb_selection_type.setVisible(False)
                else:
                    feature_types = function[0]['input_params']['featureType']
                    self.populate_cmb_type(feature_types)
                    self.dlg_functions.cmb_geom_type.currentIndexChanged.connect(
                        partial(self.populate_layer_combo))
                    self.populate_layer_combo()
                construct_form_param_user(dialog, function, 0,
                                          self.function_list,
                                          self.temp_layers_added)
                self.load_settings_values(dialog, function)
                self.load_parametric_values(dialog, function)
                status = True
                break

        return status
 def show_error(self, error_text):
     self.lstSearchResult.clear()
     new_widget = QLabel()
     new_widget.setTextFormat(Qt.RichText)
     new_widget.setOpenExternalLinks(True)
     new_widget.setWordWrap(True)
     new_widget.setText(
         u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>".format(
             self.tr('Error'),
             error_text
         )
     )
     new_item = QListWidgetItem(self.lstSearchResult)
     new_item.setSizeHint(new_widget.sizeHint())
     self.lstSearchResult.addItem(new_item)
     self.lstSearchResult.setItemWidget(
         new_item,
         new_widget
     )
Esempio n. 11
0
 def search_finished_progress(self):
     self.lstSearchResult.takeItem(0)
     if self.lstSearchResult.count() == 0:
         new_widget = QLabel()
         new_widget.setTextFormat(Qt.RichText)
         new_widget.setOpenExternalLinks(True)
         new_widget.setWordWrap(True)
         new_widget.setText(
             u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>"
             .format(
                 self.tr(u"No results."),
                 self.
                 tr(u"You can add a service to become searchable. Start <a href='{}'>here</a>."
                    ).format(u"https://qms.nextgis.com/create"),
             ))
         new_item = QListWidgetItem(self.lstSearchResult)
         new_item.setSizeHint(new_widget.sizeHint())
         self.lstSearchResult.addItem(new_item)
         self.lstSearchResult.setItemWidget(new_item, new_widget)
 def search_finished_progress(self):
     self.lstSearchResult.takeItem(0)
     if self.lstSearchResult.count() == 0:
         new_widget = QLabel()
         new_widget.setTextFormat(Qt.RichText)
         new_widget.setOpenExternalLinks(True)
         new_widget.setWordWrap(True)
         new_widget.setText(
             u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>".format(
                 self.tr(u"No results."),
                 self.tr(u"You can add a service to become searchable. Start <a href='{}'>here</a>.").format(
                     u"https://qms.nextgis.com/create"
                 ),
             )
         )
         new_item = QListWidgetItem(self.lstSearchResult)
         new_item.setSizeHint(new_widget.sizeHint())
         self.lstSearchResult.addItem(new_item)
         self.lstSearchResult.setItemWidget(
             new_item,
             new_widget
         )
Esempio n. 13
0
 def addLayer(self):
     table = self.currentTable()
     if table is not None:
         layer = table.toMapLayer()
         layers = QgsProject.instance().addMapLayers([layer])
         if len(layers) != 1:
             QgsMessageLog.logMessage(
                 self.tr("%1 is an invalid layer - not loaded").replace(
                     "%1", layer.publicSource()))
             msgLabel = QLabel(
                 self.
                 tr("%1 is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info."
                    ).replace("%1", layer.publicSource()),
                 self.mainWindow.infoBar)
             msgLabel.setWordWrap(True)
             msgLabel.linkActivated.connect(
                 self.mainWindow.iface.mainWindow().findChild(
                     QWidget, "MessageLog").show)
             msgLabel.linkActivated.connect(
                 self.mainWindow.iface.mainWindow().raise_)
             self.mainWindow.infoBar.pushItem(
                 QgsMessageBarItem(msgLabel, Qgis.Warning))
    def setup_value_mapping_panels(self, classification):
        """Setup value mapping panel in the right panel.

        :param classification: Classification definition.
        :type classification: dict
        """
        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory. \
            selected_subcategory()

        if is_raster_layer(self.parent.layer):
            description_text = classify_raster_question % (
                layer_subcategory['name'],
                layer_purpose['name'],
                classification['name'])

            dataset = gdal.Open(self.parent.layer.source(), GA_ReadOnly)
            active_band = self.parent.step_kw_band_selector.selected_band()
            unique_values = numpy.unique(numpy.array(
                dataset.GetRasterBand(active_band).ReadAsArray()))
            field_type = 0
            # Convert datatype to a json serializable type
            if numpy.issubdtype(unique_values.dtype, float):
                unique_values = [float(i) for i in unique_values]
            else:
                unique_values = [int(i) for i in unique_values]
        else:
            field = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.fields().indexFromName(field)
            field_type = self.parent.layer.fields()[field_index].type()
            description_text = classify_vector_question % (
                layer_subcategory['name'],
                layer_purpose['name'],
                classification['name'],
                field.upper())
            unique_values = list(self.parent.layer.uniqueValues(field_index))

        # Set description
        description_label = QLabel(description_text)
        description_label.setWordWrap(True)
        self.right_layout.addWidget(description_label)

        self.list_unique_values = QListWidget()
        self.list_unique_values.setDragDropMode(QAbstractItemView.DragDrop)
        self.list_unique_values.setDefaultDropAction(Qt.MoveAction)

        self.tree_mapping_widget = QTreeWidget()
        self.tree_mapping_widget.setDragDropMode(QAbstractItemView.DragDrop)
        self.tree_mapping_widget.setDefaultDropAction(Qt.MoveAction)
        self.tree_mapping_widget.header().hide()

        self.tree_mapping_widget.itemChanged.connect(
            self.update_dragged_item_flags)

        value_mapping_layout = QHBoxLayout()
        value_mapping_layout.addWidget(self.list_unique_values)
        value_mapping_layout.addWidget(self.tree_mapping_widget)

        self.right_layout.addLayout(value_mapping_layout)

        default_classes = classification['classes']

        # Assign unique values to classes (according to default)
        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if (unique_value is None
                    or (hasattr(unique_value, 'isNull')
                        and unique_value.isNull())):
                # Don't classify features with NULL value
                continue
            # Capitalization of the value and removing '_' (raw OSM data).
            value_as_string = str(unique_value).upper().replace('_', ' ')
            assigned = False
            for default_class in default_classes:
                if 'string_defaults' in default_class:
                    # To make it case insensitive
                    upper_string_defaults = [
                        c.upper() for c in default_class['string_defaults']]
                    in_string_default = (
                        value_as_string in upper_string_defaults)
                    condition_1 = field_type > 9 and in_string_default
                else:
                    condition_1 = False
                condition_2 = (
                    field_type < 10
                    and 'numeric_default_min' in default_class
                    and 'numeric_default_max' in default_class
                    and (default_class['numeric_default_min']
                         <= unique_value
                         < default_class['numeric_default_max']))
                if condition_1 or condition_2:
                    assigned_values[default_class['key']] += [unique_value]
                    assigned = True
                    break
            if not assigned:
                # add to unassigned values list otherwise
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values,
            assigned_values,
            default_classes,
            self.list_unique_values,
            self.tree_mapping_widget
        )

        # Current value map for exposure and classification
        available_classifications = self.value_maps.get(
            self.active_exposure['key'])
        if not available_classifications:
            return
        # Get active one
        current_classification = available_classifications.get(
            classification['key'])
        if not current_classification:
            return
        # Should come from metadata
        current_value_map = current_classification.get('classes')
        if not current_value_map:
            return

        unassigned_values = list()
        assigned_values = dict()
        for default_class in default_classes:
            assigned_values[default_class['key']] = list()
        for unique_value in unique_values:
            if (unique_value is None
                    or (hasattr(unique_value, 'isNull')
                        and unique_value.isNull())):
                # Don't classify features with NULL value
                continue
            # check in value map
            assigned = False
            for key, value_list in list(current_value_map.items()):
                if unique_value in value_list and key in assigned_values:
                    assigned_values[key] += [unique_value]
                    assigned = True
            if not assigned:
                unassigned_values += [unique_value]
        self.populate_classified_values(
            unassigned_values,
            assigned_values,
            default_classes,
            self.list_unique_values,
            self.tree_mapping_widget
        )
    def setup_thresholds_panel(self, classification):
        """Setup threshold panel in the right panel.

        :param classification: Classification definition.
        :type classification: dict
        """
        # Set text in the label
        layer_purpose = self.parent.step_kw_purpose.selected_purpose()
        layer_subcategory = self.parent.step_kw_subcategory.\
            selected_subcategory()

        if is_raster_layer(self.parent.layer):
            active_band = self.parent.step_kw_band_selector.selected_band()
            layer_extent = self.parent.layer.extent()
            statistics = self.parent.layer.dataProvider().bandStatistics(
                active_band, QgsRasterBandStats.All, layer_extent, 0)
            description_text = continuous_raster_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                classification['name'],
                statistics.minimumValue,
                statistics.maximumValue)
        else:
            field_name = self.parent.step_kw_field.selected_fields()
            field_index = self.parent.layer.fields().lookupField(field_name)
            min_value_layer = self.parent.layer.minimumValue(field_index)
            max_value_layer = self.parent.layer.maximumValue(field_index)
            description_text = continuous_vector_question % (
                layer_purpose['name'],
                layer_subcategory['name'],
                field_name,
                classification['name'],
                min_value_layer,
                max_value_layer)

        # Set description
        description_label = QLabel(description_text)
        description_label.setWordWrap(True)
        self.right_layout.addWidget(description_label)

        if self.thresholds:
            thresholds = self.thresholds
        else:
            thresholds = self.parent.get_existing_keyword('thresholds')
        selected_unit = self.parent.step_kw_unit.selected_unit()['key']

        self.threshold_classes = OrderedDict()
        classes = classification.get('classes')
        # Sort by value, put the lowest first
        classes = sorted(classes, key=lambda the_key: the_key['value'])

        grid_layout_thresholds = QGridLayout()

        for i, the_class in enumerate(classes):
            class_layout = QHBoxLayout()

            # Class label
            class_label = QLabel(the_class['name'])

            # Min label
            min_label = QLabel(tr('Min >'))

            # Min value as double spin
            min_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            min_value_input.setMinimum(0)
            min_value_input.setMaximum(999999)

            if thresholds.get(self.active_exposure['key']):
                exposure_thresholds = thresholds.get(
                    self.active_exposure['key'])
                if exposure_thresholds.get(classification['key']):
                    exposure_thresholds_classifications = exposure_thresholds\
                        .get(classification['key'])
                    min_value_input.setValue(
                        exposure_thresholds_classifications['classes'][
                            the_class['key']][0])
                else:
                    default_min = the_class['numeric_default_min']
                    if isinstance(default_min, dict):
                        default_min = the_class[
                            'numeric_default_min'][selected_unit]
                    min_value_input.setValue(default_min)
            else:
                default_min = the_class['numeric_default_min']
                if isinstance(default_min, dict):
                    default_min = the_class[
                        'numeric_default_min'][selected_unit]
                min_value_input.setValue(default_min)
            min_value_input.setSingleStep(0.1)

            # Max label
            max_label = QLabel(tr('Max <='))

            # Max value as double spin
            max_value_input = QDoubleSpinBox()
            # TODO(IS) We can set the min and max depends on the unit, later
            max_value_input.setMinimum(0)
            max_value_input.setMaximum(999999)
            if thresholds.get(self.active_exposure['key']):
                exposure_thresholds = thresholds.get(
                    self.active_exposure['key'])
                if exposure_thresholds.get(classification['key']):
                    exposure_thresholds_classifications = exposure_thresholds \
                        .get(classification['key'])
                    max_value_input.setValue(
                        exposure_thresholds_classifications['classes'][
                            the_class['key']][1])
                else:
                    default_max = the_class['numeric_default_max']
                    if isinstance(default_max, dict):
                        default_max = the_class[
                            'numeric_default_max'][selected_unit]
                    max_value_input.setValue(default_max)
            else:
                default_max = the_class['numeric_default_max']
                if isinstance(default_max, dict):
                    default_max = the_class[
                        'numeric_default_max'][selected_unit]
                max_value_input.setValue(default_max)
            max_value_input.setSingleStep(0.1)

            # Add to class_layout
            class_layout.addWidget(min_label)
            class_layout.addWidget(min_value_input)
            class_layout.addWidget(max_label)
            class_layout.addWidget(max_value_input)

            class_layout.setStretch(0, 1)
            class_layout.setStretch(1, 2)
            class_layout.setStretch(2, 1)
            class_layout.setStretch(3, 2)

            # Add to grid_layout
            grid_layout_thresholds.addWidget(class_label, i, 0)
            grid_layout_thresholds.addLayout(class_layout, i, 1)

            self.threshold_classes[the_class['key']] = [
                min_value_input, max_value_input]

        grid_layout_thresholds.setColumnStretch(0, 1)
        grid_layout_thresholds.setColumnStretch(0, 2)

        def min_max_changed(double_spin_index, mode):
            """Slot when min or max value change.

            :param double_spin_index: The index of the double spin.
            :type double_spin_index: int

            :param mode: The flag to indicate the min or max value.
            :type mode: int
            """
            if mode == MAX_VALUE_MODE:
                current_max_value = list(self.threshold_classes.values())[
                    double_spin_index][1]
                target_min_value = list(self.threshold_classes.values())[
                    double_spin_index + 1][0]
                if current_max_value.value() != target_min_value.value():
                    target_min_value.setValue(current_max_value.value())
            elif mode == MIN_VALUE_MODE:
                current_min_value = list(self.threshold_classes.values())[
                    double_spin_index][0]
                target_max_value = list(self.threshold_classes.values())[
                    double_spin_index - 1][1]
                if current_min_value.value() != target_max_value.value():
                    target_max_value.setValue(current_min_value.value())

        # Set behaviour
        for k, v in list(self.threshold_classes.items()):
            index = list(self.threshold_classes.keys()).index(k)
            if index < len(self.threshold_classes) - 1:
                # Max value changed
                v[1].valueChanged.connect(partial(
                    min_max_changed,
                    double_spin_index=index,
                    mode=MAX_VALUE_MODE))
            if index > 0:
                # Min value
                v[0].valueChanged.connect(partial(
                    min_max_changed,
                    double_spin_index=index,
                    mode=MIN_VALUE_MODE))

        grid_layout_thresholds.setSpacing(0)

        self.right_layout.addLayout(grid_layout_thresholds)
Esempio n. 16
0
    def update_personal_preset_view(self):
        """Update the presets displayed."""
        preset_folder = query_preset()
        files = filter(
            lambda folder: os.path.isdir(join(preset_folder, folder)),
            os.listdir(preset_folder))

        self.dialog.list_personal_preset_mp.clear()

        for file in files:
            file_path = join(preset_folder, file, file + '.json')
            with open(file_path, encoding='utf8') as json_file:
                data = json.load(json_file, object_hook=as_enum)
            name = data['file_name']

            item = QListWidgetItem(self.dialog.list_personal_preset_mp)
            item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
                          | Qt.ItemIsEnabled)
            self.dialog.list_personal_preset_mp.addItem(item)

            preset = QFrame()
            preset.setObjectName('FramePreset')
            preset.setFrameStyle(QFrame.StyledPanel)
            preset.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            hbox = QHBoxLayout()
            vbox = QVBoxLayout()
            label_name = QLabel(name)
            label_name.setStyleSheet('font-weight: bold;')
            label_name.setWordWrap(True)
            vbox.addWidget(label_name)
            for label in data['description']:
                if not label:
                    label = tr('No description')
                real_label = QLabel(label)
                real_label.setWordWrap(True)
                vbox.addWidget(real_label)
            hbox.addItem(vbox)
            button_edit = QPushButton()
            button_remove = QPushButton()
            button_edit.setIcon(
                QIcon(QgsApplication.iconPath("mActionToggleEditing.svg")))
            button_remove.setIcon(
                QIcon(QgsApplication.iconPath('symbologyRemove.svg')))
            button_edit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            button_remove.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            button_edit.setToolTip(tr('Edit the preset'))
            button_remove.setToolTip(tr('Delete the preset'))
            hbox.addWidget(button_edit)
            hbox.addWidget(button_remove)
            if data['advanced']:
                self.listAdvanced.append(True)
                preset.setStyleSheet('#FramePreset { margin: 3px;'
                                     ' border: 3px solid ' +
                                     self.advanced_selected + ';'
                                     ' border-width: 1px 1px 1px 4px;}')
            else:
                self.listAdvanced.append(False)
                preset.setStyleSheet('#FramePreset { margin: 3px;'
                                     ' border: 3px solid ' +
                                     self.basic_selected + ';'
                                     ' border-width: 1px 1px 1px 4px;}')
            preset.setLayout(hbox)

            # Actions on click
            remove = partial(self.verification_remove_preset, item, name)
            button_remove.clicked.connect(remove)
            edit = partial(self.edit_preset, data)
            button_edit.clicked.connect(edit)

            item.setSizeHint(preset.minimumSizeHint())
            self.dialog.list_personal_preset_mp.setItemWidget(item, preset)

        self.listAdvanced.append(False)
Esempio n. 17
0
class PlanetOrderBundleWidget(QFrame):

    selectionChanged = pyqtSignal()

    def __init__(self, bundleid, bundle, item_type):
        super().__init__()
        self.bundleid = bundleid
        self.name = bundle["name"]
        self.description = bundle["description"]
        self.udm = bundle.get("auxiliaryFiles", "").lower().startswith("udm2")
        assets = bundle["assets"]
        self.can_harmonize = ("ortho_analytic_4b_sr" in assets
                              or "ortho_analytic_8b_sr" in assets)
        self.can_harmonize = bundle.get("canHarmonize", False)
        self.can_clip = bundle.get("canClip", False)
        self.rectified = bundle["rectification"] == "orthorectified"
        bands = []
        asset_def = PlanetClient.getInstance(
        ).asset_types_for_item_type_as_dict(item_type)
        for asset in assets:
            asset_bands = asset_def[asset].get("bands", [])
            for band in asset_bands:
                bands.append(band["name"])
        bands = set(bands)
        layout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.setMargin(0)
        self.labelName = QLabel(f"<b>{self.name}</b>")
        hlayout.addWidget(self.labelName)
        hlayout.addStretch()
        self.chkSelected = QCheckBox()
        self.chkSelected.stateChanged.connect(self.checkStateChanged)
        hlayout.addWidget(self.chkSelected)
        layout.addLayout(hlayout)
        self.labelDescription = QLabel(self.description)
        self.labelDescription.setWordWrap(True)
        layout.addWidget(self.labelDescription)
        self.labelBands = QLabel(
            f"Bands: {', '.join([str(b) for b in bands])}")
        layout.addWidget(self.labelBands)
        hlayouttype = QHBoxLayout()
        hlayouttype.setMargin(0)
        self.radioTiff = QRadioButton("GeoTIFF")
        self.radioTiff.setChecked(True)
        self.radioTiff.toggled.connect(self.selectionChanged.emit)
        hlayouttype.addWidget(self.radioTiff)
        self.radioNitf = QRadioButton("NITF")
        self.radioNitf.toggled.connect(self.selectionChanged.emit)
        hlayouttype.addWidget(self.radioNitf)
        hlayouttype.addStretch()
        layout.addLayout(hlayouttype)
        if self.udm:
            hlayoutudm = QHBoxLayout()
            hlayoutudm.setMargin(0)
            self.labelUdm = IconLabel("UDM2", UDM_ICON)
            hlayoutudm.addWidget(self.labelUdm)
            hlayoutudm.addStretch()
            layout.addLayout(hlayoutudm)
        layout.addStretch()
        self.setFrameStyle(QFrame.Panel | QFrame.Raised)
        self.setLayout(layout)
        self.checkStateChanged()

    def checkStateChanged(self):
        self.radioTiff.setEnabled(self.chkSelected.isChecked())
        self.radioNitf.setEnabled(self.chkSelected.isChecked())
        self.labelName.setEnabled(self.chkSelected.isChecked())
        self.labelDescription.setEnabled(self.chkSelected.isChecked())
        self.labelBands.setEnabled(self.chkSelected.isChecked())
        if self.udm:
            self.labelUdm.setEnabled(self.chkSelected.isChecked())
        self.selectionChanged.emit()

    def selected(self):
        return self.chkSelected.isChecked()

    def setSelected(self, selected, emit=False):
        if not emit:
            self.blockSignals(True)
        self.chkSelected.setChecked(selected)
        self.blockSignals(False)

    def filetype(self):
        if self.radioTiff.isChecked():
            return "GeoTIFF"
        else:
            return "NITF"
    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)
class DockWidgetGimpSelectionFeature(QDockWidget):
    def __init__(self, iface):
        def setupUi():
            def getLayout(parent, widgets):
                lyt = QGridLayout(parent)
                for item in widgets:
                    if 'spam' in item:
                        sRow, sCol = item['spam']['row'], item['spam']['col']
                        lyt.addWidget(item['widget'], item['row'], item['col'],
                                      sRow, sCol, Qt.AlignLeft)
                    else:
                        lyt.addWidget(item['widget'], item['row'], item['col'],
                                      Qt.AlignLeft)
                return lyt

            def getGroupBox(name, parent, widgets):
                lyt = getLayout(parent, widgets)
                gbx = QGroupBox(name, parent)
                gbx.setLayout(lyt)
                return gbx

            def getSpinBoxOffset(wgt, value):
                sp = QDoubleSpinBox(wgt)
                sp.setRange(0.0, 50.0)
                sp.setSingleStep(12.5)
                sp.setDecimals(2)
                sp.setSuffix(' %')
                sp.setValue(value)
                return sp

            def getSpinRemoveAreaPixels(wgt, value):
                sp = QSpinBox(wgt)
                sp.setRange(0, 1000)
                sp.setSingleStep(1)
                sp.setSuffix(' pixels')
                sp.setValue(value)
                return sp

            def getSpinBoxAzimuth(wgt, value):
                sp = QSpinBox(wgt)
                sp.setRange(0, 45)
                sp.setSingleStep(1)
                sp.setSuffix(' degrees')
                sp.setValue(value)
                msg = QCoreApplication.translate(
                    'GimpSelectionFeature',
                    'Degrees of azimuth between vertexs')
                sp.setToolTip(msg)
                return sp

            def getSpinBoxIteration(wgt, value):
                sp = QSpinBox(wgt)
                sp.setRange(0, 3)
                sp.setSingleStep(1)
                sp.setValue(value)
                return sp

            self.setObjectName('gimpselectionfeature_dockwidget')
            wgt = QWidget(self)
            wgt.setAttribute(Qt.WA_DeleteOnClose)
            # Image
            width = 180
            self.lblLegendImages = QLabel('', wgt)
            self.lblLegendImages.setWordWrap(True)
            self.lblLegendImages.setMaximumWidth(width)
            l_wts = [{'widget': self.lblLegendImages, 'row': 0, 'col': 0}]
            name = self.formatTitleImages.format(0)
            self.gbxImage = getGroupBox(name, wgt, l_wts)
            # Transfer
            msg = QCoreApplication.translate('GimpSelectionFeature',
                                             'Send image')
            self.btnSendImage = QPushButton(msg, wgt)
            #
            msg = QCoreApplication.translate('GimpSelectionFeature',
                                             'Get features')
            self.btnGetFeatures = QPushButton(msg, wgt)
            msg = QCoreApplication.translate('GimpSelectionFeature',
                                             'Remove last features')
            self.btnRemoveLastFeatures = QPushButton(msg, wgt)
            #
            msg = QCoreApplication.translate('GimpSelectionFeature',
                                             'Adjust the borders')
            self.chkAdjustBorder = QCheckBox(msg, wgt)
            self.leditAnnotation = QLineEdit(wgt)
            self.sbRemoveAreaPixels = getSpinRemoveAreaPixels(wgt, 10)
            self.sbAzimuthThreshold = getSpinBoxAzimuth(wgt, 0)
            self.spSmoothOffset = getSpinBoxOffset(wgt, 25)
            self.sbSmoothIteration = getSpinBoxIteration(wgt, 1)
            msgLevel = QCoreApplication.translate('GimpSelectionFeature',
                                                  'Level(0-3):')
            msgFraction = QCoreApplication.translate(
                'GimpSelectionFeature', 'Fraction of line(0-50):')
            l_wts = [{
                'widget': QLabel(msgLevel, wgt),
                'row': 0,
                'col': 0
            }, {
                'widget': self.sbSmoothIteration,
                'row': 0,
                'col': 1
            }, {
                'widget': QLabel(msgFraction, wgt),
                'row': 1,
                'col': 0
            }, {
                'widget': self.spSmoothOffset,
                'row': 1,
                'col': 1
            }]
            msg = QCoreApplication.translate('GimpSelectionFeature', 'Smooth')
            gbxSmooth = getGroupBox(msg, wgt, l_wts)
            spamSmooth = {'row': 1, 'col': 2}
            msgAnnotation = QCoreApplication.translate('GimpSelectionFeature',
                                                       'Annotation:')
            msgRemoveArea = QCoreApplication.translate('GimpSelectionFeature',
                                                       'Remove Area:')
            msgRemoveVertex = QCoreApplication.translate(
                'GimpSelectionFeature', 'Remove Vertex:')
            l_wts = [{
                'widget': QLabel(msgAnnotation, wgt),
                'row': 0,
                'col': 0
            }, {
                'widget': self.leditAnnotation,
                'row': 0,
                'col': 1
            }, {
                'widget': QLabel(msgRemoveArea, wgt),
                'row': 1,
                'col': 0
            }, {
                'widget': self.sbRemoveAreaPixels,
                'row': 1,
                'col': 1
            }, {
                'widget': QLabel(msgRemoveVertex, wgt),
                'row': 2,
                'col': 0
            }, {
                'widget': self.sbAzimuthThreshold,
                'row': 2,
                'col': 1
            }, {
                'widget': gbxSmooth,
                'row': 3,
                'col': 0,
                'spam': spamSmooth
            }, {
                'widget': self.chkAdjustBorder,
                'row': 4,
                'col': 0,
            }]
            msg = QCoreApplication.translate('GimpSelectionFeature', 'Setting')
            self.gbxSettingFeatures = getGroupBox(msg, wgt, l_wts)
            spamSetting = {'row': 1, 'col': 2}
            l_wts = [{
                'widget': self.btnGetFeatures,
                'row': 0,
                'col': 0
            }, {
                'widget': self.btnRemoveLastFeatures,
                'row': 0,
                'col': 1
            }, {
                'widget': self.gbxSettingFeatures,
                'row': 1,
                'col': 0,
                'spam': spamSetting
            }]
            gbxGQ = getGroupBox("GIMP->QGIS", wgt, l_wts)
            l_wts = [{'widget': self.btnSendImage, 'row': 0, 'col': 0}]
            gbxQG = getGroupBox("QGIS->GIMP", wgt, l_wts)
            spamGroup = {'row': 1, 'col': 2}
            l_wts = [{
                'widget': gbxQG,
                'row': 0,
                'col': 0,
                'spam': spamGroup
            }, {
                'widget': gbxGQ,
                'row': 1,
                'col': 0,
                'spam': spamGroup
            }]
            msg = QCoreApplication.translate('GimpSelectionFeature',
                                             'Transfer')
            gbxTransfer = getGroupBox(msg, wgt, l_wts)
            #
            l_wts = [{
                'widget': self.gbxImage,
                'row': 0,
                'col': 0
            }, {
                'widget': gbxTransfer,
                'row': 1,
                'col': 0
            }]
            lyt = getLayout(wgt, l_wts)
            lyt.setSizeConstraint(QLayout.SetMaximumSize)
            wgt.setLayout(lyt)
            self.setWidget(wgt)

        super().__init__("Gimp Selection Feature", iface.mainWindow())
        #
        msg = QCoreApplication.translate('GimpSelectionFeature',
                                         'Visibles Images(total {})')
        self.formatTitleImages = msg
        setupUi()
        self.gsf = GimpSelectionFeature(iface, self)

    # def __del__(self):
    #     del self.gsf

    def clean(self):
        del self.gsf
    def upload_data(self):
        if self.check_login():
            if self.local_data_sources.count() == 0:
                return

            if self.db_connections.count() == 0:
                QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab."))
                return

            if not self.ui.cbUploadDatabase.currentIndex() >= 0:
                QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data."))
                return

            db_name = self.ui.cbUploadDatabase.currentText()

            if not self.db_connections.isPortOpen(db_name):
                uri = self.db_connections.cloud_layer_uri(db_name, "", "")
                host = str(uri.host())
                port = uri.port()
                QMessageBox.critical(self, self.tr("Network Error"),
                                     self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port)))
                return

            # disable update of local data sources during upload, as there are
            # temporary layers added and removed
            self.do_update_local_data_sources = False
            self.statusBar().showMessage(self.tr("Uploading data..."))
            self.setCursor(Qt.WaitCursor)
            self.ui.btnUploadData.hide()
            self.ui.spinner.start()
            self.ui.progressWidget.show()

            # Map<data_source, {schema: schema, table: table, layers: layers}>
            data_sources_items = {}
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = unicode(
                    self.ui.tblLocalLayers.item(
                        row, self.COLUMN_DATA_SOURCE).text())
                layers = self.local_data_sources.layers(data_source)
                if layers is not None:
                    schema_name = unicode(
                        self.ui.tblLocalLayers.cellWidget(
                            row, self.COLUMN_SCHEMA_NAME).currentText())                    
                    table_name = unicode(
                        self.ui.tblLocalLayers.item(
                            row, self.COLUMN_TABLE_NAME).text())
                    data_sources_items[data_source] = {
                        u'schema': unicode(schema_name), u'table': unicode(table_name), u'layers': layers}

            login_info = self.api.check_login(version_info=self._version_info())
            try:            
                self.maxSize = login_info['max_storage']
                self.maxDBs = login_info['max_dbs']
            except:
                self.maxSize = 50
                self.maxDBs = 5

            try:
                self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize))
                upload_ok = True
            except Exception as e:
                ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
                upload_ok = False

            self.ui.spinner.stop()
            self.ui.progressWidget.hide()
            self.ui.btnUploadData.show()
            self.unsetCursor()
            self.statusBar().showMessage("")
            # Refresh local layers
            self.do_update_local_data_sources = True
            self.update_local_layers()
            # Refresh used space after upload
            self.db_size(self.db_connections)

            if upload_ok:
                # Show save project dialog
                save_dialog = QDialog(self)
                save_dialog.setWindowTitle(self.tr("Save Project"))
                save_dialog.setLayout(QVBoxLayout())
                header = QWidget()
                header.setLayout(QVBoxLayout())
                label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database."))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                label = QLabel(self.tr("Choose were to save the modified project:"))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                save_dialog.layout().setContentsMargins(0, 0, 0, 0)
                save_dialog.layout().addWidget(header)
                initialPath = QgsProject.instance().fileName()
                if not initialPath:
                    initialPath = QSettings().value("/UI/lastProjectDir", ".")
                fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files"))
                fd.setParent(save_dialog, Qt.Widget)
                fd.setOption(QFileDialog.DontUseNativeDialog)
                fd.setAcceptMode(QFileDialog.AcceptSave)
                save_dialog.layout().addWidget(fd)
                header.layout().setContentsMargins(fd.layout().contentsMargins())
                fd.accepted.connect(save_dialog.accept)
                fd.rejected.connect(save_dialog.reject)
                if save_dialog.exec_() == QDialog.Accepted:
                    files = list(fd.selectedFiles())
                    if files:
                        QgsProject.instance().setFileName(files[0])
                        self.iface.actionSaveProject().trigger()

                # Switch to map tab
                self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
class DockWidgetGimpSelectionFeature(QDockWidget):
  def __init__(self, iface):
    def setupUi():
      def getLayout(parent, widgets):
        lyt = QGridLayout( parent )
        for item in widgets:
          if 'spam' in item:
            sRow, sCol = item['spam']['row'], item['spam']['col']
            lyt.addWidget( item['widget'], item['row'], item['col'], sRow, sCol, Qt.AlignLeft )
          else:
            lyt.addWidget( item['widget'], item['row'], item['col'], Qt.AlignLeft )
        return lyt

      def getGroupBox(name, parent, widgets):
        lyt = getLayout( parent, widgets )
        gbx = QGroupBox(name, parent )
        gbx.setLayout( lyt )
        return gbx

      def getSpinBoxOffset(wgt, value):
        sp = QDoubleSpinBox( wgt)
        sp.setRange(0.0, 50.0)
        sp.setSingleStep(12.5)
        sp.setDecimals(2)
        sp.setSuffix(' %')
        sp.setValue(value)
        return sp

      def getSpinRemoveAreaPixels(wgt, value):
        sp = QSpinBox( wgt)
        sp.setRange(0, 1000)
        sp.setSingleStep(1)
        sp.setSuffix(' pixels')
        sp.setValue(value)
        return sp

      def getSpinBoxAzimuth(wgt, value):
        sp = QSpinBox( wgt)
        sp.setRange(0, 45)
        sp.setSingleStep(1)
        sp.setSuffix(' degrees')
        sp.setValue(value)
        msg = QCoreApplication.translate('GimpSelectionFeature', 'Degrees of azimuth between vertexs')
        sp.setToolTip( msg )
        return sp

      def getSpinBoxIteration(wgt, value):
        sp = QSpinBox( wgt)
        sp.setRange(0, 3)
        sp.setSingleStep(1)
        sp.setValue(value)
        return sp

      self.setObjectName('gimpselectionfeature_dockwidget')
      wgt = QWidget( self )
      wgt.setAttribute(Qt.WA_DeleteOnClose)
      # Image
      width = 180
      self.lblLegendImages = QLabel('', wgt )
      self.lblLegendImages.setWordWrap( True )
      self.lblLegendImages.setMaximumWidth(width )
      l_wts = [ { 'widget': self.lblLegendImages,     'row': 0, 'col': 0 } ]
      name = self.formatTitleImages.format(0)
      self.gbxImage = getGroupBox(name, wgt, l_wts)
      # Transfer
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Send image')
      self.btnSendImage = QPushButton(msg, wgt )
      #
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Get features')
      self.btnGetFeatures = QPushButton( msg, wgt )
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Remove last features')
      self.btnRemoveLastFeatures = QPushButton( msg, wgt )
      #
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Adjust the borders' )
      self.chkAdjustBorder = QCheckBox( msg, wgt )
      self.leditAnnotation = QLineEdit( wgt )
      self.sbRemoveAreaPixels = getSpinRemoveAreaPixels( wgt, 10 )
      self.sbAzimuthThreshold = getSpinBoxAzimuth( wgt, 0 )
      self.spSmoothOffset = getSpinBoxOffset( wgt, 25 )
      self.sbSmoothIteration  = getSpinBoxIteration( wgt, 1)
      msgLevel = QCoreApplication.translate('GimpSelectionFeature','Level(0-3):')
      msgFraction = QCoreApplication.translate('GimpSelectionFeature','Fraction of line(0-50):')
      l_wts = [
        { 'widget': QLabel( msgLevel, wgt ),    'row': 0, 'col': 0 },
        { 'widget': self.sbSmoothIteration,     'row': 0, 'col': 1 },
        { 'widget': QLabel( msgFraction, wgt ), 'row': 1, 'col': 0 },
        { 'widget': self.spSmoothOffset,        'row': 1, 'col': 1 }
      ]
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Smooth')
      gbxSmooth = getGroupBox( msg, wgt, l_wts)
      spamSmooth = { 'row': 1, 'col': 2 }
      msgAnnotation   = QCoreApplication.translate('GimpSelectionFeature', 'Annotation:' )
      msgRemoveArea   = QCoreApplication.translate('GimpSelectionFeature', 'Remove Area:' )
      msgRemoveVertex = QCoreApplication.translate('GimpSelectionFeature', 'Remove Vertex:' )
      l_wts = [
        { 'widget': QLabel( msgAnnotation, wgt ),   'row': 0, 'col': 0 },
        { 'widget': self.leditAnnotation,           'row': 0, 'col': 1 },
        { 'widget': QLabel( msgRemoveArea, wgt ),   'row': 1, 'col': 0 },
        { 'widget': self.sbRemoveAreaPixels,          'row': 1, 'col': 1 },
        { 'widget': QLabel( msgRemoveVertex, wgt ), 'row': 2, 'col': 0 },
        { 'widget': self.sbAzimuthThreshold,        'row': 2, 'col': 1 },
        { 'widget': gbxSmooth,                      'row': 3, 'col': 0, 'spam': spamSmooth },
        { 'widget': self.chkAdjustBorder,           'row': 4, 'col': 0, }
      ]
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Setting' )
      self.gbxSettingFeatures = getGroupBox( msg, wgt, l_wts)
      spamSetting = { 'row': 1, 'col': 2 }
      l_wts = [
        { 'widget': self.btnGetFeatures,        'row': 0, 'col': 0 },
        { 'widget': self.btnRemoveLastFeatures, 'row': 0, 'col': 1 },
        { 'widget': self.gbxSettingFeatures,    'row': 1, 'col': 0, 'spam': spamSetting }
      ]
      gbxGQ = getGroupBox( "GIMP->QGIS", wgt, l_wts)
      l_wts = [
        { 'widget': self.btnSendImage,        'row': 0, 'col': 0 }
      ]
      gbxQG = getGroupBox( "QGIS->GIMP", wgt, l_wts)
      spamGroup = { 'row': 1, 'col': 2 }
      l_wts = [
        { 'widget': gbxQG,                'row': 0, 'col': 0, 'spam': spamGroup },
        { 'widget': gbxGQ,                'row': 1, 'col': 0, 'spam': spamGroup }
      ]
      msg = QCoreApplication.translate('GimpSelectionFeature', 'Transfer' )
      gbxTransfer = getGroupBox( msg, wgt, l_wts)
      #
      l_wts = [
        { 'widget': self.gbxImage,  'row': 0, 'col': 0 },
        { 'widget': gbxTransfer,    'row': 1, 'col': 0 }
      ]
      lyt = getLayout( wgt, l_wts )
      lyt.setSizeConstraint( QLayout.SetMaximumSize )
      wgt.setLayout( lyt )
      self.setWidget( wgt )

    super().__init__( "Gimp Selection Feature", iface.mainWindow() )
    #
    msg = QCoreApplication.translate('GimpSelectionFeature', 'Visibles Images(total  {})')
    self.formatTitleImages = msg
    setupUi()
    self.gsf = GimpSelectionFeature( iface, self )

  def __del__(self):
    del self.gsf
Esempio n. 22
0
class ProgressDialog(QDialog):
    """ Progress dialog shows progress bar for algorithm.
    """

    def __init__(self, iface):
        QDialog.__init__(self, iface.mainWindow())
        self.workerThread = None
        self.state = False
        self.resultStatus = None
        self.doReRun = False
        self.wasCanceled = False
        self.wasSuccessful = False
        self.savedProj = None
        self.result = None
        self.messageTxt = {
            'msg_optimierung': self.tr('Berechnung der optimalen Stuetzenpositionen...'),
            'msg_seillinie': self.tr('Berechnung der optimale Seillinie...')
        }
        
        # Build GUI Elements
        self.setWindowTitle(self.tr("SEILAPLAN wird ausgefuehrt"))
        self.resize(500, 100)
        self.container = QVBoxLayout()
        self.progressBar = QProgressBar(self)
        self.progressBar.setMinimumWidth(500)
        self.statusLabel = QLabel(self)
        self.hbox = QHBoxLayout()
        self.cancelButton = QDialogButtonBox()
        self.closeButton = QDialogButtonBox()
        self.resultLabel = QLabel(self)
        self.resultLabel.setMaximumWidth(500)
        self.resultLabel.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding))
        self.resultLabel.setWordWrap(True)
        spacer1 = QSpacerItem(20, 20, QSizePolicy.Fixed,
                              QSizePolicy.Fixed)
        self.rerunButton = QPushButton(self.tr("zurueck zum Startfenster"))
        self.rerunButton.setVisible(False)
        spacer2 = QSpacerItem(40, 20, QSizePolicy.Expanding,
                             QSizePolicy.Minimum)
        self.cancelButton.setStandardButtons(QDialogButtonBox.Cancel)
        self.cancelButton.button(QDialogButtonBox.Cancel).setText(self.tr("Abbrechen"))
        self.cancelButton.clicked.connect(self.onAbort)
        self.closeButton.setStandardButtons(QDialogButtonBox.Close)
        self.closeButton.button(QDialogButtonBox.Close).setText(self.tr("Schliessen"))
        self.closeButton.clicked.connect(self.onClose)
        self.hbox.addWidget(self.rerunButton)
        self.hbox.addItem(spacer2)
        self.hbox.addWidget(self.cancelButton)
        self.hbox.setAlignment(self.cancelButton, Qt.AlignHCenter)
        self.hbox.addWidget(self.closeButton)
        self.hbox.setAlignment(self.closeButton, Qt.AlignHCenter)
        self.closeButton.hide()
        
        self.container.addWidget(self.progressBar)
        self.container.addWidget(self.statusLabel)
        self.container.addWidget(self.resultLabel)
        self.container.addItem(spacer1)
        self.container.addLayout(self.hbox)
        self.container.setSizeConstraint(QLayout.SetFixedSize)
        self.setLayout(self.container)

    # noinspection PyMethodMayBeStatic
    def tr(self, message, **kwargs):
        """Get the translation for a string using Qt translation API.
        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString

        Parameters
        ----------
        **kwargs
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate(type(self).__name__, message)
        
    def setThread(self, workerThread):
        self.workerThread = workerThread
        self.connectThreadSignals()
    
    def connectThreadSignals(self):
        # Connect signals of thread
        self.workerThread.sig_jobEnded.connect(self.jobEnded)
        self.workerThread.sig_jobError.connect(self.onError)
        self.workerThread.sig_value.connect(self.valueFromThread)
        self.workerThread.sig_range.connect(self.rangeFromThread)
        self.workerThread.sig_text.connect(self.textFromThread)
        self.workerThread.sig_result.connect(self.resultFromThread)
        self.rerunButton.clicked.connect(self.onRerun)
        
    def run(self):
        # Show modal dialog window (QGIS is still responsive)
        self.show()
        # start event loop
        self.exec()
    
    def jobEnded(self, success):
        self.setWindowTitle("SEILAPLAN")
        if success:
            self.progressBar.setValue(self.progressBar.maximum())
            self.wasSuccessful = True
            # Close progress dialog so that adjustment window can be opened
            self.close()
        else:  # If there was an abort by the user
            self.statusLabel.setText(self.tr("Berechnungen abgebrochen."))
            self.progressBar.setValue(self.progressBar.minimum())
            self.finallyDo()
    
    def valueFromThread(self, value):
        self.progressBar.setValue(int(value))
    
    def rangeFromThread(self, range_vals):
        self.progressBar.setRange(int(round(range_vals[0])), int(round(range_vals[1])))
    
    def maxFromThread(self, max):
        self.progressBar.setValue(self.progressBar.maximum())
    
    def textFromThread(self, message):
        self.statusLabel.setText(self.messageTxt[message])
    
    def resultFromThread(self, resultStatus):
        self.resultStatus = resultStatus
        # resultStatus:
        #   1 = Optimization successful
        #   2 = Cable takes off from support
        #   3 = Optimization partially successful
    
    def onAbort(self):
        self.setWindowTitle('SEILAPLAN')
        self.statusLabel.setText(self.tr(
            'Laufender Prozess wird abgebrochen...'))
        self.workerThread.cancel()  # Terminates process cleanly
        self.wasCanceled = True
    
    def onError(self, exception_string):
        self.setWindowTitle(self.tr('SEILAPLAN: Berechnung fehlgeschlagen'))
        self.statusLabel.setText(self.tr('Ein Fehler ist aufgetreten:'))
        self.resultLabel.setText(self.tr(exception_string))
        self.resultLabel.setHidden(False)
        self.progressBar.setValue(self.progressBar.minimum())
        self.setLayout(self.container)
        self.finallyDo()
    
    def onRerun(self):
        self.doReRun = True
        self.onClose()
    
    def finallyDo(self):
        self.rerunButton.setVisible(True)
        self.cancelButton.hide()
        self.closeButton.show()
    
    def onClose(self):
        self.close()
    def upload_data(self):
        if self.check_login():
            if self.local_data_sources.count() == 0:
                return

            if self.db_connections.count() == 0:
                QMessageBox.warning(self, self.tr("No database available"), self.tr("Please create a database in the 'Account' tab."))
                return

            if not self.ui.cbUploadDatabase.currentIndex() >= 0:
                QMessageBox.warning(self, self.tr("No database selected"), self.tr("Please select a database to upload data."))
                return

            db_name = self.ui.cbUploadDatabase.currentText()

            if not self.db_connections.isPortOpen(db_name):
                uri = self.db_connections.cloud_layer_uri(db_name, "", "")
                host = str(uri.host())
                port = uri.port()
                QMessageBox.critical(self, self.tr("Network Error"),
                                     self.tr("Could not connect to database server ({0}) on port {1}. Please contact your system administrator or internet provider to open port {1} in the firewall".format(host, port)))
                return

            # disable update of local data sources during upload, as there are
            # temporary layers added and removed
            self.do_update_local_data_sources = False
            self.statusBar().showMessage(self.tr("Uploading data..."))
            self.setCursor(Qt.WaitCursor)
            self.ui.btnUploadData.hide()
            self.ui.spinner.start()
            self.ui.progressWidget.show()

            # Map<data_source, {table: table, layers: layers}>
            data_sources_items = {}
            for row in range(0, self.ui.tblLocalLayers.rowCount()):
                data_source = unicode(
                    self.ui.tblLocalLayers.item(
                        row, self.COLUMN_DATA_SOURCE).text())
                layers = self.local_data_sources.layers(data_source)
                if layers is not None:
                    table_name = unicode(
                        self.ui.tblLocalLayers.item(
                            row, self.COLUMN_TABLE_NAME).text())
                    data_sources_items[data_source] = {
                        u'table': unicode(table_name), u'layers': layers}

            login_info = self.api.check_login(version_info=self._version_info())
            try:            
                self.maxSize = login_info['max_storage']
                self.maxDBs = login_info['max_dbs']
            except:
                self.maxSize = 50
                self.maxDBs = 5

            try:
                self.data_upload.upload(self.db_connections.db(unicode(db_name)), data_sources_items, unicode(self.maxSize))
                upload_ok = True
            except Exception as e:
                ErrorReportDialog(self.tr("Upload errors occurred"), self.tr("Upload errors occurred. Not all data could be uploaded."), str(e) + "\n" + traceback.format_exc(), self.user, self).exec_()
                upload_ok = False

            self.ui.spinner.stop()
            self.ui.progressWidget.hide()
            self.ui.btnUploadData.show()
            self.unsetCursor()
            self.statusBar().showMessage("")
            # Refresh local layers
            self.do_update_local_data_sources = True
            self.update_local_layers()
            # Refresh used space after upload
            self.db_size(self.db_connections)

            if upload_ok:
                # Show save project dialog
                save_dialog = QDialog(self)
                save_dialog.setWindowTitle(self.tr("Save Project"))
                save_dialog.setLayout(QVBoxLayout())
                header = QWidget()
                header.setLayout(QVBoxLayout())
                label = QLabel(self.tr("Upload complete. The local layers in the project were replaced with the layers uploaded to the qgiscloud database."))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                label = QLabel(self.tr("Choose were to save the modified project:"))
                label.setWordWrap(True)
                header.layout().addWidget(label)
                save_dialog.layout().setContentsMargins(0, 0, 0, 0)
                save_dialog.layout().addWidget(header)
                initialPath = QgsProject.instance().fileName()
                if not initialPath:
                    initialPath = QSettings().value("/UI/lastProjectDir", ".")
                fd = QFileDialog(None, self.tr("Save Project"), initialPath, "%s (*.qgz *.qgs)" % self.tr("QGIS Project Files"))
                fd.setParent(save_dialog, Qt.Widget)
                fd.setOption(QFileDialog.DontUseNativeDialog)
                fd.setAcceptMode(QFileDialog.AcceptSave)
                save_dialog.layout().addWidget(fd)
                header.layout().setContentsMargins(fd.layout().contentsMargins())
                fd.accepted.connect(save_dialog.accept)
                fd.rejected.connect(save_dialog.reject)
                if save_dialog.exec_() == QDialog.Accepted:
                    files = list(fd.selectedFiles())
                    if files:
                        QgsProject.instance().setFileName(files[0])
                        self.iface.actionSaveProject().trigger()

                # Switch to map tab
                self.ui.tabWidget.setCurrentWidget(self.ui.mapTab)
Esempio n. 24
0
class FieldMappingDialog(QDialog, FORM_CLASS):

    """Dialog implementation class for the InaSAFE field mapping tool."""

    def __init__(self, parent=None, iface=None, setting=None):
        """Constructor."""
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self.setWindowTitle(self.tr('InaSAFE Field Mapping Tool'))
        icon = resources_path('img', 'icons', 'show-mapping-tool.svg')
        self.setWindowIcon(QIcon(icon))
        self.parent = parent
        self.iface = iface
        if setting is None:
            setting = QSettings()
        self.setting = setting

        self.keyword_io = KeywordIO()

        self.layer = None
        self.metadata = {}

        self.layer_input_layout = QHBoxLayout()
        self.layer_label = QLabel(tr('Layer'))
        self.layer_combo_box = QgsMapLayerComboBox()
        # Filter only for Polygon and Point
        self.layer_combo_box.setFilters(
            QgsMapLayerProxyModel.PolygonLayer
            | QgsMapLayerProxyModel.PointLayer)
        # Filter out a layer that don't have layer groups
        excepted_layers = []
        for i in range(self.layer_combo_box.count()):
            layer = self.layer_combo_box.layer(i)
            try:
                keywords = self.keyword_io.read_keywords(layer)
            except (KeywordNotFoundError, NoKeywordsFoundError):
                excepted_layers.append(layer)
                continue
            layer_purpose = keywords.get('layer_purpose')
            if not layer_purpose:
                excepted_layers.append(layer)
                continue
            if layer_purpose == layer_purpose_exposure['key']:
                layer_subcategory = keywords.get('exposure')
            elif layer_purpose == layer_purpose_hazard['key']:
                layer_subcategory = keywords.get('hazard')
            else:
                layer_subcategory = None

            field_groups = get_field_groups(layer_purpose, layer_subcategory)
            if len(field_groups) == 0:
                excepted_layers.append(layer)
                continue
        self.layer_combo_box.setExceptedLayerList(excepted_layers)

        # Select the active layer.
        if self.iface.activeLayer():
            found = self.layer_combo_box.findText(
                self.iface.activeLayer().name())
            if found > -1:
                self.layer_combo_box.setLayer(self.iface.activeLayer())

        self.field_mapping_widget = None
        self.main_stacked_widget.setCurrentIndex(1)

        # Input
        self.layer_input_layout.addWidget(self.layer_label)
        self.layer_input_layout.addWidget(self.layer_combo_box)

        self.header_label = QLabel()
        self.header_label.setWordWrap(True)
        self.main_layout.addWidget(self.header_label)
        self.main_layout.addLayout(self.layer_input_layout)

        # Signal
        self.layer_combo_box.layerChanged.connect(self.set_layer)

        if self.layer_combo_box.currentLayer():
            self.set_layer(self.layer_combo_box.currentLayer())

        # Set up things for context help
        self.help_button = self.button_box.button(QDialogButtonBox.Help)
        # Allow toggling the help button
        self.help_button.setCheckable(True)
        self.help_button.toggled.connect(self.help_toggled)

        # Set up things for ok button
        self.ok_button = self.button_box.button(QDialogButtonBox.Ok)
        self.ok_button.clicked.connect(self.accept)

        # Set up things for cancel button
        self.cancel_button = self.button_box.button(QDialogButtonBox.Cancel)
        self.cancel_button.clicked.connect(self.reject)

    def set_layer(self, layer=None, keywords=None):
        """Set layer and update UI accordingly.

        :param layer: A QgsVectorLayer.
        :type layer: QgsVectorLayer

        :param keywords: Keywords for the layer.
        :type keywords: dict, None
        """
        if self.field_mapping_widget is not None:
            self.field_mapping_widget.setParent(None)
            self.field_mapping_widget.close()
            self.field_mapping_widget.deleteLater()
            self.main_layout.removeWidget(self.field_mapping_widget)
            self.field_mapping_widget = None

        if layer:
            self.layer = layer
        else:
            self.layer = self.layer_combo_box.currentLayer()
        if not self.layer:
            return

        if keywords is not None:
            self.metadata = keywords
        else:
            # Always read from metadata file.
            try:
                self.metadata = self.keyword_io.read_keywords(self.layer)
            except (
                    NoKeywordsFoundError,
                    KeywordNotFoundError,
                    MetadataReadError) as e:
                raise e
        if 'inasafe_default_values' not in self.metadata:
            self.metadata['inasafe_default_values'] = {}
        if 'inasafe_fields' not in self.metadata:
            self.metadata['inasafe_fields'] = {}
        self.field_mapping_widget = FieldMappingWidget(
            parent=self, iface=self.iface)
        self.field_mapping_widget.set_layer(self.layer, self.metadata)
        self.field_mapping_widget.show()
        self.main_layout.addWidget(self.field_mapping_widget)

        # Set header label
        group_names = [
            self.field_mapping_widget.tabText(i) for i in range(
                self.field_mapping_widget.count())]
        if len(group_names) == 0:
            header_text = tr(
                'There is no field group for this layer. Please select '
                'another layer.')
            self.header_label.setText(header_text)
            return
        elif len(group_names) == 1:
            pretty_group_name = group_names[0]
        elif len(group_names) == 2:
            pretty_group_name = group_names[0] + tr(' and ') + group_names[1]
        else:
            pretty_group_name = ', '.join(group_names[:-1])
            pretty_group_name += tr(', and {0}').format(group_names[-1])
        header_text = tr(
            'Please fill the information for every tab to determine the '
            'attribute for {0} group.').format(pretty_group_name)
        self.header_label.setText(header_text)

    @pyqtSlot(bool)  # prevents actions being handled twice
    def help_toggled(self, flag):
        """Show or hide the help tab in the stacked widget.

        .. versionadded: 3.2.1

        :param flag: Flag indicating whether help should be shown or hidden.
        :type flag: bool
        """
        if flag:
            self.help_button.setText(self.tr('Hide Help'))
            self.show_help()
        else:
            self.help_button.setText(self.tr('Show Help'))
            self.hide_help()

    def hide_help(self):
        """Hide the usage info from the user.

        .. versionadded: 3.2.1
        """
        self.main_stacked_widget.setCurrentIndex(1)

    def show_help(self):
        """Show usage info to the user."""
        # Read the header and footer html snippets
        self.main_stacked_widget.setCurrentIndex(0)
        header = html_header()
        footer = html_footer()

        string = header

        message = field_mapping_help()

        string += message.to_html()
        string += footer

        self.help_web_view.setHtml(string)

    def save_metadata(self):
        """Save metadata based on the field mapping state."""
        metadata = self.field_mapping_widget.get_field_mapping()
        for key, value in list(metadata['fields'].items()):
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_default_values']:
                self.metadata['inasafe_default_values'].pop(key)
            if value is None or value == []:
                if key in self.metadata['inasafe_fields']:
                    self.metadata['inasafe_fields'].pop(key)
            else:
                self.metadata['inasafe_fields'][key] = value

        for key, value in list(metadata['values'].items()):
            # Delete the key if it's set to None
            if key in self.metadata['inasafe_fields']:
                self.metadata['inasafe_fields'].pop(key)
            if value is None:
                if key in self.metadata['inasafe_default_values']:
                    self.metadata['inasafe_default_values'].pop(key)
            else:
                self.metadata['inasafe_default_values'][key] = value

        # Save metadata
        try:
            self.keyword_io.write_keywords(
                layer=self.layer, keywords=self.metadata)
        except InaSAFEError as e:
            error_message = get_error_message(e)
            # noinspection PyCallByClass,PyTypeChecker,PyArgumentList
            QMessageBox.warning(
                self, self.tr('InaSAFE'),
                ((self.tr(
                    'An error was encountered when saving the following '
                    'keywords:\n %s') % error_message.to_html())))

        # Update setting fir recent value
        if self.metadata.get('inasafe_default_values'):
            for key, value in \
                    list(self.metadata['inasafe_default_values'].items()):
                set_inasafe_default_value_qsetting(
                    self.setting, key, RECENT, value)

    def accept(self):
        """Method invoked when OK button is clicked."""
        try:
            self.save_metadata()
        except InvalidValidationException as e:
            display_warning_message_box(
                self, tr('Invalid Field Mapping'), str(e))
            return
        super(FieldMappingDialog, self).accept()
Esempio n. 25
0
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))
Esempio n. 26
0
    def onAbout(self):
        self.about_dlg = QWidget()
        vlayout = QVBoxLayout()
        l = QLabel("""
        <h1>QGIS GML Application Schema Toolbox</h1>
        <h3>Version: {}</h3>
        <p>This plugin is a prototype aiming at experimenting with the manipulation of <b>Complex Features</b> streams.</p>
        <p>Two modes are available:
        <ul><li>A mode where the <b>initial XML hierarchical view</b> is preserved. In this mode, an XML instance
        is represented by a unique QGIS vector layer with a column that stores the XML subtree for each feature.
        Augmented tools are available to identify a feature or display the attribute table of the layer.</li>
        <li>A mode where the XML hierarchical data is first <b>converted to a relational database</b>.
        In this mode, the data is spread accross different QGIS layers. Links between tables are declared
        as QGIS relations and "relation reference" widgets. It then allows to use the standard QGIS attribute
        table (in "forms" mode) to navigate the relationel model.</li>
        </ul>
        <p>Custom Qt-based viewers can be run on XML elements of given types.</p>

        <p>Teams involved in the development of the current plugin:
        <ul>
        <li><a href="http://www.oslandia.com">Oslandia</a> (current version of the QGIS plugin, and first proof of concept)</li>
        <li><a href="http://www.spatialys.com">Spatialys</a> (GMLAS driver in OGR)</li>
        <li><a href="http://www.camptocamp.com">camptocamp</a> (former version of the plugin)</li>
        </ul>
        </p>
        <p>Funders involved:
        <ul>
        <li><a href="http://www.brgm.fr">BRGM</a></li>
        <li><a href="https://www.eea.europa.eu/">European Environment Agency</a> (Copernicus funding)</li>
        <li><b>The Association of Finnish Local and Regional Authorities</b> (through <a href="http://www.gispo.fi">Gispo.fi</a>)</li>
        </ul>
        </p>
        """.format(plugin_version()))
        l.setWordWrap(True)
        vlayout.addWidget(l)
        hlayout = QHBoxLayout()
        hlayout2 = QHBoxLayout()
        l2 = QLabel()
        l2.setPixmap(
            QPixmap(os.path.join(os.path.dirname(__file__),
                                 "logo_brgm.svg")).scaledToWidth(
                                     200, Qt.SmoothTransformation))
        l3 = QLabel()
        l3.setPixmap(
            QPixmap(os.path.join(os.path.dirname(__file__),
                                 "logo_eea.png")).scaledToWidth(
                                     200, Qt.SmoothTransformation))
        l4 = QLabel()
        l4.setPixmap(
            QPixmap(
                os.path.join(os.path.dirname(__file__),
                             "logo_oslandia.png")).scaledToWidth(
                                 150, Qt.SmoothTransformation))
        l5 = QLabel()
        l5.setPixmap(
            QPixmap(
                os.path.join(os.path.dirname(__file__),
                             "logo_spatialys.png")).scaledToWidth(
                                 100, Qt.SmoothTransformation))
        l6 = QLabel()
        l6.setPixmap(
            QPixmap(os.path.join(os.path.dirname(__file__),
                                 "logo_c2c.svg")).scaledToWidth(
                                     100, Qt.SmoothTransformation))
        hlayout.addWidget(l2)
        hlayout.addWidget(l3)
        vlayout.addLayout(hlayout)
        hlayout2.addWidget(l4)
        hlayout2.addWidget(l5)
        hlayout2.addWidget(l6)
        vlayout.addLayout(hlayout2)
        self.about_dlg.setLayout(vlayout)
        self.about_dlg.setWindowTitle(plugin_name())
        self.about_dlg.setWindowModality(Qt.WindowModal)
        self.about_dlg.show()
        self.about_dlg.resize(600, 800)
Esempio n. 27
0
class QmsSearchResultItemWidget(QWidget):
    def __init__(self,
                 geoservice,
                 image_ba,
                 parent=None,
                 extent_renderer=None):
        QWidget.__init__(self, parent)

        self.extent_renderer = extent_renderer

        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(5, 10, 5, 10)
        self.setLayout(self.layout)

        self.service_icon = QLabel(self)
        self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.service_icon.resize(24, 24)

        qimg = QImage.fromData(image_ba)
        pixmap = QPixmap.fromImage(qimg)
        self.service_icon.setPixmap(pixmap)
        self.layout.addWidget(self.service_icon)

        self.service_desc_layout = QGridLayout(self)
        self.service_desc_layout.setSpacing(0)
        self.layout.addLayout(self.service_desc_layout)

        self.service_name = QLabel(self)
        self.service_name.setTextFormat(Qt.RichText)
        self.service_name.setWordWrap(True)
        self.service_name.setText(u"   <strong> {} </strong>".format(
            geoservice.get('name', u"")))
        self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3)

        self.service_type = QLabel(self)
        self.service_type.setTextFormat(Qt.RichText)
        self.service_type.setWordWrap(True)
        self.service_type.setText(geoservice.get('type', u"").upper() + " ")
        self.service_desc_layout.addWidget(self.service_type, 1, 0)

        self.service_deteils = QLabel(self)
        self.service_deteils.setTextFormat(Qt.RichText)
        self.service_deteils.setWordWrap(True)
        self.service_deteils.setOpenExternalLinks(True)
        self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format(
            Client().geoservice_info_url(geoservice.get('id', u"")),
            self.tr('details')))
        self.service_desc_layout.addWidget(self.service_deteils, 1, 1)

        self.service_report = QLabel(self)
        self.service_report.setTextFormat(Qt.RichText)
        self.service_report.setWordWrap(True)
        self.service_report.setOpenExternalLinks(True)
        self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format(
            Client().geoservice_report_url(geoservice.get('id', u"")),
            self.tr('report a problem')))
        self.service_desc_layout.addWidget(self.service_report, 1, 2)
        self.service_desc_layout.setColumnStretch(2, 1)

        self.status_label = QLabel(self)
        self.status_label.setTextFormat(Qt.RichText)
        self.status_label.setText(u'\u2022')

        status = geoservice.get('cumulative_status', u'')
        if status == 'works':
            self.status_label.setStyleSheet("color: green; font-size: 30px")
        if status == 'failed':
            self.status_label.setStyleSheet("color: red; font-size: 30px")
        if status == 'problematic':
            self.status_label.setStyleSheet("color: yellow; font-size: 30px")
        self.layout.addWidget(self.status_label)

        self.addButton = QToolButton()
        self.addButton.setText(self.tr("Add"))
        self.addButton.clicked.connect(self.addToMap)
        self.layout.addWidget(self.addButton)

        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)

        self.geoservice = geoservice
        self.image_ba = image_ba

    def addToMap(self):
        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            client = Client()
            client.set_proxy(*QGISSettings.get_qgis_proxy())
            geoservice_info = client.get_geoservice_info(self.geoservice)
            ds = DataSourceSerializer.read_from_json(geoservice_info)
            add_layer_to_map(ds)

            CachedServices().add_service(self.geoservice, self.image_ba)
        except Exception as ex:
            plPrint(unicode(ex))
            pass
        finally:
            QApplication.restoreOverrideCursor()

    def mouseDoubleClickEvent(self, event):
        self.addToMap()

    def enterEvent(self, event):
        extent = self.geoservice.get('extent', None)
        if self.extent_renderer and extent:
            if ';' in extent:
                extent = extent.split(';')[1]
            geom = QgsGeometry.fromWkt(extent)
            self.extent_renderer.show_feature(geom)

    def leaveEvent(self, event):
        if self.extent_renderer:
            self.extent_renderer.clear_feature()
Esempio n. 28
0
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))
Esempio n. 29
0
class MutantWidget(QWidget, Ui_Widget):
    def __init__(self, iface):
        self.hasqwt = has_qwt
        self.hasmpl = has_mpl
        self.haspqg = has_pyqtgraph
        self.layerMap = dict()
        self.statsChecked = False
        self.ymin = 0
        self.ymax = 365
        self.isActive = False
        self.mt_enabled = False

        # Statistics (>=1.9)
        self.statsSampleSize = 2500000
        self.stats = {}  # stats per layer

        self.layersSelected = []
        self.layerBands = dict()

        self.iface = iface
        self.canvas = self.iface.mapCanvas()

        # self.legend = self.iface.legendInterface()
        self.legend = QgsProject.instance().layerTreeRoot()
        self.logger = logging.getLogger('.'.join(
            (__name__, self.__class__.__name__)))

        QWidget.__init__(self)
        self.setupUi(self)
        self.tabWidget.setEnabled(False)
        self.plotOnMove.setChecked(QSettings().value(
            'plugins/mutant/mouseClick', False, type=bool))

        self.leYMin.setText(str(self.ymin))
        self.leYMax.setText(str(self.ymax))

        self.tracker = TimeTracker(self, self.canvas)
        self.filter = ApplyFilter(self, self.canvas)
        if has_mpl:
            self.mpl_cust = MplSettings(self, self.canvas)

        # self.setupUi_plot()
        # don't setup plot until Graph(1) tab is clicked - workaround for bug
        # #7450
        # qgis will still crash in some cases, but at least the tool can be
        # used in Table mode

        self.qwtPlot = None
        self.mplPlot = None
        self.mplLine = None

        self.plotLibSelector.currentIndexChanged.connect(self.change_plot)
        self.tabWidget.currentChanged.connect(self.tabWidgetChanged)
        self.layerSelection.currentIndexChanged.connect(self.update_layers)
        self.bandSelection.currentIndexChanged.connect(self.update_layers)
        self.selectionTable.cellChanged.connect(self.layerSelected)
        self.enableMTAnalysesCheckBox.toggled.connect(
            self.on_mt_analysis_toggled)
        self.selectionStringLineEdit.textChanged.connect(self.update_layers)
        self.yAutoCheckBox.toggled.connect(self.y_auto_toggle)

        self.toggleMutant.toggled.connect(self.catch_errors)

        self.exportPushButton.clicked.connect(self.export_values)
        # TODO Get Export from graph values
        # self.exportPushButton_2.clicked.connect(self.xxxx)

        self.registry = QgsProject.instance()
        self.registry.layersAdded.connect(self.catch_errors)
        self.registry.layersRemoved.connect(self.catch_errors)
        self.setupUi_plot()

    def catch_errors(self):
        if self.toggleMutant.isChecked():
            layers = self.activeRasterLayers()
            if len(layers) == 0:
                if self.canvas.layerCount() > 0:
                    text = self.tr("Mutant: No valid layers to display - "
                                   "add Rasterlayers")
                    self.pop_messagebar(text)
                    self.changeActive(False)
                else:
                    text = self.tr("Mutant: No valid layers to display")
                    self.pop_messagebar(text)
                    self.changeActive(False)
                self.values = []
                return
            else:
                return
        else:
            return

    def y_auto_toggle(self, state):
        # User has toggled automatic (default) y min/max values
        if state == 1:
            self.leYMin.setEnabled(False)
            self.leYMax.setEnabled(False)
            self.leYMin.setText(str(self.ymin))
            self.leYMax.setText(str(self.ymax))
        else:
            self.leYMin.setEnabled(True)
            self.leYMax.setEnabled(True)

    def pop_messagebar(self, text, d_time=5):
        if d_time == 0:
            self.iface.messageBar().pushWidget(
                self.iface.messageBar().createMessage(text), Qgis.Warning)
        else:
            self.iface.messageBar().pushWidget(
                self.iface.messageBar().createMessage(text), Qgis.Warning,
                d_time)

    def setupUi_plot(self):
        # plot
        self.plotLibSelector.setVisible(False)
        self.enableStatistics.setVisible(False)
        # stats by default because estimated are fast
        self.enableStatistics.setChecked(True)

        plot_count = 0
        self.mplLine = None  # make sure to invalidate when layers change

        if self.hasqwt:  # Page 2 - qwt
            self.plotLibSelector.addItem('Qwt')
            plot_count += 1
            # Setup Qwt Plot Area in Widget
            self.qwtPlot = QwtPlot(self.stackedWidget)
            self.qwtPlot.setAutoFillBackground(False)
            self.qwtPlot.setObjectName("qwtPlot")
            self.curve = QwtPlotCurve()
            self.curve.setSymbol(
                QwtSymbol(QwtSymbol.Ellipse, QBrush(Qt.white), QPen(Qt.red, 2),
                          QSize(9, 9)))
            self.curve.attach(self.qwtPlot)

            # Size Policy ???
            sizePolicy = QSizePolicy(QSizePolicy.Expanding,
                                     QSizePolicy.Expanding)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            sizePolicy.setHeightForWidth(
                self.qwtPlot.sizePolicy().hasHeightForWidth())
            self.qwtPlot.setSizePolicy(sizePolicy)
            # Size Policy ???

            self.qwtPlot.updateGeometry()
            self.stackedWidget.addWidget(self.qwtPlot)
            self.qwt_widgetnumber = self.stackedWidget.indexOf(self.qwtPlot)

        if self.hasmpl:  # Page 3 -  setup matplotlib
            self.plotLibSelector.addItem('matplotlib')
            # If matplotlib is the only one
            self.toggleInterpolation.setEnabled(True)
            self.toggleInterpolation.setVisible(True)
            plot_count += 1
            self.mplBackground = None
            # http://www.scipy.org/Cookbook/Matplotlib/Animations
            self.mplFig = plt.Figure(facecolor='w',
                                     edgecolor='g',
                                     linewidth=0.0)

            self.mpl_subplot = self.mplFig.add_subplot(111)
            self.pltCanvas = FigureCanvasQTAgg(self.mplFig)
            self.pltCanvas.setParent(self.stackedWidget)
            self.pltCanvas.setAutoFillBackground(False)
            self.pltCanvas.setObjectName("mplPlot")
            self.mplPlot = self.pltCanvas
            self.mplPlot.updateGeometry()
            self.stackedWidget.addWidget(self.mplPlot)
            self.mpl_widgetnumber = self.stackedWidget.indexOf(self.mplPlot)

        if self.haspqg:  # Page 3 - setup PyQtGraph
            self.plotLibSelector.addItem('PyQtGraph')
            plot_count += 1
            # Setup PyQtGraph stuff
            pg.setConfigOption('background', 'w')
            pg.setConfigOption('foreground', 'k')
            self.pqg_axis = DateTimeAxis(orientation='bottom')
            self.pqg_plot_widget = pg.PlotWidget(
                parent=self.stackedWidget, axisItems={'bottom': self.pqg_axis})
            self.pqg_plot_item = self.pqg_plot_widget.getPlotItem()
            self.pqg_plot_widget.updateGeometry()
            self.stackedWidget.addWidget(self.pqg_plot_widget)
            self.pqg_widgetnumber = self.stackedWidget.indexOf(
                self.pqg_plot_widget)
            # on zoom change do:
            self.pqg_plot_item.sigXRangeChanged.connect(self.refresh_ticks)

        if plot_count > 1:
            self.plotLibSelector.setEnabled(True)
            self.plotLibSelector.setVisible(True)
            self.plotLibSelector.setCurrentIndex(0)
            if self.hasqwt:
                self.plotLibSelector.setCurrentIndex(self.qwt_widgetnumber)
            elif self.hasmpl:
                self.plotLibSelector.setCurrentIndex(self.mpl_widgetnumber)
            else:
                self.plotLibSelector.setCurrentIndex(self.pqg_widgetnumber)
            self.change_plot()
        elif plot_count == 1:
            self.plotLibSelector.setCurrentIndex(0)
            self.change_plot()
        else:  # can only be 0 if nothing else matched
            message_text = "Mutant cannot find any graphiclibrary for " \
                           "creating plots. Please install either Qwt >= 5.0 " \
                           ",matplotlib >= 1.0 or PyQtGraph >= 0.9.8!"
            self.plot_message = QLabel(message_text)
            self.plot_message.setWordWrap(True)
            self.stackedWidget.addWidget(self.plot_message)
            self.pop_messagebar(message_text)

    def change_plot(self):
        if self.stackedWidget.count() > 1:
            if self.plotLibSelector.currentText() == 'Qwt':
                self.stackedWidget.setCurrentIndex(self.qwt_widgetnumber)
                self.toggleInterpolation.setDisabled(True)
                self.toggleInterpolation.setVisible(False)
            elif self.plotLibSelector.currentText() == 'matplotlib':
                self.stackedWidget.setCurrentIndex(self.mpl_widgetnumber)
                self.toggleInterpolation.setEnabled(True)
                self.toggleInterpolation.setVisible(True)
                self.mpl_subplot.clear()
            elif self.plotLibSelector.currentText() == 'PyQtGraph':
                self.stackedWidget.setCurrentIndex(self.pqg_widgetnumber)
                self.toggleInterpolation.setDisabled(True)
                self.toggleInterpolation.setVisible(False)
                self.pqg_plot_widget.clear()
        elif self.stackedWidget.count() == 1:
            self.stackedWidget.setCurrentIndex(0)
        else:
            self.stackedWidget.setCurrentIndex(-1)

    def keyPressEvent(self, e):
        if (e.modifiers() == Qt.ControlModifier
                or e.modifiers() == Qt.MetaModifier) and e.key() == Qt.Key_C:
            items = ''
            for rec in range(self.valueTable.rowCount()):
                items += '"' + self.valueTable.item(
                    rec, 0).text() + '",' + self.valueTable.item(
                        rec, 1).text() + "\n"
            if not items == '':
                clipboard = QApplication.clipboard()
                clipboard.setText(items)
        else:
            QWidget.keyPressEvent(self, e)

    def changeActive(self, active, gui=True):
        if self.isActive == active:
            return
        self.isActive = active

        if active:
            self.toggleMutant.setCheckState(Qt.Checked)
            self.canvas.layersChanged.connect(self.invalidatePlot)
            if not self.plotOnMove.isChecked():
                self.canvas.xyCoordinates.connect(self.printValue)
        else:
            self.toggleMutant.setCheckState(Qt.Unchecked)
            self.canvas.layersChanged.disconnect(self.invalidatePlot)
            if self.plotOnMove.isChecked():
                self.canvas.xyCoordinates.disconnect(self.printValue)

        if gui:
            self.tabWidget.setEnabled(active)
            if active:
                self.labelStatus.setText(self.tr("Mutant is enabled!"))
                # FIXME: Only on Options Tab?
                if self.tabWidget.currentIndex() == 2:
                    self.update_layers()
            else:
                self.labelStatus.setText(self.tr(""))
                # use this to clear plot when deactivated
                # self.values=[]
                # self.showValues()

    def activeRasterLayers(self, index=None):
        layers = []
        allLayers = []

        if not index:
            index = self.layerSelection.currentIndex()
        if index == 0:  # visible layers
            allLayers = self.canvas.layers()
        elif index == 1 or index == 3:  # All layers | by selection string
            allLayers = [ltl.layer() for ltl in self.legend.findLayers()]
        elif index == 2:  # Manual selection
            for layer in [ltl.layer() for ltl in self.legend.findLayers()]:
                if layer.id() in self.layersSelected:
                    allLayers.append(layer)

        for layer in allLayers:

            if index == 3:  # by selection string
                # Check if the layer name matches our filter and skip it if it
                # doesn't
                if not self.name_matches_filter(layer.name()):
                    continue

            if layer is not None and layer.isValid() and \
                    layer.type() == QgsMapLayer.RasterLayer and \
                    layer.dataProvider() and \
                    (layer.dataProvider().capabilities() & QgsRasterDataProvider.IdentifyValue):
                layers.append(layer)

        return layers

    def activeBandsForRaster(self, layer):
        activeBands = []

        if self.bandSelection.currentIndex() == 1 and layer.renderer():
            activeBands = layer.renderer().usesBands()
        elif self.bandSelection.currentIndex() == 2:
            if layer.bandCount() == 1:
                activeBands = [1]
            else:
                activeBands = self.layerBands[layer.id()] if (
                    layer.id() in self.layerBands) else []
        else:
            activeBands = list(range(1, layer.bandCount() + 1))

        return activeBands

    def printValue(self, position):

        if debug > 0:
            print(position)

        if not position:
            return
        if self.tabWidget.currentIndex() == 2:
            return

        if debug > 0:
            print("%d active rasters, %d canvas layers" %
                  (len(self.activeRasterLayers()), self.canvas.layerCount()))

        layers = self.activeRasterLayers()

        self.labelStatus.setText(
            self.tr('Coordinate:') + ' (%f, %f)' %
            (position.x(), position.y()))

        need_extremum = (self.tabWidget.currentIndex() == 1
                         )  # if plot is shown
        # count the number of required rows and remember the raster layers
        nrow = 0
        rasterlayers = []
        layersWOStatistics = []

        for layer in layers:
            nrow += layer.bandCount()
            rasterlayers.append(layer)

            # check statistics for each band
            if need_extremum:
                for i in range(1, layer.bandCount() + 1):
                    has_stats = self.get_statistics(layer, i) is not None
                    if not layer.id() in self.layerMap and not has_stats \
                            and not layer in layersWOStatistics:
                        layersWOStatistics.append(layer)

        if layersWOStatistics and not self.statsChecked:
            self.calculateStatistics(layersWOStatistics)

        irow = 0
        self.values = []
        self.ymin = 1e38
        self.ymax = -1e38

        mapCanvasSrs = self.iface.mapCanvas().mapSettings().destinationCrs()

        # TODO - calculate the min/max values only once,
        # instead of every time!!!
        # And keep them in a dict() with key=layer.id()

        counter = 0
        for layer in rasterlayers:
            layer_name = str(layer.name())
            layer_srs = layer.crs()

            pos = position

            # if given no position, get dummy values
            if position is None:
                pos = QgsPoint(0, 0)
            # transform points if needed
            elif not mapCanvasSrs == layer_srs:
                srsTransform = QgsCoordinateTransform(mapCanvasSrs, layer_srs)
                try:
                    pos = srsTransform.transform(position)
                except QgsCsException as err:
                    continue

            if True:
                if not layer.dataProvider():
                    continue
                ident = None

                if position is not None:
                    canvas = self.iface.mapCanvas()

                    # first test if point is within map layer extent
                    # maintain same behaviour as in 1.8 and print out of extent
                    if not layer.dataProvider().extent().contains(pos):
                        ident = dict()
                        for iband in range(1, layer.bandCount() + 1):
                            ident[iband] = str(self.tr('out of extent'))
                    # we can only use context if layer is not projected
                    elif layer.dataProvider().crs() != \
                                    canvas.mapSettings().destinationCrs():
                        ident = layer.dataProvider().identify(
                            pos, QgsRaster.IdentifyFormatValue).results()
                    else:
                        extent = canvas.extent()
                        width = round(extent.width() /
                                      canvas.mapUnitsPerPixel())
                        height = round(extent.height() /
                                       canvas.mapUnitsPerPixel())
                        extent = canvas.mapSettings().mapToLayerCoordinates(
                            layer, extent)
                        ident = layer.dataProvider().identify(
                            pos, QgsRaster.IdentifyFormatValue,
                            canvas.extent(), width, height).results()
                    if not len(ident) > 0:
                        continue

                # if given no position, set values to 0
                if position is None and ident is not None and iter(
                        ident.keys()) is not None:
                    for key in ident.keys():
                        ident[key] = layer.dataProvider().noDataValue(key)

                # bands displayed depends on cbxBands (all / active / selected)
                activeBands = self.activeBandsForRaster(layer)

                for iband in activeBands:  # loop over the active bands
                    layer_name_with_band = layer_name
                    if ident is not None and len(ident) > 1:
                        layer_name_with_band += ' ' + layer.bandName(iband)

                    if not ident or iband not in ident:
                        bandvalue = "?"
                    else:
                        bandvalue = ident[iband]
                        if bandvalue is None:
                            bandvalue = "no data"

                    # different x-Axis depending on if we want to use time or
                    # not
                    if self.mt_enabled:
                        layer_time = self.tracker.get_time_for_layer(layer)

                        if layer_time is None:
                            continue
                        else:
                            # pyqtgraph enabled convert date to epoch
                            graphlib = self.plotLibSelector.currentText()

                            if graphlib == 'PyQtGraph':
                                layer_time = time.mktime(
                                    layer_time.timetuple())
                                # overwrite
                            tup = (layer_name_with_band, layer_time,
                                   str(bandvalue))
                    else:
                        tup = (layer_name_with_band, counter + 1,
                               str(bandvalue))

                    self.values.append(tup)

                    if need_extremum:
                        # estimated statistics
                        stats = self.get_statistics(layer, iband)
                        if stats:
                            self.ymin = min(self.ymin, stats.minimumValue)
                            self.ymax = max(self.ymax, stats.maximumValue)
                    counter += 1

        # Update the ymin, ymax line edits if required
        if self.yAutoCheckBox.isChecked():
            self.leYMin.setText(str(self.ymin))
            self.leYMax.setText(str(self.ymax))

        self.values.sort(key=operator.itemgetter(1))

        if len(self.values) == 0:
            self.labelStatus.setText(self.tr("No valid bands to display"))

        self.showValues(position)

    def showValues(self, position):
        if self.tabWidget.currentIndex() == 1:
            if len(self.values) == 0:
                # FIXME don't plot if there is no data to plot...
                return
            else:
                self.plot()
        else:
            self.printInTable(position)

    def export_values(self):
        path = QFileDialog.getSaveFileName(self, 'Save File', '', 'CSV(*.csv)')
        if path != "":
            with open(str(path), 'wb') as stream:
                writer = csv.writer(stream)
                for row in range(self.valueTable.rowCount()):
                    rowdata = []
                    for column in range(self.valueTable.columnCount()):
                        item = self.valueTable.item(row, column)
                        if item is not None:
                            rowdata.append(str(item.text()).encode('utf8'))
                        else:
                            rowdata.append('')
                    writer.writerow(rowdata)

    def calculateStatistics(self, layersWOStatistics):

        self.invalidatePlot(False)
        self.statsChecked = True

        layernames = []
        for layer in layersWOStatistics:
            if not layer.id() in self.layerMap:
                layernames.append(layer.name())

        if len(layernames) != 0:
            if not self.enableStatistics.isChecked():
                for layer in layersWOStatistics:
                    self.layerMap[layer.id()] = True
                return
        else:
            print('ERROR, no layers to get stats for')

        save_state = self.isActive
        self.changeActive(False, False)  # deactivate

        # calculate statistics
        for layer in layersWOStatistics:
            if not layer.id() in self.layerMap:
                self.layerMap[layer.id()] = True
                for i in range(1, layer.bandCount() + 1):
                    self.get_statistics(layer, i, True)

        if save_state:
            self.changeActive(True, False)  # activate if necessary

    # get cached statistics for layer and band or None if not calculated
    def get_statistics(self, layer, bandNo, force=False):
        if layer in self.stats:
            if bandNo in self.stats[layer]:
                return self.stats[layer][bandNo]
        else:
            self.stats[layer] = {}

        if force or \
                layer.dataProvider().hasStatistics(bandNo,
                                                   QgsRasterBandStats.Min | QgsRasterBandStats.Min,
                                                   QgsRectangle(),
                                                   self.statsSampleSize):
            self.stats[layer][bandNo] = \
                layer.dataProvider().bandStatistics(bandNo,
                                                    QgsRasterBandStats.Min | QgsRasterBandStats.Min,
                                                    QgsRectangle(),
                                                    self.statsSampleSize)
            return self.stats[layer][bandNo]
        return None

    def printInTable(self, position):
        self.valueTable.clearContents()
        # set table widget row count
        self.valueTable.setRowCount(len(self.values))
        posX = position.x()
        posY = position.y()
        irow = 0
        for layername, xval, value in self.values:

            if self.valueTable.item(irow, 0) is None:
                # create the item
                self.valueTable.setItem(irow, 0, QTableWidgetItem())
                self.valueTable.setItem(irow, 1, QTableWidgetItem())
                self.valueTable.setItem(irow, 2, QTableWidgetItem())
                self.valueTable.setItem(irow, 3, QTableWidgetItem())
                self.valueTable.setItem(irow, 4, QTableWidgetItem())

            self.valueTable.item(irow, 0).setText(layername)
            self.valueTable.item(irow, 3).setText(str(posX))
            self.valueTable.item(irow, 4).setText(str(posY))

            if self.mt_enabled:
                graphlib = self.plotLibSelector.currentText()
                if graphlib == 'PyQtGraph':
                    date = datetime.datetime.fromtimestamp(xval)
                    self.valueTable.item(irow, 2).setText(str(date))
                else:
                    self.valueTable.item(irow, 2).setText(str(xval))
            # else:
            # self.valueTable.item(irow, 2).setText('')

            if value == 'no data' or value == 'out of extent':
                self.valueTable.item(irow, 1).setText(value)
            else:
                value = float(value)
                if self.cbxDigits.isChecked():
                    try:
                        x = str(self.spinDigits.value())
                        y = "{:." + x + "f}"
                        value = y.format(value)
                    except ValueError:
                        pass
                self.valueTable.item(irow, 1).setData(Qt.EditRole, value)
            irow += 1

    def refresh_ticks(self):
        # At this point the X extent has been changed (e.g. zoom) and we need
        #  to redraw ticks and associated labels
        major_tick_times = []
        # define label width as minimum label distance readable
        label_width = 40

        # First determine what visible x range we are looking at
        view_min_x = self.pqg_plot_item.getViewBox().viewRange()[0][0]
        view_max_x = self.pqg_plot_item.getViewBox().viewRange()[0][1]
        min_date_axis = datetime.datetime.fromtimestamp(view_min_x)

        view_range = view_max_x - view_min_x

        # Determine the current width of the plot in px
        rect_bound = self.pqg_plot_item.viewGeometry()
        width = rect_bound.width()

        major_label_count = (width - label_width) // label_width

        major_label_spacing = view_range // (
            major_label_count * 3600.0 * 24 * 365.25)  # In major tick units

        min_tick_to_label_int = int(
            datetime.datetime.strftime(min_date_axis, '%Y')) + 1

        major_label_spacing_delta = view_range / major_label_count

        min_tick_to_label_stamp = (
            datetime.datetime(min_tick_to_label_int, 1, 1) -
            datetime.datetime(1970, 1, 1)).total_seconds()

        major_tick_times.append(
            (int(min_tick_to_label_stamp),
             str(
                 datetime.datetime.fromtimestamp(
                     min_tick_to_label_stamp).strftime('%Y'))))

        next_tick_to_label_int = int(
            (datetime.datetime(min_tick_to_label_int, 1, 1) -
             datetime.datetime(1970, 1, 1)).total_seconds())

        next_tick_to_label_stamp = min_tick_to_label_stamp

        while True:
            next_tick_to_label_int += int(major_label_spacing_delta)
            next_tick_to_label_stamp += major_label_spacing_delta

            if next_tick_to_label_int > int(view_max_x):
                break
            major_tick_times.append(
                (next_tick_to_label_int,
                 str(
                     datetime.datetime.fromtimestamp(
                         next_tick_to_label_stamp).strftime('%Y'))))
        # An experiment
        # ticks = [
        #      [(631152000.34, '1990'), (788918400, '1995')],
        #      [(662688000, '1991'),(694224000.46, '1992'),
        #       (725846400, '1993'), (757382400, '1994')]
        # ]
        self.pqg_axis.setTicks([major_tick_times])

    def plot(self):
        data_values = []
        x_values = []
        do_filter = self.toggleFilter.isChecked()
        do_interpolation = self.toggleInterpolation.isChecked()

        if self.hasqwt or self.hasmpl or self.haspqg:
            for layername, xval, value in self.values:
                x_values.append(xval)
                try:
                    data_values.append(float(value))
                except ValueError:
                    data_values.append(None)
                    # instead to not be plotted, be aware of min()
                    # calculation in plotting range = affects graphs (check
                    # there?
            if not data_values:
                data_values = [0]

        if self.yAutoCheckBox.isChecked():
            ymin = self.ymin
            ymax = self.ymax
        else:
            # Beware the user may not have entered a number
            try:
                ymin = float(self.leYMin.text())
                ymax = float(self.leYMax.text())
            except ValueError:
                message = 'Valuetool: Please enter Numbers!'
                self.pop_messagebar(message)
                return

        # Qwt Plot
        if self.hasqwt and (self.plotLibSelector.currentText() == 'Qwt'):
            self.qwtPlot.setAxisMaxMinor(QwtPlot.xBottom, 0)
            # self.qwtPlot.setAxisMaxMajor(QwtPlot.xBottom,0)
            self.qwtPlot.setAxisScale(QwtPlot.xBottom, 1, len(self.values))
            # self.qwtPlot.setAxisScale(QwtPlot.yLeft, self.ymin, self.ymax)
            self.qwtPlot.setAxisScale(QwtPlot.yLeft, ymin, ymax)
            try:
                qwtx, qwtydata = list(
                    zip(*[
                        x for x in zip(x_values, data_values)
                        if x[1] is not None
                    ]))
            except ValueError:
                return
            self.curve.setSamples(list(range(1, len(qwtydata) + 1)), qwtydata)
            self.qwtPlot.replot()
            self.qwtPlot.setVisible(len(qwtydata) > 0)

        # matplotlib Plot
        elif self.hasmpl and (self.plotLibSelector.currentText()
                              == 'matplotlib'):
            # don't clear to draw another row of data
            self.mpl_subplot.clear()
            self.mpl_cust.mpl_setup()
            # If Multi-temporal Analysis enabled set xAxis away from Standard
            # 1 to values to dates.
            # Plot code from here
            xv = np.asarray(x_values)
            dv = np.asarray(data_values)
            dvd = dv.astype(np.double)
            datav_mask = np.isfinite(dvd)

            if do_interpolation:
                xaxis = xv[datav_mask]
                yaxis = dvd[datav_mask]
            else:
                xaxis = x_values
                yaxis = data_values

            self.mpl_subplot.plot_date(xaxis,
                                       yaxis,
                                       linestyle='-',
                                       xdate=self.mt_enabled,
                                       ydate=False,
                                       marker='o',
                                       markersize=4,
                                       color='k',
                                       markerfacecolor='b',
                                       markeredgecolor='b')
            if self.mt_enabled:
                plt.xticks(rotation='vertical')
                self.mpl_cust.mpl_date_settings(x_values, ymin, ymax)
            else:
                self.mpl_cust.mpl_value_settings(x_values, ymin, ymax)

            if do_filter:
                derived_x, derived_y = self.filter.smooth(xaxis, yaxis)
                self.mpl_subplot.plot_date(derived_x,
                                           derived_y,
                                           linestyle='-',
                                           xdate=self.mt_enabled,
                                           ydate=False,
                                           marker='x',
                                           markersize=2,
                                           color='r',
                                           markerfacecolor='r',
                                           markeredgecolor='r')
            self.mplFig.canvas.draw()

        # PyQtGraph Plot
        elif self.haspqg and (self.plotLibSelector.currentText()
                              == 'PyQtGraph'):
            # clear on plot - don't clear if additional data should be added
            self.pqg_plot_widget.clear()  # clean canvas on call
            # self.pqg_plot_item.clear()  # clear item
            # self.pqg_plot_widget.scene().removeItem(legend)
            self.pqg_plot_item.setYRange(ymin, ymax)
            style_normal = Qt.SolidLine
            # Qt.DashLine, Qt.DotLine, Qt.DashDotLine, Qt.DashDotDotLine, Qt.CustomDashLine
            style_filter = Qt.SolidLine
            # filter None values out of input data
            try:
                pgxaxis, pgyaxis = list(
                    zip(*[
                        x for x in zip(x_values, data_values)
                        if x[1] is not None
                    ]))
            except ValueError:
                return
            self.pqg_plot_widget.plot(pgxaxis,
                                      pgyaxis,
                                      name='data',
                                      symbol='o',
                                      pen=pg.mkPen(color='k',
                                                   width=1,
                                                   style=style_normal))
            if do_filter:
                derived_x, derived_y = self.filter.smooth(pgxaxis, pgyaxis)
                self.pqg_plot_widget.plot(derived_x,
                                          derived_y,
                                          name='filter',
                                          symbol='x',
                                          pen=pg.mkPen(color='r',
                                                       width=1,
                                                       style=style_filter))

    def invalidatePlot(self, replot=True):
        if self.tabWidget.currentIndex() == 2:
            self.update_layers()
        if not self.isActive:
            return
        self.statsChecked = False
        if self.mplLine is not None:
            del self.mplLine
            self.mplLine = None
        # update empty plot
        if replot and self.tabWidget.currentIndex() == 1:
            # self.values=[]
            self.printValue(None)

    def resizeEvent(self, event):
        self.invalidatePlot()

    def tabWidgetChanged(self):
        if self.tabWidget.currentIndex() == 2:
            self.update_layers()

    def on_mt_analysis_toggled(self, new_state):
        if new_state == 1:
            self.mt_enabled = True
            if self.haspqg:
                self.pqg_axis.set_time_enabled(True)
            if self.hasqwt and self.plotLibSelector.currentText() == 'Qwt':
                message = 'Mutant: There is currently no support using Date ' \
                          'values while using the Qwt plotlibrary'
                self.pop_messagebar(message, 0)
            self.tracker.enable_selection()
            self.priorityLabel.setEnabled(True)
            self.extractionPriorityListWidget.setEnabled(True)
            self.patternLabel.setEnabled(True)
            self.patternLineEdit.setEnabled(True)
            self.writeMetaDataCheckBox.setEnabled(True)
            self.labelStatus.setText(
                self.tr("Multi-temporal analysis "
                        "enabled!"))
            self.cutFirst.setEnabled(True)
            self.dateLength.setEnabled(True)
            self.sampleLineEdit.setEnabled(True)
            self.sampleLabel.setEnabled(True)
            self.tracker.refresh_tracker()  # Only call when mt_enabled
        else:
            self.mt_enabled = False
            if self.haspqg:
                self.pqg_axis.set_time_enabled(False)
            self.priorityLabel.setEnabled(False)
            self.extractionPriorityListWidget.setEnabled(False)
            self.patternLabel.setEnabled(False)
            self.patternLineEdit.setEnabled(False)
            self.writeMetaDataCheckBox.setEnabled(False)
            self.labelStatus.setText(self.tr(""))
            self.cutFirst.setEnabled(False)
            self.dateLength.setEnabled(False)
            self.sampleLineEdit.setEnabled(False)
            self.sampleLabel.setEnabled(False)
            self.tracker.disable_selection()

    def name_matches_filter(self, name):
        selection_string = self.selectionStringLineEdit.text()
        return fnmatch.fnmatchcase(name, selection_string)

    # update active layers in table
    def update_layers(self):
        if self.tabWidget.currentIndex() != 2:
            return

        if self.layerSelection.currentIndex() == 3:  # by selection string
            self.selectionStringLineEdit.setEnabled(True)
        else:
            self.selectionStringLineEdit.setEnabled(False)

        if self.layerSelection.currentIndex() == 0:  # visible layers
            layers = self.activeRasterLayers(0)
        elif self.layerSelection.currentIndex() == 3:  # by selection string
            layers = self.activeRasterLayers(3)
        else:
            layers = self.activeRasterLayers(1)  # All layers

        self.selectionTable.blockSignals(True)
        self.selectionTable.clearContents()
        self.selectionTable.setRowCount(len(layers))
        self.selectionTable.horizontalHeader().resizeSection(0, 20)
        self.selectionTable.horizontalHeader().resizeSection(2, 20)

        j = 0
        for layer in layers:
            item = QTableWidgetItem()
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            if self.layerSelection.currentIndex() != 2:
                item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
                item.setCheckState(Qt.Checked)
            else:
                # manual selection
                if layer.id() in self.layersSelected:
                    item.setCheckState(Qt.Checked)
                else:
                    item.setCheckState(Qt.Unchecked)
            self.selectionTable.setItem(j, 0, item)
            item = QTableWidgetItem(layer.name())
            item.setData(Qt.UserRole, layer.id())
            self.selectionTable.setItem(j, 1, item)
            activeBands = self.activeBandsForRaster(layer)
            button = QToolButton()
            button.setIcon(QIcon(':/plugins/mutant/img/bands.jpg'))
            # button.setIconSize(QtCore.QSize(400, 400))
            button.setPopupMode(QToolButton.InstantPopup)
            group = QActionGroup(button)
            group.setExclusive(False)
            group.triggered.connect(self.bandSelected)
            if self.bandSelection.currentIndex(
            ) == 2 and layer.bandCount() > 1:
                menu = QMenu()
                menu.installEventFilter(self)

                for iband in range(1, layer.bandCount() + 1):
                    action = QAction(str(layer.bandName(iband)), group)
                    action.setData([layer.id(), iband, j, False])
                    action.setCheckable(True)
                    action.setChecked(iband in activeBands)
                    menu.addAction(action)
                if layer.bandCount() > 1:
                    action = QAction(str(self.tr("All")), group)
                    action.setData([layer.id(), -1, j, True])
                    action.setCheckable(False)
                    menu.addAction(action)
                    action = QAction(str(self.tr("None")), group)
                    action.setData([layer.id(), -1, j, False])
                    action.setCheckable(False)
                    menu.addAction(action)

                button.setMenu(menu)
            else:
                button.setEnabled(False)
            self.selectionTable.setCellWidget(j, 2, button)
            item = QTableWidgetItem(str(activeBands))
            item.setToolTip(str(activeBands))
            self.selectionTable.setItem(j, 3, item)
            j += 1

        self.selectionTable.blockSignals(False)

    # slot for when active layer selection has changed
    def layerSelected(self, row, column):
        if column != 0:
            return

        self.layersSelected = []
        for i in range(0, self.selectionTable.rowCount()):
            item = self.selectionTable.item(i, 0)
            layer_id = self.selectionTable.item(i, 1).data(Qt.UserRole)
            if item and item.checkState() == Qt.Checked:
                self.layersSelected.append(layer_id)
            elif layer_id in self.layersSelected:
                self.layersSelected.remove(layer_id)

    # slot for when active band selection has changed
    def bandSelected(self, action):
        layer_id = action.data()[0]
        layerBand = action.data()[1]
        j = action.data()[2]
        toggleAll = action.data()[3]
        activeBands = self.layerBands[layer_id] if (
            layer_id in self.layerBands) else []

        # special actions All/None
        if layerBand == -1:
            for layer in [ltl.layer() for ltl in self.legend.findLayers()]:
                if layer.id() == layer_id:
                    if toggleAll:
                        activeBands = list(range(1, layer.bandCount() + 1))
                    else:
                        activeBands = []
                    # toggle all band# actions
                    group = action.parent()
                    if group and not isinstance(group, QActionGroup):
                        group = None
                    if group:
                        group.blockSignals(True)
                        for a in group.actions():
                            if a.isCheckable():
                                a.setChecked(toggleAll)
                        group.blockSignals(False)

        # any Band# action
        else:
            if action.isChecked():
                activeBands.append(layerBand)
            else:
                if layerBand in activeBands:
                    activeBands.remove(layerBand)
            activeBands.sort()

        self.layerBands[layer_id] = activeBands

        # update UI
        item = QTableWidgetItem(str(activeBands))
        item.setToolTip(str(activeBands))
        self.selectionTable.setItem(j, 3, item)

    # event filter for band selection menu, do not close after toggling each
    # band
    def eventFilter(self, obj, event):
        if event.type() in [QEvent.MouseButtonRelease]:
            if isinstance(obj, QMenu):
                if obj.activeAction():
                    if not obj.activeAction().menu():
                        # if the selected action does not have a submenu eat the event, but trigger the function
                        obj.activeAction().trigger()
                        return True
        return super(MutantWidget, self).eventFilter(obj, event)

    def shouldPrintValues(self):
        return self.isVisible() and not self.visibleRegion().isEmpty() and \
               self.isActive and self.tabWidget.currentIndex() != 2

    def toolMoved(self, position):
        if self.shouldPrintValues() and not self.plotOnMove.isChecked():
            self.printValue(
                self.canvas.getCoordinateTransform().toMapCoordinates(
                    position))

    def toolPressed(self, position):
        if self.shouldPrintValues() and self.plotOnMove.isChecked():
            self.printValue(
                self.canvas.getCoordinateTransform().toMapCoordinates(
                    position))
    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 GroupSelectParameterWidget(GenericParameterWidget):
    """Widget class for Group Select Parameter."""
    def __init__(self, parameter, parent=None):
        """Constructor.

        :param parameter: A GroupSelectParameter object.
        :type parameter: GroupSelectParameter
        """
        QWidget.__init__(self, parent)
        self._parameter = parameter

        # Store spin box
        self.spin_boxes = {}

        # Create elements
        # Label (name)
        self.label = QLabel(self._parameter.name)

        # Layouts
        self.main_layout = QVBoxLayout()
        self.input_layout = QVBoxLayout()

        # _inner_input_layout must be filled with widget in the child class
        self.inner_input_layout = QVBoxLayout()

        self.radio_button_layout = QGridLayout()

        # Create radio button group
        self.input_button_group = QButtonGroup()

        # List widget
        self.list_widget = QListWidget()
        self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget.setDragDropMode(QAbstractItemView.DragDrop)
        self.list_widget.setDefaultDropAction(Qt.MoveAction)
        self.list_widget.setEnabled(False)
        self.list_widget.setSizePolicy(QSizePolicy.Maximum,
                                       QSizePolicy.Expanding)

        for i, key in enumerate(self._parameter.options):
            value = self._parameter.options[key]
            radio_button = QRadioButton(value.get('label'))
            self.radio_button_layout.addWidget(radio_button, i, 0)
            if value.get('type') == SINGLE_DYNAMIC:
                percentage_spin_box = PercentageSpinBox(self)
                self.radio_button_layout.addWidget(percentage_spin_box, i, 1)
                percentage_spin_box.setValue(value.get('value', 0))
                step = percentage_spin_box.singleStep()
                if step > 1:
                    precision = 0
                else:
                    precision = len(str(step).split('.')[1])
                    if precision > 3:
                        precision = 3
                percentage_spin_box.setDecimals(precision)
                self.spin_boxes[key] = percentage_spin_box

                # Enable spin box depends on the selected option
                if self._parameter.selected == key:
                    percentage_spin_box.setEnabled(True)
                else:
                    percentage_spin_box.setEnabled(False)

            elif value.get('type') == STATIC:
                static_value = value.get('value', 0)
                if static_value is not None:
                    self.radio_button_layout.addWidget(
                        QLabel(str(static_value * 100) + ' %'), i, 1)
            elif value.get('type') == MULTIPLE_DYNAMIC:
                if self._parameter.selected == key:
                    self.list_widget.setEnabled(True)
                else:
                    self.list_widget.setEnabled(False)

            self.input_button_group.addButton(radio_button, i)
            if self._parameter.selected == key:
                radio_button.setChecked(True)

        # Help text
        self.help_label = QLabel(self._parameter.help_text)
        self.help_label.setSizePolicy(QSizePolicy.Maximum,
                                      QSizePolicy.Expanding)
        self.help_label.setWordWrap(True)
        self.help_label.setAlignment(Qt.AlignTop)

        self.inner_input_layout.addLayout(self.radio_button_layout)
        self.inner_input_layout.addWidget(self.list_widget)

        # Put elements into layouts
        self.input_layout.addWidget(self.label)
        self.input_layout.addLayout(self.inner_input_layout)

        self.help_layout = QVBoxLayout()
        self.help_layout.addWidget(self.help_label)

        self.main_layout.addLayout(self.input_layout)
        self.main_layout.addLayout(self.help_layout)

        self.setLayout(self.main_layout)

        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)

        # Update list widget
        self.update_list_widget()

        # Connect signal
        # noinspection PyUnresolvedReferences
        self.input_button_group.buttonClicked.connect(
            self.radio_buttons_clicked)

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A DefaultValueParameter from the current state of widget
        :rtype: DefaultValueParameter
        """
        # Set value for each key
        for key, value in list(self._parameter.options.items()):
            if value.get('type') == STATIC:
                continue
            elif value.get('type') == SINGLE_DYNAMIC:
                new_value = self.spin_boxes.get(key).value()
                self._parameter.set_value_for_key(key, new_value)
            elif value.get('type') == MULTIPLE_DYNAMIC:
                # Need to iterate through all items
                items = []
                for index in range(self.list_widget.count()):
                    items.append(self.list_widget.item(index))
                new_value = [i.text() for i in items]
                self._parameter.set_value_for_key(key, new_value)

        # Get selected radio button
        radio_button_checked_id = self.input_button_group.checkedId()
        # No radio button checked, then default value = None
        if radio_button_checked_id == -1:
            self._parameter.selected = None
        else:
            self._parameter.selected = list(
                self._parameter.options.keys())[radio_button_checked_id]

        return self._parameter

    def update_list_widget(self):
        """Update list widget when radio button is clicked."""
        # Get selected radio button
        radio_button_checked_id = self.input_button_group.checkedId()
        # No radio button checked, then default value = None
        if radio_button_checked_id > -1:
            selected_dict = list(
                self._parameter.options.values())[radio_button_checked_id]
            if selected_dict.get('type') == MULTIPLE_DYNAMIC:
                for field in selected_dict.get('value'):
                    # Update list widget
                    field_item = QListWidgetItem(self.list_widget)
                    field_item.setFlags(Qt.ItemIsEnabled
                                        | Qt.ItemIsSelectable
                                        | Qt.ItemIsDragEnabled)
                    field_item.setData(Qt.UserRole, field)
                    field_item.setText(field)
                    self.list_widget.addItem(field_item)

    def radio_buttons_clicked(self):
        """Handler when selected radio button changed."""
        # Disable all spin boxes
        for spin_box in list(self.spin_boxes.values()):
            spin_box.setEnabled(False)
        # Disable list widget
        self.list_widget.setEnabled(False)

        # Get selected radio button
        radio_button_checked_id = self.input_button_group.checkedId()

        if radio_button_checked_id > -1:
            selected_value = list(
                self._parameter.options.values())[radio_button_checked_id]
            if selected_value.get('type') == MULTIPLE_DYNAMIC:
                # Enable list widget
                self.list_widget.setEnabled(True)
            elif selected_value.get('type') == SINGLE_DYNAMIC:
                selected_key = list(
                    self._parameter.options.keys())[radio_button_checked_id]
                self.spin_boxes[selected_key].setEnabled(True)

    def select_radio_button(self, key):
        """Helper to select a radio button with key.

        :param key: The key of the radio button.
        :type key: str
        """
        key_index = list(self._parameter.options.keys()).index(key)
        radio_button = self.input_button_group.button(key_index)
        radio_button.click()
class QmsSearchResultItemWidget(QWidget):
    def __init__(self, geoservice, image_ba, parent=None, extent_renderer=None):
        QWidget.__init__(self, parent)

        self.extent_renderer = extent_renderer

        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(5, 10, 5, 10)
        self.setLayout(self.layout)

        self.service_icon = QLabel(self)
        self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.service_icon.resize(24, 24)

        qimg = QImage.fromData(image_ba)
        pixmap = QPixmap.fromImage(qimg)
        self.service_icon.setPixmap(pixmap)
        self.layout.addWidget(self.service_icon)

        self.service_desc_layout = QGridLayout(self)
        self.service_desc_layout.setSpacing(0)
        self.layout.addLayout(self.service_desc_layout)

        self.service_name = QLabel(self)
        self.service_name.setTextFormat(Qt.RichText)
        self.service_name.setWordWrap(True)
        self.service_name.setText(u"   <strong> {} </strong>".format(geoservice.get('name', u"")))
        self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3)

        self.service_type = QLabel(self)
        self.service_type.setTextFormat(Qt.RichText)
        self.service_type.setWordWrap(True)
        self.service_type.setText(geoservice.get('type', u"").upper() + " ")
        self.service_desc_layout.addWidget(self.service_type, 1, 0)

        self.service_deteils = QLabel(self)
        self.service_deteils.setTextFormat(Qt.RichText)
        self.service_deteils.setWordWrap(True)
        self.service_deteils.setOpenExternalLinks(True)
        self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format(
            Client().geoservice_info_url(geoservice.get('id', u"")),
            self.tr('details')
        ))
        self.service_desc_layout.addWidget(self.service_deteils, 1, 1)

        self.service_report = QLabel(self)
        self.service_report.setTextFormat(Qt.RichText)
        self.service_report.setWordWrap(True)
        self.service_report.setOpenExternalLinks(True)
        self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format(
            Client().geoservice_report_url(geoservice.get('id', u"")),
            self.tr('report a problem')
        ))
        self.service_desc_layout.addWidget(self.service_report, 1, 2)
        self.service_desc_layout.setColumnStretch(2, 1)


        self.status_label = QLabel(self)
        self.status_label.setTextFormat(Qt.RichText)
        self.status_label.setText(u'\u2022')


        status = geoservice.get('cumulative_status', u'')
        if status == 'works':
            self.status_label.setStyleSheet("color: green; font-size: 30px")
        if status == 'failed':
            self.status_label.setStyleSheet("color: red; font-size: 30px")
        if status == 'problematic':
            self.status_label.setStyleSheet("color: yellow; font-size: 30px")
        self.layout.addWidget(self.status_label)


        self.addButton = QToolButton()
        self.addButton.setText(self.tr("Add"))
        self.addButton.clicked.connect(self.addToMap)
        self.layout.addWidget(self.addButton)
        
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)

        self.geoservice = geoservice
        self.image_ba = image_ba

    def addToMap(self):
        try:
            QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
            client = Client()
            client.set_proxy(*QGISSettings.get_qgis_proxy())
            geoservice_info = client.get_geoservice_info(self.geoservice)
            ds = DataSourceSerializer.read_from_json(geoservice_info)
            add_layer_to_map(ds)

            CachedServices().add_service(self.geoservice, self.image_ba)
        except Exception as ex:
            plPrint(unicode(ex))
            pass
        finally:
            QApplication.restoreOverrideCursor()

    def mouseDoubleClickEvent(self, event):
        self.addToMap()

    def enterEvent(self, event):
        extent = self.geoservice.get('extent', None)
        if self.extent_renderer and extent:
            if ';' in extent:
                extent = extent.split(';')[1]
            geom = QgsGeometry.fromWkt(extent)
            self.extent_renderer.show_feature(geom)

    def leaveEvent(self, event):
        if self.extent_renderer:
            self.extent_renderer.clear_feature()
Esempio n. 33
0
class PlanetOrderBundleWidget(QFrame):

    selectionChanged = pyqtSignal()

    def __init__(self, bundleid, name, description, udm, can_harmonize,
                 rectified):
        super().__init__()

        self.bundleid = bundleid
        self.name = name
        self.description = description
        self.udm = udm
        self.can_harmonize = can_harmonize
        self.rectified = rectified

        layout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout.setMargin(0)
        self.labelName = QLabel(f"<b>{name}</b>")
        hlayout.addWidget(self.labelName)
        hlayout.addStretch()
        self.chkSelected = QCheckBox()
        self.chkSelected.stateChanged.connect(self.checkStateChanged)
        hlayout.addWidget(self.chkSelected)
        layout.addLayout(hlayout)
        self.labelDescription = QLabel(description)
        self.labelDescription.setWordWrap(True)
        layout.addWidget(self.labelDescription)
        hlayouttype = QHBoxLayout()
        hlayouttype.setMargin(0)
        self.radioTiff = QRadioButton("GeoTIFF")
        self.radioTiff.setChecked(True)
        self.radioTiff.toggled.connect(self.selectionChanged.emit)
        hlayouttype.addWidget(self.radioTiff)
        self.radioNitf = QRadioButton("NITF")
        self.radioNitf.toggled.connect(self.selectionChanged.emit)
        hlayouttype.addWidget(self.radioNitf)
        hlayouttype.addStretch()
        layout.addLayout(hlayouttype)
        if udm:
            hlayoutudm = QHBoxLayout()
            hlayoutudm.setMargin(0)
            self.labelUdm = IconLabel("UDM2", UDM_ICON)
            hlayoutudm.addWidget(self.labelUdm)
            hlayoutudm.addStretch()
            layout.addLayout(hlayoutudm)

        self.setFrameStyle(QFrame.Panel | QFrame.Raised)
        self.setLayout(layout)
        self.checkStateChanged()

    def checkStateChanged(self):
        self.radioTiff.setEnabled(self.chkSelected.isChecked())
        self.radioNitf.setEnabled(self.chkSelected.isChecked())
        self.labelName.setEnabled(self.chkSelected.isChecked())
        self.labelDescription.setEnabled(self.chkSelected.isChecked())
        if self.udm:
            self.labelUdm.setEnabled(self.chkSelected.isChecked())
        self.selectionChanged.emit()

    def selected(self):
        return self.chkSelected.isChecked()

    def setSelected(self, selected, emit=False):
        if not emit:
            self.blockSignals(True)
        self.chkSelected.setChecked(selected)
        self.blockSignals(False)

    def filetype(self):
        if self.radioTiff.isChecked():
            return "GeoTIFF"
        else:
            return "NITF"
class GroupSelectParameterWidget(GenericParameterWidget):

    """Widget class for Group Select Parameter."""

    def __init__(self, parameter, parent=None):
        """Constructor.

        :param parameter: A GroupSelectParameter object.
        :type parameter: GroupSelectParameter
        """
        QWidget.__init__(self, parent)
        self._parameter = parameter

        # Store spin box
        self.spin_boxes = {}

        # Create elements
        # Label (name)
        self.label = QLabel(self._parameter.name)

        # Layouts
        self.main_layout = QVBoxLayout()
        self.input_layout = QVBoxLayout()

        # _inner_input_layout must be filled with widget in the child class
        self.inner_input_layout = QVBoxLayout()

        self.radio_button_layout = QGridLayout()

        # Create radio button group
        self.input_button_group = QButtonGroup()

        # List widget
        self.list_widget = QListWidget()
        self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.list_widget.setDragDropMode(QAbstractItemView.DragDrop)
        self.list_widget.setDefaultDropAction(Qt.MoveAction)
        self.list_widget.setEnabled(False)
        self.list_widget.setSizePolicy(
            QSizePolicy.Maximum, QSizePolicy.Expanding)

        for i, key in enumerate(self._parameter.options):
            value = self._parameter.options[key]
            radio_button = QRadioButton(value.get('label'))
            self.radio_button_layout.addWidget(radio_button, i, 0)
            if value.get('type') == SINGLE_DYNAMIC:
                percentage_spin_box = PercentageSpinBox(self)
                self.radio_button_layout.addWidget(percentage_spin_box, i, 1)
                percentage_spin_box.setValue(value.get('value', 0))
                step = percentage_spin_box.singleStep()
                if step > 1:
                    precision = 0
                else:
                    precision = len(str(step).split('.')[1])
                    if precision > 3:
                        precision = 3
                percentage_spin_box.setDecimals(precision)
                self.spin_boxes[key] = percentage_spin_box

                # Enable spin box depends on the selected option
                if self._parameter.selected == key:
                    percentage_spin_box.setEnabled(True)
                else:
                    percentage_spin_box.setEnabled(False)

            elif value.get('type') == STATIC:
                static_value = value.get('value', 0)
                if static_value is not None:
                    self.radio_button_layout.addWidget(
                        QLabel(str(static_value * 100) + ' %'), i, 1)
            elif value.get('type') == MULTIPLE_DYNAMIC:
                if self._parameter.selected == key:
                    self.list_widget.setEnabled(True)
                else:
                    self.list_widget.setEnabled(False)

            self.input_button_group.addButton(radio_button, i)
            if self._parameter.selected == key:
                radio_button.setChecked(True)

        # Help text
        self.help_label = QLabel(self._parameter.help_text)
        self.help_label.setSizePolicy(
            QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.help_label.setWordWrap(True)
        self.help_label.setAlignment(Qt.AlignTop)

        self.inner_input_layout.addLayout(self.radio_button_layout)
        self.inner_input_layout.addWidget(self.list_widget)

        # Put elements into layouts
        self.input_layout.addWidget(self.label)
        self.input_layout.addLayout(self.inner_input_layout)

        self.help_layout = QVBoxLayout()
        self.help_layout.addWidget(self.help_label)

        self.main_layout.addLayout(self.input_layout)
        self.main_layout.addLayout(self.help_layout)

        self.setLayout(self.main_layout)

        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)

        # Update list widget
        self.update_list_widget()

        # Connect signal
        # noinspection PyUnresolvedReferences
        self.input_button_group.buttonClicked.connect(
            self.radio_buttons_clicked)

    def get_parameter(self):
        """Obtain list parameter object from the current widget state.

        :returns: A DefaultValueParameter from the current state of widget
        :rtype: DefaultValueParameter
        """
        # Set value for each key
        for key, value in list(self._parameter.options.items()):
            if value.get('type') == STATIC:
                continue
            elif value.get('type') == SINGLE_DYNAMIC:
                new_value = self.spin_boxes.get(key).value()
                self._parameter.set_value_for_key(key, new_value)
            elif value.get('type') == MULTIPLE_DYNAMIC:
                # Need to iterate through all items
                items = []
                for index in range(self.list_widget.count()):
                    items.append(self.list_widget.item(index))
                new_value = [i.text() for i in items]
                self._parameter.set_value_for_key(key, new_value)

        # Get selected radio button
        radio_button_checked_id = self.input_button_group.checkedId()
        # No radio button checked, then default value = None
        if radio_button_checked_id == -1:
            self._parameter.selected = None
        else:
            self._parameter.selected = list(self._parameter.options.keys())[
                radio_button_checked_id]

        return self._parameter

    def update_list_widget(self):
        """Update list widget when radio button is clicked."""
        # Get selected radio button
        radio_button_checked_id = self.input_button_group.checkedId()
        # No radio button checked, then default value = None
        if radio_button_checked_id > -1:
            selected_dict = list(self._parameter.options.values())[
                radio_button_checked_id]
            if selected_dict.get('type') == MULTIPLE_DYNAMIC:
                for field in selected_dict.get('value'):
                    # Update list widget
                    field_item = QListWidgetItem(self.list_widget)
                    field_item.setFlags(
                        Qt.ItemIsEnabled
                        | Qt.ItemIsSelectable
                        | Qt.ItemIsDragEnabled)
                    field_item.setData(Qt.UserRole, field)
                    field_item.setText(field)
                    self.list_widget.addItem(field_item)

    def radio_buttons_clicked(self):
        """Handler when selected radio button changed."""
        # Disable all spin boxes
        for spin_box in list(self.spin_boxes.values()):
            spin_box.setEnabled(False)
        # Disable list widget
        self.list_widget.setEnabled(False)

        # Get selected radio button
        radio_button_checked_id = self.input_button_group.checkedId()

        if radio_button_checked_id > -1:
            selected_value = list(self._parameter.options.values())[
                radio_button_checked_id]
            if selected_value.get('type') == MULTIPLE_DYNAMIC:
                # Enable list widget
                self.list_widget.setEnabled(True)
            elif selected_value.get('type') == SINGLE_DYNAMIC:
                selected_key = list(self._parameter.options.keys())[
                    radio_button_checked_id]
                self.spin_boxes[selected_key].setEnabled(True)

    def select_radio_button(self, key):
        """Helper to select a radio button with key.

        :param key: The key of the radio button.
        :type key: str
        """
        key_index = list(self._parameter.options.keys()).index(key)
        radio_button = self.input_button_group.button(key_index)
        radio_button.click()