Beispiel #1
0
    def on_load_base_layer(self):
        # look for base layers in the config
        layer_config = get_layer_config()

        dlg = QDialog()
        vbox = QVBoxLayout()
        list_widget = QListWidget()
        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        vbox.addWidget(list_widget)
        vbox.addWidget(button_box)
        dlg.setWindowTitle("Select a base layer to load")
        dlg.setLayout(vbox)

        # populate the list widget
        for (uri, provider), cfg in layer_config.items():
            layer_name = cfg.get(
                "layer_name", "Unnamed layer ({}, {})".format(uri, provider))
            list_item = QListWidgetItem()
            list_item.setText(layer_name)
            list_item.setData(Qt.UserRole, (uri, provider))
            list_widget.addItem(list_item)

        button_box.rejected.connect(dlg.reject)
        button_box.accepted.connect(dlg.accept)

        if dlg.exec_():
            item = list_widget.currentItem()
            if item:
                uri, provider = item.data(Qt.UserRole)
                self.iface.addVectorLayer(uri, item.text(), provider)
Beispiel #2
0
 def createCellWidget(self, qmlDict, attr, count):
     """
     Creates specific widgets for each attribute, which can be a QCombobox, a QLineEdit or a QListWidget.
     """
     if attr in qmlDict:
         enableIgnoreOption = False
         #case the type is dict the cell widget must be a combobox
         if isinstance(qmlDict[attr],dict):
             comboItem = DsgCustomComboBox()
             comboItem.addItems(sorted(qmlDict[attr].keys()))
             self.attributeTableWidget.setCellWidget(count, 1, comboItem)
         #case the type is tuple the cell widget must be a listwidget
         if isinstance(qmlDict[attr],tuple):
             (table, filterKeys) = qmlDict[attr]
             #getting the value relation dictionary used to make the listwidget
             valueRelation = self.makeValueRelationDict(table, filterKeys)
             list = QListWidget()
             for key in list(valueRelation.keys()):
                 listItem = QListWidgetItem(key)
                 listItem.setCheckState(Qt.Unchecked)
                 list.addItem(listItem)
             self.attributeTableWidget.setCellWidget(count, 1, list)
     #this is the normal case, a simple lineedit
     else:
         textItem = QLineEdit()
         self.attributeTableWidget.setCellWidget(count, 1, textItem)
         enableIgnoreOption = True
     #insert here aditional parameters
     self.createAditionalParameters(count, enableIgnoreOption)
Beispiel #3
0
 def createEditor(self, parent, option, index):
     """
     Creates a custom editor to edit value relation data
     """
     # special combobox for field type
     if index.column() == self.column:
         list = QListWidget(parent)
         for item in self.itemsDict:
             listItem = QListWidgetItem(item)
             listItem.setCheckState(Qt.Unchecked)
             list.addItem(listItem)
         return list
     return QItemDelegate.createEditor(self, parent, option, index)
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()
Beispiel #5
0
class DataSelector(QDialog):
    def __init__(self, viewer, features, config_list, config):
        QDialog.__init__(self)

        self.__viewer = viewer
        self.__features = features
        self.__config_list = config_list
        self.__config = config
        vbox = QVBoxLayout()

        btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn.accepted.connect(self.accept)
        btn.rejected.connect(self.reject)

        self.__list = QListWidget()
        self.__list.setSelectionMode(QAbstractItemView.ExtendedSelection)

        hbox = QHBoxLayout()
        lbl = QLabel("Sub selection")
        self.__sub_selection_combo = QComboBox()
        self.__sub_selection_combo.setEnabled(False)
        hbox.addWidget(lbl)
        hbox.addWidget(self.__sub_selection_combo)

        self.__title_label = QLabel()

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.__title_label)

        vbox.addLayout(hbox2)
        vbox.addWidget(self.__list)
        vbox.addLayout(hbox)
        vbox.addWidget(btn)

        self.__list.itemSelectionChanged.connect(self.on_selection_changed)
        self.__sub_selection_combo.currentIndexChanged[str].connect(
            self.on_combo_changed)

        self.setLayout(vbox)
        self.setWindowTitle("Choose the data to add")
        self.resize(400, 200)

        self._populate_list()
        self.set_title(",".join([
            feature[self.__config["name_column"]]
            for feature in self.__features
        ]))

    def set_title(self, title):
        self.__title_label.setText("Station(s): {}".format(title))

    def _populate_list(self):
        self.__list.clear()
        for cfg in self.__config_list:
            if cfg["type"] in ("cumulative", "instantaneous"):
                # check number of features for this station

                if cfg.get("feature_filter_type") == "unique_data_from_values":
                    # get unique filter values

                    layerid = cfg["source"]
                    data_l = QgsProject.instance().mapLayers()[layerid]
                    values = set()
                    for feature in self.__features:
                        feature_id = feature[self.__config["id_column"]]
                        req = QgsFeatureRequest()
                        req.setFilterExpression("{}={}".format(
                            cfg["feature_ref_column"], feature_id))
                        values.update([
                            f[cfg["feature_filter_column"]]
                            for f in data_l.getFeatures(req)
                        ])

                        cfg.set_filter_unique_values(sorted(list(values)))

            item = QListWidgetItem(cfg["name"])
            item.setData(Qt.UserRole, cfg)
            self.__list.addItem(item)

    def accept(self):

        for feature in self.__features:
            self.__load_feature(feature)

    def __load_feature(self, feature):
        # FIXME this code too similar to main_dialog.load_plots
        # FIXME find a way to factor

        feature_id = feature[self.__config["id_column"]]
        feature_name = feature[self.__config["name_column"]]

        for item in self.__list.selectedItems():
            # now add the selected configuration
            cfg = item.data(Qt.UserRole)
            if cfg["type"] in ("cumulative", "instantaneous", "continuous"):
                layerid = cfg["source"]
                data_l = QgsProject.instance().mapLayers()[layerid]
                req = QgsFeatureRequest()
                filter_expr = "{}='{}'".format(cfg["feature_ref_column"],
                                               feature_id)
                req.setFilterExpression(filter_expr)

                title = cfg["name"]

                if cfg.get_filter_value():
                    filter_expr += " and {}='{}'".format(
                        cfg["feature_filter_column"], cfg.get_filter_value())

                    title = cfg.get_filter_value()
                else:
                    title = cfg["name"]

                f = None
                # test if the layer actually contains data
                for f in data_l.getFeatures(req):
                    break
                if f is None:
                    return
                if cfg["type"] == "instantaneous":
                    uom = cfg.get_uom()
                    data = LayerData(data_l,
                                     cfg["event_column"],
                                     cfg["value_column"],
                                     filter_expression=filter_expr,
                                     uom=uom)
                    uom = data.uom()
                    self.__viewer.add_data_cell(data,
                                                title,
                                                uom,
                                                station_name=feature_name,
                                                config=cfg)
                    self.__viewer.add_scale()
                if cfg["type"] == "continuous":
                    uom = cfg.get_uom()
                    fids = [f.id() for f in data_l.getFeatures(req)]
                    data = FeatureData(
                        data_l,
                        cfg["values_column"],
                        feature_ids=fids,
                        x_start_fieldname=cfg["start_measure_column"],
                        x_delta_fieldname=cfg["interval_column"])
                    self.__viewer.add_data_cell(data,
                                                title,
                                                uom,
                                                station_name=feature_name,
                                                config=cfg)
                elif cfg["type"] == "cumulative":
                    self.__viewer.add_histogram(
                        data_l,
                        filter_expression=filter_expr,
                        column_mapping={
                            f: cfg[f]
                            for f in ("min_event_column", "max_event_column",
                                      "value_column")
                        },
                        title=title,
                        config=cfg,
                        station_name=feature_name)

            elif cfg["type"] == "image":
                self.__viewer.add_imagery_from_db(cfg, feature_id)

        QDialog.accept(self)

    def on_selection_changed(self):
        self.__sub_selection_combo.clear()
        self.__sub_selection_combo.setEnabled(False)
        for item in self.__list.selectedItems():
            cfg = item.data(Qt.UserRole)
            for v in cfg.get_filter_unique_values():
                self.__sub_selection_combo.addItem(v)
            if cfg.get_filter_value():
                self.__sub_selection_combo.setCurrentIndex(
                    self.__sub_selection_combo.findText(
                        cfg.get_filter_value()))
            self.__sub_selection_combo.setEnabled(True)
            return

    def on_combo_changed(self, text):
        for item in self.__list.selectedItems():
            cfg = item.data(Qt.UserRole)
            cfg.set_filter_value(text)
            item.setData(Qt.UserRole, cfg)
            return
class ScenarioSelectionDialog(QDialog):
    """
    A dialog used for selecting from available scenarios
    """

    def __init__(self, scenario_registry: ScenarioRegistry, parent=None):
        """
        Constructor for ScenarioSelectionDialog
        :param scenario_registry: linked scenario registry
        :param parent: parent widget
        """
        super().__init__(parent)

        self.scenario_registry = scenario_registry

        self.setWindowTitle(self.tr('Select Current Scenario'))

        layout = QVBoxLayout()

        self.search = QgsFilterLineEdit()
        self.search.setShowSearchIcon(True)
        self.search.setPlaceholderText(self.tr('Search for scenario'))
        self.search.textChanged.connect(self.filter_changed)
        layout.addWidget(self.search)

        self.list = QListWidget()
        for title, scenario_id in scenario_registry.scenario_titles().items():
            item = QListWidgetItem(title)
            item.setData(Qt.UserRole, scenario_id)
            self.list.addItem(item)

        layout.addWidget(self.list, 10)

        button_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        layout.addWidget(button_box)
        button_box.rejected.connect(self.reject)
        button_box.accepted.connect(self.accept)

        self.setLayout(layout)

        self.list.itemDoubleClicked.connect(
            self.accept)

        # select last scenario by default
        if self.list.count() > 0:
            self.list.item(self.list.count() - 1).setSelected(True)

    def set_selected_scenario(self, scenario):
        """
        Sets the scenario selected in the dialog
        :param scenario: scenario to select
        """
        for i in range(self.list.count()):
            if self.list.item(i).data(Qt.UserRole) == scenario:
                self.list.item(i).setSelected(True)
                return

    def selected_scenario(self):
        """
        Returns the scenario selected in the dialog
        """
        if self.list.selectedItems():
            return self.list.selectedItems()[0].data(Qt.UserRole)

        return None

    def filter_changed(self, filter_text):
        """
        Handles search filter changes
        """
        for i in range(self.list.count()):
            item = self.list.item(i)
            item.setHidden(filter_text.upper() not in item.text().upper())
class DeprecateElectorateDialog(QDialog):
    """
    A dialog used for selecting electorates to deprecate (or un-deprecate)
    :param district_registry: associated registry of available
    districts to show
    """
    def __init__(self,
                 electorate_registry: LinzElectoralDistrictRegistry,
                 parent=None):
        super().__init__(parent)

        self.electorate_registry = electorate_registry

        self.setWindowTitle(self.tr('Deprecate Electorate'))

        layout = QVBoxLayout()

        self.search = QgsFilterLineEdit()
        self.search.setShowSearchIcon(True)
        self.search.setPlaceholderText(
            self.tr('Search for {}').format(
                electorate_registry.type_string_sentence()))
        self.search.textChanged.connect(self.filter_changed)
        layout.addWidget(self.search)

        request = QgsFeatureRequest()
        request.setFlags(QgsFeatureRequest.NoGeometry)
        request.setSubsetOfAttributes([
            electorate_registry.source_field_index,
            electorate_registry.title_field_index,
            electorate_registry.deprecated_field_index
        ])
        self.list = QListWidget()
        for f in electorate_registry.source_layer.getFeatures(request):
            title = f[electorate_registry.title_field_index]
            code = f[electorate_registry.source_field_index]
            deprecated = f[electorate_registry.deprecated_field_index]

            if deprecated:
                title = '*' + title
            item = QListWidgetItem(title)
            item.setData(Qt.UserRole, code)
            self.list.addItem(item)

        layout.addWidget(self.list, 10)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        layout.addWidget(button_box)
        button_box.rejected.connect(self.reject)
        button_box.accepted.connect(self.accept)

        self.setLayout(layout)
        self.list.itemDoubleClicked.connect(self.accept)

    def selected_district(self):
        """
        Returns the electorate selected in the dialog
        """
        if self.list.selectedItems():
            return self.list.selectedItems()[0].data(Qt.UserRole)

        return None

    def filter_changed(self, filter_text):
        """
        Handles search filter changes
        """
        for i in range(self.list.count()):
            item = self.list.item(i)
            item.setHidden(filter_text.upper() not in item.text().upper())
Beispiel #8
0
class GraphDialog(QDialog):

    edit_patterns = 0
    edit_curves = 1

    titles = {edit_patterns: 'Pattern editor', edit_curves: 'Curve editor'}

    labels = {edit_patterns: 'Patterns', edit_curves: 'Curves'}

    def __init__(self, dockwidget, parent, params, edit_type):

        QDialog.__init__(self, parent)
        main_lay = QVBoxLayout(self)
        self.dockwidget = dockwidget
        self.params = params
        self.edit_type = edit_type

        self.x_label = ''
        self.y_label = ''

        self.setMinimumWidth(600)
        self.setMinimumHeight(400)

        self.setWindowTitle(self.titles[edit_type])  # TODO: softcode
        self.setWindowModality(QtCore.Qt.ApplicationModal)

        self.current = None

        self.current_saved = False

        # File
        self.lbl_file = QLabel('File:')
        self.fra_file = QFrame()
        self.fra_file.setContentsMargins(0, 0, 0, 0)
        fra_file_lay = QHBoxLayout(self.fra_file)

        if edit_type == self.edit_patterns:
            self.txt_file = QLineEdit(self.params.patterns_file)
        elif edit_type == self.edit_curves:
            self.txt_file = QLineEdit(self.params.curves_file)

        self.txt_file.setReadOnly(True)
        self.txt_file.setAlignment(QtCore.Qt.AlignLeft
                                   | QtCore.Qt.AlignVCenter)
        self.txt_file.setSizePolicy(QSizePolicy.MinimumExpanding,
                                    QSizePolicy.Minimum)
        fra_file_lay.addWidget(self.txt_file)
        self.btn_file = QPushButton('Change')  # TODO: softcode
        self.btn_file.clicked.connect(self.import_file)
        fra_file_lay.addWidget(self.btn_file)
        fra_file_lay.setContentsMargins(0, 0, 0, 0)

        self.lbl_list = QLabel(self.labels[edit_type])
        self.lst_list = QListWidget()
        self.lst_list.currentItemChanged.connect(self.list_item_changed)

        # Form
        self.fra_form = QFrame()
        fra_form1_lay = QFormLayout(self.fra_form)
        fra_form1_lay.setContentsMargins(0, 0, 0, 0)
        fra_form1_lay.addRow(self.lbl_list, self.lst_list)

        # Buttons
        self.fra_buttons = QFrame()
        fra_buttons_lay = QHBoxLayout(self.fra_buttons)
        fra_buttons_lay.setContentsMargins(0, 0, 0, 0)

        if self.edit_type == self.edit_patterns:
            ele_name = 'pattern'
        elif self.edit_type == self.edit_curves:
            ele_name = 'curve'

        self.btn_new = QPushButton('New ' + ele_name)  # TODO: softcode
        self.btn_new.clicked.connect(self.new_element)
        fra_buttons_lay.addWidget(self.btn_new)

        self.btn_import = QPushButton('Import ' + ele_name +
                                      's')  # TODO: softcode
        self.btn_import.clicked.connect(self.import_file)
        fra_buttons_lay.addWidget(self.btn_import)

        self.btn_save = QPushButton('Save current ' +
                                    ele_name)  # TODO: softcode
        self.btn_save.clicked.connect(self.save)
        fra_buttons_lay.addWidget(self.btn_save)

        self.btn_del = QPushButton('Delete current ' +
                                   ele_name)  # TODO: softcode
        self.btn_del.clicked.connect(self.del_item)
        fra_buttons_lay.addWidget(self.btn_del)

        # ID
        self.lbl_id = QLabel('ID:')
        self.txt_id = QLineEdit()
        self.txt_id.setSizePolicy(QSizePolicy.Maximum,
                                  QSizePolicy.MinimumExpanding)
        self.lbl_desc = QLabel('Desc.:')
        self.txt_desc = QLineEdit()

        self.fra_id = QFrame()
        fra_id_lay = QHBoxLayout(self.fra_id)
        fra_id_lay.addWidget(self.lbl_id)
        fra_id_lay.addWidget(self.txt_id)
        fra_id_lay.addWidget(self.lbl_desc)
        fra_id_lay.addWidget(self.txt_desc)

        # Table form
        self.table = QTableWidget(self)
        self.rows_nr = 24
        self.cols_nr = 2
        self.table.setRowCount(self.rows_nr)
        self.table.setColumnCount(self.cols_nr)
        self.table.verticalHeader().setVisible(False)

        # Initialize empty table
        self.clear_table()

        self.table.itemChanged.connect(self.data_changed)

        self.fra_table = QFrame()
        fra_table_lay = QVBoxLayout(self.fra_table)
        fra_table_lay.setContentsMargins(0, 0, 0, 0)

        if edit_type == self.edit_curves:
            self.fra_pump_type = QFrame()
            fra_pump_type_lay = QFormLayout(self.fra_pump_type)

            self.lbl_pump_type = QLabel('Curve type:')  # TODO: softcode
            self.cbo_pump_type = QComboBox()

            for key, name in Curve.type_names.items():
                self.cbo_pump_type.addItem(name, key)

            fra_pump_type_lay.addRow(self.lbl_pump_type, self.cbo_pump_type)

            fra_table_lay.addWidget(self.fra_pump_type)

            self.cbo_pump_type.activated.connect(self.cbo_pump_type_activated)

        fra_table_lay.addWidget(self.table)
        self.btn_add_row = QPushButton('Add row')
        self.btn_add_row.clicked.connect(self.add_row)
        fra_table_lay.addWidget(self.btn_add_row)

        # Graph canvas
        self.fra_graph = QFrame()
        self.static_canvas = StaticMplCanvas(self.fra_graph,
                                             width=5,
                                             height=4,
                                             dpi=100)
        fra_graph_lay = QVBoxLayout(self.fra_graph)
        fra_graph_lay.addWidget(self.static_canvas)

        # Top frame
        self.fra_top = QFrame()
        fra_top_lay = QVBoxLayout(self.fra_top)
        fra_top_lay.addWidget(self.fra_form)
        fra_top_lay.addWidget(self.fra_id)
        fra_top_lay.addWidget(self.fra_buttons)

        # Bottom frame
        self.fra_bottom = QFrame()
        fra_bottom_lay = QHBoxLayout(self.fra_bottom)
        fra_bottom_lay.addWidget(self.fra_table)
        fra_bottom_lay.addWidget(self.fra_graph)

        # Main
        main_lay.addWidget(self.fra_top)
        main_lay.addWidget(self.fra_bottom)

        # Get existing patterns/curves
        self.need_to_update_graph = False
        if self.edit_type == self.edit_patterns:
            for pattern_id, pattern in self.params.patterns.items():
                self.lst_list.addItem(pattern.id)

        elif self.edit_type == self.edit_curves:
            for curve_id, curve in self.params.curves.items():
                self.lst_list.addItem(curve.id)

        if self.lst_list.count() > 0:
            self.lst_list.setCurrentRow(0)
            self.txt_id.setEnabled(True)
            self.txt_desc.setEnabled(True)
            self.btn_save.setEnabled(True)
            self.btn_del.setEnabled(True)
            self.table.setEnabled(True)
            self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)
        else:
            self.txt_id.setEnabled(False)
            self.txt_desc.setEnabled(False)
            self.btn_save.setEnabled(False)
            self.btn_del.setEnabled(False)
            self.table.setEnabled(False)
            self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.new_dialog = None
        self.need_to_update_graph = True

    def cbo_pump_type_activated(self):
        self.update_table_headers()
        self.update_graph()

    def add_row(self):
        row_pos = self.table.rowCount()
        self.table.insertRow(row_pos)
        col = 0
        item = QTableWidgetItem(str(row_pos))

        if self.edit_type == self.edit_patterns:
            self.table.setItem(row_pos, col, item)
            item.setFlags(QtCore.Qt.ItemIsSelectable)

    def setVisible(self, bool):
        QDialog.setVisible(self, bool)

        self.update_table_headers()
        self.update_graph()

    def list_item_changed(self):

        p_index = self.lst_list.currentRow()

        flags = Qt.ItemFlags()
        flags != Qt.ItemIsEnabled

        # Clear table
        self.clear_table()

        self.need_to_update_graph = False
        if p_index >= 0:

            self.table.setRowCount(0)

            if self.edit_type == self.edit_patterns:
                self.current = self.params.patterns[
                    self.lst_list.currentItem().text()]
                for v in range(len(self.current.values)):

                    row_pos = self.table.rowCount()
                    self.table.insertRow(row_pos)

                    item = QTableWidgetItem(str(v))
                    item.setFlags(flags)
                    self.table.setItem(v, 0, item)
                    self.table.setItem(
                        v, 1, QTableWidgetItem(str(self.current.values[v])))

            elif self.edit_type == self.edit_curves:
                self.current = self.params.curves[
                    self.lst_list.currentItem().text()]
                for v in range(len(self.current.xs)):

                    row_pos = self.table.rowCount()
                    self.table.insertRow(row_pos)

                    self.table.setItem(
                        v, 0, QTableWidgetItem(str(self.current.xs[v])))
                    self.table.setItem(
                        v, 1, QTableWidgetItem(str(self.current.ys[v])))

                curve_type = self.current.type
                self.cbo_pump_type.setCurrentIndex(curve_type)

            # Update GUI
            self.txt_id.setText(self.current.id)
            self.txt_desc.setText(self.current.desc)

            self.update_table_headers()

            # Update graph
            self.need_to_update_graph = True
            self.update_graph()

        else:

            # No curves
            self.txt_id.setText('')
            self.txt_desc.setText('')

            # Update table and chart
            self.need_to_update_graph = False
            for v in range(self.table.columnCount()):
                self.table.setItem(v, 1, QTableWidgetItem(''))

            self.need_to_update_graph = True
            self.update_graph()

    def import_file(self):

        config_file = ConfigFile(Parameters.config_file_path)

        directory = None
        if self.edit_type == GraphDialog.edit_curves:
            directory = self.params.last_curves_dir
        elif self.edit_type == GraphDialog.edit_patterns:
            directory = self.params.last_patterns_dir

        if directory is None:
            directory = self.params.last_project_dir

        file_path, __ = QFileDialog.getOpenFileName(self, 'Select file',
                                                    directory,
                                                    'Files (*.txt *.inp)')

        if file_path is None or file_path == '':
            return
        else:
            if self.edit_type == GraphDialog.edit_patterns:
                # Save patterns file path in configuration file
                config_file.set_patterns_file_path(file_path)
                Parameters.patterns_file = file_path
            elif self.edit_type == GraphDialog.edit_curves:
                # Save curve file path in configuration file
                config_file.set_curves_file_path(file_path)
                Parameters.curves_file = file_path

        self.read(file_path)

    def read(self, file_path):

        self.lst_list.clear()

        if self.edit_type == self.edit_patterns:
            InpFile.read_patterns(self.params, file_path)
            for pattern_id, pattern in self.params.patterns.items():
                # desc = ' (' + pattern.desc + ')' if pattern.desc is not None else ''
                self.lst_list.addItem(pattern.id)
                self.params.patterns[pattern.id] = pattern

        elif self.edit_type == self.edit_curves:
            InpFile.read_curves(self.params, file_path)
            for curve_id, curve in self.params.curves.items():
                # desc = ' (' + curve.desc + ')' if curve.desc is not None else ''
                self.lst_list.addItem(curve.id)
                self.params.curves[curve.id] = curve

        if self.lst_list.count() > 0:
            self.lst_list.setCurrentRow(0)

    def new_element(self):

        old_ids = []
        if self.edit_type == self.edit_patterns:
            for pattern in self.params.patterns.values():
                old_ids.append(pattern.id)
        elif self.edit_type == self.edit_curves:
            for curve in self.params.curves.values():
                old_ids.append(curve.id)
        self.new_dialog = NewIdDialog(self, old_ids)
        self.new_dialog.exec_()

        new_id = self.new_dialog.get_newid()
        description = self.new_dialog.get_description()
        if new_id is None or description is None:
            return

        if self.edit_type == self.edit_patterns:
            new_pattern = Pattern(new_id, description)
            self.params.patterns[new_pattern.id] = new_pattern
            self.lst_list.addItem(new_pattern.id)
        elif self.edit_type == self.edit_curves:
            curve_type = self.cbo_pump_type.itemData(
                self.cbo_pump_type.currentIndex())
            new_curve = Curve(new_id, curve_type, desc=description)
            self.params.curves[new_curve.id] = new_curve
            self.lst_list.addItem(new_curve.id)

        self.lst_list.setCurrentRow(self.lst_list.count() - 1)

        self.txt_id.setText(new_id)
        self.txt_desc.setText(description)

        # Clear table
        self.clear_table()
        self.static_canvas.axes.clear()

        self.txt_id.setEnabled(True)
        self.txt_desc.setEnabled(True)
        self.btn_save.setEnabled(True)
        self.btn_del.setEnabled(True)
        self.table.setEnabled(True)
        self.table.setEditTriggers(QAbstractItemView.AllEditTriggers)

    def save(self):

        self.need_to_update_graph = False

        # Check for ID
        if not self.txt_id.text():
            QMessageBox.warning(
                self,
                Parameters.plug_in_name,
                u'Please specify the ID.',  # TODO: softcode
                QMessageBox.Ok)
            return

        if self.edit_type == GraphDialog.edit_patterns:
            values = []
            for row in range(self.table.rowCount()):
                item = self.table.item(row, 1)
                if item is not None and item.text() != '':
                    values.append(self.from_item_to_val(item))
                else:
                    values.append('0')

            pattern = Pattern(self.txt_id.text(), self.txt_desc.text(), values)

            old_patterns = self.params.patterns
            old_patterns[pattern.id] = pattern
            self.params.patterns = old_patterns

            self.lst_list.currentItem().setText(pattern.id)

        elif self.edit_type == GraphDialog.edit_curves:

            # Check for ID unique
            xs = []
            ys = []
            for row in range(self.table.rowCount()):
                item_x = self.table.item(row, 0)
                item_y = self.table.item(row, 1)

                if item_x.text().strip() != '' and item_y.text().strip() != '':
                    xs.append(self.from_item_to_val(item_x))
                    ys.append(self.from_item_to_val(item_y))

            curve_type = self.cbo_pump_type.itemData(
                self.cbo_pump_type.currentIndex())
            curve = Curve(self.txt_id.text(), curve_type, self.txt_desc.text())
            for v in range(len(xs)):
                curve.append_xy(xs[v], ys[v])

            old_curves = self.params.curves
            old_curves[curve.id] = curve
            self.params.curves = old_curves

            self.lst_list.currentItem().setText(curve.id)

            # Update GUI
            self.dockwidget.update_curves_combo()

        # self.read()
        self.need_to_update_graph = True

    def clear_table(self):

        self.need_to_update_graph = False
        for r in range(self.table.rowCount()):
            self.table.setItem(r, 0, QTableWidgetItem(None))
            self.table.setItem(r, 1, QTableWidgetItem(None))

        for row in range(self.rows_nr):
            for col in range(self.cols_nr):
                if self.edit_type == self.edit_patterns:
                    if col == 0:
                        item = QTableWidgetItem(str(row))
                        self.table.setItem(row, col, item)
                        item.setFlags(QtCore.Qt.ItemIsSelectable)
                    # elif col == 1 and row == 0:
                    #     item = QTableWidgetItem(str(1))
                    #     self.table.setItem(row, col, item)
                    #     item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)

                # elif self.edit_type == self.edit_curves:
                # if row == 0:
                # item = QTableWidgetItem(str(0))
                # self.table.setItem(row, 0, item)
                # item = QTableWidgetItem(str(1))
                # self.table.setItem(row, 1, item)
                # item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
        self.need_to_update_graph = True

    def del_item(self):
        selected_row = self.lst_list.currentRow()
        name = self.lst_list.currentItem().text()
        if selected_row < 0:
            return

        self.lst_list.takeItem(selected_row)
        if self.lst_list.count() == 0:
            self.txt_id.setEnabled(False)
            self.txt_desc.setEnabled(False)
            self.btn_save.setEnabled(False)
            self.btn_del.setEnabled(False)
            self.table.setEnabled(False)
            self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)

        if self.edit_type == GraphDialog.edit_curves:
            del self.params.curves[name]
            # Update GUI
            self.dockwidget.update_curves_combo()
        elif self.edit_type == GraphDialog.edit_patterns:
            del self.params.patterns[name]
            # Update GUI
            self.dockwidget.update_patterns_combo()

    def data_changed(self):

        if self.need_to_update_graph:
            self.update_graph()

    def update_table_headers(self):
        if self.edit_type == self.edit_patterns:
            self.x_label = 'Time period'
            self.y_label = 'Multiplier'
        elif self.edit_type == self.edit_curves:
            cbo_data = self.cbo_pump_type.itemData(
                self.cbo_pump_type.currentIndex())
            if cbo_data == Curve.type_efficiency:
                self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']'
                self.y_label = 'Efficiency ' + '[' + self.params.options.units_deltaz[
                    self.params.options.units] + ']'
            if cbo_data == Curve.type_headloss:
                self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']'
                self.y_label = 'Headloss ' + '[' + self.params.options.units_deltaz[
                    self.params.options.units] + ']'
            if cbo_data == Curve.type_pump:
                self.x_label = 'Flow ' + '[' + self.params.options.flow_units + ']'
                self.y_label = 'Head ' + '[' + self.params.options.units_deltaz[
                    self.params.options.units] + ']'
            if cbo_data == Curve.type_volume:
                self.x_label = 'Height ' + '[' + self.params.options.flow_units + ']'
                self.y_label = 'Volume ' + '[' + self.params.options.units_deltaz[
                    self.params.options.units] + ']'

        self.table.setHorizontalHeaderLabels([self.x_label,
                                              self.y_label])  # TODO: softcode

    def update_graph(self):

        if not self.need_to_update_graph:
            return

        xs = []
        ys = []

        for row in range(self.table.rowCount()):
            item = self.table.item(row, 0)
            x = self.from_item_to_val(item)
            item = self.table.item(row, 1)
            y = self.from_item_to_val(item)

            if x is not None:
                xs.append(float(x))
            if y is not None:
                ys.append(float(y))

        if len(xs) == 0 or len(ys) == 0:
            self.static_canvas.clear()
            return

        xys_t = list(zip(xs, ys))
        xys_t.sort()

        xys = list(zip(*xys_t))
        xs = xys[0]
        ys = xys[1]

        if self.edit_type == self.edit_patterns:
            y_axis_label = 'Mult. avg.: ' + '{0:.2f}'.format(
                (numpy.average(ys)))
            self.static_canvas.draw_bars_graph(
                ys,
                time_period=self.params.times.pattern_timestep,
                y_axes_label=y_axis_label)

        elif self.edit_type == self.edit_curves:

            # Account for different types of curves
            cbo_data = self.cbo_pump_type.itemData(
                self.cbo_pump_type.currentIndex())

            series_length = min(len(xs), len(ys))

            # Need to account for different types of curves
            if cbo_data == Curve.type_efficiency or cbo_data == Curve.type_headloss or cbo_data == Curve.type_volume:
                self.static_canvas.draw_line_graph(xs[:series_length],
                                                   ys[:series_length],
                                                   self.x_label, self.y_label)

            elif cbo_data == Curve.type_pump:
                if series_length == 1 or series_length == 3:
                    if series_length == 1:
                        # 3 curve points
                        curve_xs = [0, xs[0], xs[0] * 2]
                        curve_ys = [ys[0] * 1.33, ys[0], 0]
                        # y = a * x^2 + b * x + c

                    elif series_length == 3:
                        # 3 curve points
                        curve_xs = [xs[0], xs[1], xs[2]]
                        curve_ys = [ys[0], ys[1], ys[2]]

                    (a, b, c) = numpy.polyfit(curve_xs, curve_ys, 2)

                    # Create a few interpolated values
                    interp_xs = []
                    interp_ys = []
                    n_vals = 30
                    for v in range(n_vals + 1):
                        x = (curve_xs[2] - curve_xs[0]) / n_vals * v
                        interp_xs.append(x)
                        y = a * x**2 + b * x + c
                        interp_ys.append(y)

                    self.static_canvas.draw_line_graph(interp_xs, interp_ys,
                                                       self.x_label,
                                                       self.y_label)

                else:
                    self.static_canvas.draw_line_graph(xs[:series_length],
                                                       ys[:series_length],
                                                       self.x_label,
                                                       self.y_label)

    def from_item_to_val(self, item):

        if item is None:
            value = None
        else:
            value = item.text()
        try:
            value = float(value)
            value = max(value, 0)

        except:
            value = None

        return value
class 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 DistrictSelectionDialog(QDialog):
    """
    A dialog used for selecting from available districts
    :param district_registry: associated registry of available
    districts to show
    """

    def __init__(self, district_registry, parent=None):
        super().__init__(parent)

        self.district_registry = district_registry

        self.setWindowTitle(self.tr('Select New {}').format(
            district_registry.type_string_title()))
        layout = QVBoxLayout()
        self.recent_label = QLabel(self.tr('Recently used {}').format(
            district_registry.type_string_sentence_plural()))
        layout.addWidget(self.recent_label)

        self.recent_list = QListWidget()
        self.recent_list.setMaximumHeight(100)
        for d in district_registry.recent_districts_list():
            item = QListWidgetItem(self.district_registry.get_district_title(d))
            item.setData(Qt.UserRole, d)
            self.recent_list.addItem(item)
        layout.addWidget(self.recent_list, 0)

        self.available_label = QLabel(self.tr('Available {}').format(
            district_registry.type_string_sentence_plural()
        ))
        layout.addWidget(self.available_label)
        self.search = QgsFilterLineEdit()
        self.search.setShowSearchIcon(True)
        self.search.setPlaceholderText(self.tr('Search for {}').format(
            district_registry.type_string_sentence()))
        self.search.textChanged.connect(self.filter_changed)
        layout.addWidget(self.search)

        self.list = QListWidget()
        for title, code in district_registry.district_titles().items():
            item = QListWidgetItem(title)
            item.setData(Qt.UserRole, code)
            self.list.addItem(item)

        layout.addWidget(self.list, 10)

        button_box = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        layout.addWidget(button_box)
        button_box.rejected.connect(self.reject)
        button_box.accepted.connect(self.accept)

        if self.district_registry.flags() & DistrictRegistry.FLAG_ALLOWS_SPATIAL_SELECT:
            self.select_from_map_button = button_box.addButton(
                self.tr("Select from Map"), QDialogButtonBox.ActionRole)
            self.select_from_map_button.clicked.connect(self.pick_from_map)
        else:
            self.select_from_map_button = None
        self.chose_pick_from_map = False

        self.setLayout(layout)

        self.recent_list.itemSelectionChanged.connect(
            self.recent_list_item_selected)
        self.list.itemSelectionChanged.connect(
            self.list_item_selected)
        self.recent_list.itemDoubleClicked.connect(
            self.accept)
        self.list.itemDoubleClicked.connect(
            self.accept)

        # select most recently used district by default
        if self.recent_list.count() > 0:
            self.recent_list.item(0).setSelected(True)

    def recent_list_item_selected(self):
        """
        Handles a selection made in the recent district list
        """
        if self.recent_list.selectedItems():
            self.list.clearSelection()

    def list_item_selected(self):
        """
        Handles a selection made in the complete district list
        """
        if self.list.selectedItems():
            self.recent_list.clearSelection()

    def set_selected_district(self, district):
        """
        Sets the district selected in the dialog
        :param district: district to select
        """
        for i in range(self.list.count()):
            if self.list.item(i).data(Qt.UserRole) == district:
                self.list.item(i).setSelected(True)
                return

    def selected_district(self):
        """
        Returns the district selected in the dialog
        """
        if self.recent_list.selectedItems():
            return self.recent_list.selectedItems()[0].data(Qt.UserRole)
        elif self.list.selectedItems():
            return self.list.selectedItems()[0].data(Qt.UserRole)

        return None

    def accept(self):  # pylint: disable=missing-docstring
        self.district_registry.push_recent_district(self.selected_district())
        super().accept()

    def filter_changed(self, filter_text):
        """
        Handles search filter changes
        """
        for i in range(self.list.count()):
            item = self.list.item(i)
            item.setHidden(filter_text.upper() not in item.text().upper())

    def pick_from_map(self):
        """
        Triggered when a user selects the "Select from Map" option
        """
        self.chose_pick_from_map = True
        self.reject()
Beispiel #11
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))
Beispiel #12
0
class AnnotationManager:
    def __init__(self, iface):
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(os.path.dirname(__file__), 'i18n',
                                   'annotationManager_{}.qm'.format(locale))

        self.translator = None
        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

        if qVersion() > '4.3.3':
            QCoreApplication.installTranslator(self.translator)

        self.iface = iface
        self.iface.projectRead.connect(self.projectOpen)

        self.dock = QDockWidget(self.tr('Annotations'))
        self.manager = QWidget()
        toolbar = QToolBar()

        self.annotationList = QListWidget()
        self.annotationList.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.annotationList.itemSelectionChanged.connect(self.selectAnnotation)
        self.annotationList.itemChanged.connect(self.checkItem)
        action_refresh = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionDraw.png'),
            self.tr('Refresh the annotations list'), self.manager)
        action_refresh.triggered.connect(self.refreshAnnotations)
        action_remove = QAction(
            QIcon(
                ':/plugins/annotationManager/resources/mActionRemoveAnnotation.png'
            ), self.tr('Remove the selected annotation'), self.manager)
        action_remove.triggered.connect(self.removeAnnotation)

        viewMenu = QMenu()
        action_showAll = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'),
            self.tr('Show all annotations'), self.manager)
        action_showAll.triggered.connect(self.showAll)
        action_hideAll = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionHideAll.png'),
            self.tr('Hide all annotations'), self.manager)
        action_hideAll.triggered.connect(self.hideAll)
        action_showAllSelected = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'),
            self.tr('Show all selected annotations'), self.manager)
        action_showAllSelected.triggered.connect(self.showAllSelected)
        action_hideAllSelected = QAction(
            QIcon(':/plugins/annotationManager/resources/mActionHideAll.png'),
            self.tr('Hide all selected annotations'), self.manager)
        action_hideAllSelected.triggered.connect(self.hideAllSelected)
        viewMenu.addAction(action_showAll)
        viewMenu.addAction(action_hideAll)
        viewMenu.addAction(action_showAllSelected)
        viewMenu.addAction(action_hideAllSelected)
        viewButton = QToolButton()
        viewButton.setIcon(
            QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'))
        viewButton.setPopupMode(2)
        viewButton.setMenu(viewMenu)

        toolbar.addAction(action_refresh)
        toolbar.addAction(action_remove)
        toolbar.addWidget(viewButton)
        toolbar.setIconSize(QSize(16, 16))

        p1_vertical = QVBoxLayout()
        p1_vertical.setContentsMargins(0, 0, 0, 0)
        p1_vertical.addWidget(toolbar)
        p1_vertical.addWidget(self.annotationList)
        self.manager.setLayout(p1_vertical)

        self.dock.setWidget(self.manager)
        self.dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                  | Qt.RightDockWidgetArea)
        self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock)

        self.rb = QgsRubberBand(self.iface.mapCanvas(),
                                QgsWkbTypes.PolygonGeometry)

        self.project = QgsProject.instance()
        self.annotationManager = self.project.annotationManager()
        self.annotationManager.annotationAdded.connect(self.refreshAnnotations)
        self.annotationManager.annotationRemoved.connect(
            self.refreshAnnotations)

    def checkItem(self, item):
        index = self.annotationList.row(item)
        if item.checkState() == Qt.Checked:
            self.annotationManager.annotations()[index].setVisible(True)
        else:
            self.annotationManager.annotations()[index].setVisible(False)
            if item.isSelected():
                item.setSelected(False)
                self.rb.reset(QgsWkbTypes.PolygonGeometry)

    def selectAnnotation(self):
        self.rb.reset(QgsWkbTypes.PolygonGeometry)
        self.rb.setColor(QColor(0, 0, 255, 128))
        for item in self.annotationList.selectedItems():
            index = self.annotationList.row(item)
            mapTool = QgsMapTool(self.iface.mapCanvas())
            point = mapTool.toCanvasCoordinates(
                self.annotationManager.annotations()[index].mapPosition())
            pt1 = mapTool.toMapCoordinates(
                QPoint(point.x() - 10,
                       point.y() - 10))
            pt2 = mapTool.toMapCoordinates(
                QPoint(point.x() + 10,
                       point.y() + 10))
            rect = QgsRectangle(pt1, pt2)
            poly = QgsGeometry().fromRect(rect)
            self.rb.addGeometry(poly, None)

    def showAll(self):
        count = self.annotationList.count()
        for i in range(count):
            self.annotationList.item(i).setCheckState(Qt.Checked)

    def hideAll(self):
        count = self.annotationList.count()
        for i in range(count):
            self.annotationList.item(i).setCheckState(Qt.Unchecked)

    def showAllSelected(self):
        for item in self.annotationList.selectedItems():
            item.setCheckState(Qt.Checked)

    def hideAllSelected(self):
        for item in self.annotationList.selectedItems():
            item.setCheckState(Qt.Unchecked)

    def unload(self):
        del self.dock

    def tr(self, message):
        return QCoreApplication.translate('AnnotationManager', message)

    def refreshAnnotationTitle(self, annotation=None):
        if annotation is None:
            annotation = self.project.annotationManager().sender()
        item = self.annotationList.item(
            self.annotationManager.annotations().index(annotation))
        title = 'Annotation'
        if isinstance(annotation, QgsTextAnnotation):
            title = annotation.document().toPlainText().split('\n')[0]
            if len(title) > 40:
                title = title[:40] + '(...)'
        item.setText(title)

    def refreshAnnotations(self):
        self.annotationList.clearSelection()
        self.annotationList.clear()
        for annotation in self.annotationManager.annotations():
            item = QListWidgetItem()
            annotation.appearanceChanged.connect(self.refreshAnnotationTitle)
            if annotation.isVisible():
                item.setCheckState(Qt.Checked)
            else:
                item.setCheckState(Qt.Unchecked)
            item.setFlags(item.flags())
            self.annotationList.addItem(item)
            self.refreshAnnotationTitle(annotation)

    def removeAnnotation(self):
        if len(self.annotationList.selectedItems()) > 0:
            self.annotationManager.annotationRemoved.disconnect()
            trash = []
            for item in self.annotationList.selectedItems():
                index = self.annotationList.row(item)
                trash.append(self.annotationManager.annotations()[index])
            while trash:
                self.annotationManager.removeAnnotation(trash.pop())
            self.refreshAnnotations()
            self.annotationManager.annotationRemoved.connect(
                self.refreshAnnotations)

    def projectOpen(self):
        self.refreshAnnotations()

    def initGui(self):
        self.refreshAnnotations()
Beispiel #13
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))
Beispiel #14
0
class DataSelector(QDialog):
    #def select_data_to_add(viewer, feature_id, config_list):
    def __init__(self, viewer, feature_id, feature_name, config_list, config):
        QDialog.__init__(self)

        self.__viewer = viewer
        self.__feature_id = feature_id
        self.__feature_name = feature_name
        self.__config_list = config_list
        self.__config = config

        vbox = QVBoxLayout()

        btn = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn.accepted.connect(self.accept)
        btn.rejected.connect(self.reject)

        self.__list = QListWidget()
        self.__list.setSelectionMode(QAbstractItemView.ExtendedSelection)

        hbox = QHBoxLayout()
        lbl = QLabel("Sub selection")
        self.__sub_selection_combo = QComboBox()
        self.__sub_selection_combo.setEnabled(False)
        hbox.addWidget(lbl)
        hbox.addWidget(self.__sub_selection_combo)

        from_elsewhere_btn = QPushButton("Select another station")

        self.__title_label = QLabel()

        hbox2 = QHBoxLayout()
        hbox2.addWidget(self.__title_label)
        hbox2.addWidget(from_elsewhere_btn)

        vbox.addLayout(hbox2)
        vbox.addWidget(self.__list)
        vbox.addLayout(hbox)
        vbox.addWidget(btn)

        self.__list.itemSelectionChanged.connect(self.on_selection_changed)
        self.__sub_selection_combo.currentIndexChanged[str].connect(
            self.on_combo_changed)
        from_elsewhere_btn.clicked.connect(self.on_from_elsewhere_clicked)

        self.setLayout(vbox)
        self.setWindowTitle("Choose the data to add")
        self.resize(400, 200)

        self._populate_list()
        self.set_title(feature_name)

    def set_title(self, title):
        self.__title_label.setText("Station: {}".format(title))

    def _populate_list(self):
        self.__list.clear()
        for cfg in self.__config_list:
            if cfg["type"] in ("continuous", "instantaneous"):
                uri, provider = cfg["source"]
                # check number of features for this station
                data_l = QgsVectorLayer(uri, "data_layer", provider)
                req = QgsFeatureRequest()
                req.setFilterExpression("{}={}".format(
                    cfg["feature_ref_column"], self.__feature_id))
                if len(list(data_l.getFeatures(req))) == 0:
                    continue

                if cfg.get("feature_filter_type") == "unique_data_from_values":
                    # get unique filter values
                    cfg["filter_unique_values"] = sorted(
                        list(
                            set([
                                f[cfg["feature_filter_column"]]
                                for f in data_l.getFeatures(req)
                            ])))

            elif cfg["type"] == "image":
                if not self.__viewer.has_imagery_data(cfg, self.__feature_id):
                    continue

            item = QListWidgetItem(cfg["name"])
            item.setData(Qt.UserRole, cfg)
            self.__list.addItem(item)

    def accept(self):
        for item in self.__list.selectedItems():
            # now add the selected configuration
            cfg = item.data(Qt.UserRole)
            if cfg["type"] in ("continuous", "instantaneous"):
                uri, provider = cfg["source"]
                data_l = QgsVectorLayer(uri, "data_layer", provider)
                req = QgsFeatureRequest()
                filter_expr = "{}={}".format(cfg["feature_ref_column"],
                                             self.__feature_id)
                req.setFilterExpression(filter_expr)
                print("Layer", uri, "Filter", filter_expr)

                title = cfg["name"]

                if cfg["type"] == "instantaneous":
                    if "filter_value" in cfg:
                        filter_expr += " and {}='{}'".format(
                            cfg["feature_filter_column"], cfg["filter_value"])
                        title = cfg["filter_value"]
                    else:
                        title = cfg["name"]

                    f = None
                    for f in data_l.getFeatures(req):
                        pass
                    if f is None:
                        return
                    uom = cfg[
                        "uom"] if "uom" in cfg else "@" + cfg["uom_column"]
                    data = LayerData(data_l,
                                     cfg["event_column"],
                                     cfg["value_column"],
                                     filter_expression=filter_expr,
                                     uom=uom)
                    uom = data.uom()

                if cfg["type"] == "continuous":
                    uom = cfg["uom"]
                    fids = [f.id() for f in data_l.getFeatures(req)]
                    data = FeatureData(
                        data_l,
                        cfg["values_column"],
                        feature_ids=fids,
                        x_start_fieldname=cfg["start_measure_column"],
                        x_delta_fieldname=cfg["interval_column"])

                if hasattr(self.__viewer, "add_data_column"):
                    self.__viewer.add_data_column(
                        data, title, uom, station_name=self.__feature_name)
                if hasattr(self.__viewer, "add_data_row"):
                    self.__viewer.add_data_row(
                        data, title, uom, station_name=self.__feature_name)
            elif cfg["type"] == "image":
                self.__viewer.add_imagery_from_db(cfg, self.__feature_id)

        QDialog.accept(self)

    def on_selection_changed(self):
        self.__sub_selection_combo.clear()
        self.__sub_selection_combo.setEnabled(False)
        for item in self.__list.selectedItems():
            cfg = item.data(Qt.UserRole)
            if "filter_unique_values" in cfg:
                for v in cfg["filter_unique_values"]:
                    self.__sub_selection_combo.addItem(v)
            if "filter_value" in cfg:
                self.__sub_selection_combo.setCurrentIndex(
                    self.__sub_selection_combo.findText(cfg["filter_value"]))
            self.__sub_selection_combo.setEnabled(True)
            return

    def on_combo_changed(self, text):
        for item in self.__list.selectedItems():
            cfg = item.data(Qt.UserRole)
            cfg["filter_value"] = text
            item.setData(Qt.UserRole, cfg)
            return

    def on_from_elsewhere_clicked(self):
        layer_config = get_layer_config()
        from qgis.utils import iface
        if iface.activeLayer() is None:
            iface.messageBar().pushMessage(u"Please select an active layer",
                                           QgsMessageBar.CRITICAL)
            return
        uri, provider = iface.activeLayer().source(), iface.activeLayer(
        ).dataProvider().name()
        if (uri, provider) not in layer_config:
            iface.messageBar().pushMessage(u"Unconfigured layer",
                                           QgsMessageBar.CRITICAL)
            return

        config = layer_config[(uri, provider)]
        iface.messageBar().pushMessage(
            u"Please select a feature on the active layer")
        self.__tool = FeatureSelectionTool(iface.mapCanvas(),
                                           iface.activeLayer())
        iface.mapCanvas().setMapTool(self.__tool)
        self.__tool.featureSelected.connect(self.on_other_station_selected)

        self.setModal(False)
        self.setWindowState(Qt.WindowMinimized)

    def on_other_station_selected(self, selected):
        self.__feature_id = selected[0].id()
        self._populate_list()
        self.__feature_name = selected[0][self.__config["name_column"]]
        self.set_title(self.__feature_name)
        self.setModal(True)
        self.setWindowState(Qt.WindowActive)
Beispiel #15
0
class MultiSelectComboBox(QComboBox):

    SEARCH_BAR_IDX = 0
    SELECT_ALL_IDX = 1
    RESERVED_IDXS_COUNT = 2
    selection_changed = pyqtSignal()
    item_was_clicked = pyqtSignal(str, bool)

    def __init__(self, parent, mono=False):

        super().__init__(parent)
        self.mono = mono
        if self.mono:
            return

        self.mlist = QListWidget(self)
        self.line_edit = ComplexLineEdit(self)

        self.clear()

        self.line_edit.setReadOnly(True)
        self.line_edit.installEventFilter(self)

        self.setModel(self.mlist.model())
        self.setView(self.mlist)
        self.view().setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setLineEdit(self.line_edit)

        # NOTE: this is necessary to handle the case in which an item in the
        # list is clicked to its right part, outside the text
        self.activated.connect(self.itemClicked)

    def on_select_all_toggled(self, state):
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if self.search_bar.text().lower() in checkbox.text().lower():
                checkbox.setChecked(state)

    def itemClicked(self, idx):
        if self.mono:
            self.item_was_clicked.emit(self.currentText(), True)
            return super().itemClicked(idx)
        if idx not in [self.SEARCH_BAR_IDX, self.SELECT_ALL_IDX]:
            checkbox = self.mlist.itemWidget(self.mlist.item(idx))
            checkbox.setChecked(not checkbox.isChecked())
            self.item_was_clicked.emit(checkbox.text(), checkbox.isChecked())

    def hidePopup(self):
        if self.mono:
            return super().hidePopup()
        width = self.width()
        height = self.mlist.height()
        x = (QCursor.pos().x()
             - self.mapToGlobal(self.geometry().topLeft()).x()
             + self.geometry().x())
        y = (QCursor.pos().y()
             - self.mapToGlobal(self.geometry().topLeft()).y()
             + self.geometry().y())
        if (x >= 0 and x <= width and y >= self.height()
                and y <= height + self.height()):
            # Item was clicked, do not hide popup
            pass
        else:
            super().hidePopup()

    def stateChanged(self, state):
        if self.mono:
            return super().stateChanged(state)
        # NOTE: not using state
        selected_data = ""
        separator = "; "
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if checkbox.isChecked():
                selected_data += checkbox.text() + separator
        if selected_data.endswith(separator):
            selected_data = selected_data[:-len(separator)]
        if selected_data:
            self.line_edit.setText(selected_data)
        else:
            self.line_edit.clear()
        self.line_edit.setToolTip(selected_data)
        self.selection_changed.emit()

    def on_checkbox_stateChanged(self, text, state):
        self.item_was_clicked.emit(text, state)

    def add_selected_items(self, items):
        if self.mono:
            return super().addItems(items)
        self.addItems(items, selected=True)

    def add_unselected_items(self, items):
        if self.mono:
            return super().addItems(items)
        self.addItems(items, selected=False)

    def set_selected_items(self, items):
        if self.mono:
            return
        self.set_items_selection(items, True)

    def set_unselected_items(self, items):
        if self.mono:
            return
        self.set_items_selection(items, False)

    def set_idxs_selection(self, idxs, checked=True):
        if self.mono:
            # NOTE: this method is not expected to be used for mono selectors.
            # Anyway, we are making it possible to use it, and the selector
            # will point to the first element of idxs
            return self.setCurrentIndex(idxs[0])
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if i - self.RESERVED_IDXS_COUNT in idxs:
                checkbox.setChecked(checked)
            else:
                checkbox.setChecked(not checked)

    def set_items_selection(self, items, checked):
        if self.mono:
            return
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if checkbox.text() in items:
                checkbox.setChecked(checked)
            else:
                checkbox.setChecked(not checked)

    def get_selected_items(self):
        items = []
        if self.mono:
            if super().currentText():
                return [super().currentText()]
            else:
                return []
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if checkbox.isChecked():
                items.append(checkbox.text())
        return items

    def get_unselected_items(self):
        items = []
        if self.mono:
            selected_text = self.currentText()
            for i in range(self.count()):
                item_text = self.itemText(i)
                if item_text and item_text != selected_text:
                    items.append(item_text)
            return items
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if not checkbox.isChecked():
                items.append(checkbox.text())
        return items

    def addItem(self, text, user_data=None, selected=False):
        if self.mono:
            return super().addItem(text, user_data)
        # NOTE: not using user_data
        list_widget_item = QListWidgetItem(self.mlist)
        checkbox = QCheckBox(self)
        checkbox.setText(text)
        self.mlist.addItem(list_widget_item)
        self.mlist.setItemWidget(list_widget_item, checkbox)
        checkbox.stateChanged.connect(self.stateChanged)
        checkbox.stateChanged.connect(
            lambda state: self.on_checkbox_stateChanged(
                checkbox.text(), state))
        checkbox.setChecked(selected)

    def currentText(self):
        if self.mono:
            return super().currentText()
        return self.line_edit.current_text()

    def addItems(self, texts, selected=False):
        if self.mono:
            return super().addItems(texts)
        for text in texts:
            self.addItem(text, selected=selected)

    def count(self):
        if self.mono:
            return super().count()
        # do not count search bar and toggle select all
        count = self.mlist.count() - self.RESERVED_IDXS_COUNT
        if count < 0:
            count = 0
        return count

    def selected_count(self):
        if self.mono:
            if self.currentIndex() == -1:
                return 0
            else:
                return 1
        return len(self.get_selected_items())

    def onSearch(self, search_str):
        self.setMaxVisibleItems(min(10, self.mlist.count()))
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            if search_str.lower() in checkbox.text().lower():
                self.mlist.item(i).setHidden(False)
            else:
                self.mlist.item(i).setHidden(True)
        # NOTE: hack to fix problem when you first filter and have few items,
        # then filter again and have more items
        self.hidePopup()
        self.showPopup()
        # NOTE: hide/show would lose focus from the search bar
        self.search_bar.setFocus()

    def set_search_bar_placeholder_text(self, text):
        self.search_bar.setPlaceholderText(text)

    def clear(self):
        if self.mono:
            return super().clear()
        self.mlist.clear()
        self.search_bar = QLineEdit(self)
        self.search_item = QListWidgetItem(self.mlist)
        self.search_bar.setPlaceholderText("Search...")
        self.search_bar.setClearButtonEnabled(True)
        self.mlist.addItem(self.search_item)
        self.mlist.setItemWidget(self.search_item, self.search_bar)
        self.toggle_select_item = QListWidgetItem(self.mlist)
        self.toggle_ckb = QCheckBox(self)
        self.toggle_ckb.setText('Select/unselect all')
        self.mlist.addItem(self.toggle_select_item)
        self.mlist.setItemWidget(self.toggle_select_item, self.toggle_ckb)
        self.toggle_ckb.stateChanged.connect(self.on_select_all_toggled)
        self.search_bar.textChanged[str].connect(self.onSearch)

    def wheelEvent(self, wheel_event):
        if self.mono:
            return super().wheelEvent(wheel_event)
        # do not handle the wheel event
        pass

    def eventFilter(self, obj, event):
        if self.mono:
            return super().eventFilter(obj, event)
        # this is handled by ComplexLineEdit
        return False

    def keyPressEvent(self, event):
        if self.mono:
            return super().keyPressEvent(event)
        # do not handle key event
        pass

    # def setCurrentText(self, text):
    #     pass

    def setCurrentText(self, texts):
        if self.mono:
            # NOTE: using the first text
            return super().setCurrentText(texts[0])
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            checkbox_str = checkbox.text()
            if checkbox_str in texts:
                checkbox.setChecked(True)

    def resetSelection(self):
        if self.mono:
            return super().setCurrentIndex(-1)
        for i in range(self.RESERVED_IDXS_COUNT, self.mlist.count()):
            checkbox = self.mlist.itemWidget(self.mlist.item(i))
            checkbox.setChecked(False)
Beispiel #16
0
class PlotLayoutItemWidget(QgsLayoutItemBaseWidget):
    """
    Configuration widget for layout plot items
    """
    def __init__(self, parent, layout_object):
        super().__init__(parent, layout_object)
        self.plot_item = layout_object
        self.message_bar = None

        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)

        plot_tools_layout = QHBoxLayout()

        plot_add_button = QPushButton()
        plot_add_button.setIcon(GuiUtils.get_icon('symbologyAdd.svg'))
        plot_add_button.setToolTip('Add a new plot')
        plot_tools_layout.addWidget(plot_add_button)
        plot_add_button.clicked.connect(self.add_plot)

        plot_remove_button = QPushButton()
        plot_remove_button.setIcon(GuiUtils.get_icon('symbologyRemove.svg'))
        plot_remove_button.setToolTip('Remove selected plot')
        plot_tools_layout.addWidget(plot_remove_button)
        plot_remove_button.clicked.connect(self.remove_plot)

        plot_duplicate_button = QPushButton()
        plot_duplicate_button.setIcon(
            GuiUtils.get_icon('mActionDuplicateLayer.svg'))
        plot_duplicate_button.setToolTip('Duplicates the selected plot')
        plot_tools_layout.addWidget(plot_duplicate_button)
        plot_duplicate_button.clicked.connect(self.duplicate_plot)

        plot_move_up_button = QPushButton()
        plot_move_up_button.setIcon(GuiUtils.get_icon('mActionArrowUp.svg'))
        plot_move_up_button.setToolTip('Move selected plot up')
        plot_tools_layout.addWidget(plot_move_up_button)
        plot_move_up_button.clicked.connect(self.move_up_plot)

        plot_move_down_button = QPushButton()
        plot_move_down_button.setIcon(
            GuiUtils.get_icon('mActionArrowDown.svg'))
        plot_move_down_button.setToolTip('Move selected plot down')
        plot_tools_layout.addWidget(plot_move_down_button)
        plot_move_down_button.clicked.connect(self.move_down_plot)

        vl.addLayout(plot_tools_layout)

        self.plot_list = QListWidget()
        self.plot_list.setSelectionMode(QListWidget.SingleSelection)
        self.plot_list.doubleClicked.connect(self.show_properties)
        vl.addWidget(self.plot_list)
        self.populate_plot_list()

        plot_properties_button = QPushButton(self.tr('Setup Selected Plot'))
        vl.addWidget(plot_properties_button)
        plot_properties_button.clicked.connect(self.show_properties)

        self.panel = None
        self.setPanelTitle(self.tr('Plot Properties'))
        self.item_properties_widget = QgsLayoutItemPropertiesWidget(
            self, layout_object)
        vl.addWidget(self.item_properties_widget)
        self.setLayout(vl)

    def populate_plot_list(self):
        """
        Clears and re-populates the plot list widget. The currently selection is retained
        """
        selected_index = self.plot_list.currentRow()
        self.plot_list.clear()
        for setting in self.plot_item.plot_settings:
            plot_type = setting.plot_type if setting.plot_type is not None else '(not set)'
            legend_title = ('[' + setting.properties.get('name') + ']') \
                if setting.properties.get('name', '') != '' else ''
            self.plot_list.addItem(plot_type + ' ' + legend_title)

        # select index within range [0, len(plot_settings)-1]
        selected_index = max(
            0, min(len(self.plot_item.plot_settings) - 1, selected_index))
        self.plot_list.setCurrentRow(selected_index,
                                     QItemSelectionModel.SelectCurrent)

    def add_plot(self):
        """
         Adds a new plot and updates the plot list and the plot item
        """
        self.plot_item.add_plot()
        self.populate_plot_list()
        self.plot_item.refresh()

    def duplicate_plot(self):
        """
         Duplicates an existing plot and updates the plot list and the plot item
        """

        selected_plot_index = self.plot_list.currentRow()
        if selected_plot_index < 0:
            return

        self.plot_item.duplicate_plot(selected_plot_index)
        self.populate_plot_list()
        self.plot_item.refresh()

    def remove_plot(self):
        """
        Removes the selected plot and updates the plot list and the plot item
        """
        selected_index = self.plot_list.currentRow()
        if selected_index < 0:
            return

        self.plot_item.remove_plot(selected_index)
        self.populate_plot_list()
        self.plot_item.refresh()

    def move_up_plot(self):
        """
        Moves the selected plot up and updates the plot list and the plot item
        """
        selected_index = self.plot_list.currentRow()
        if selected_index <= 0:
            return

        item = self.plot_item.plot_settings.pop(selected_index)
        self.plot_item.plot_settings.insert(selected_index - 1, item)
        self.plot_list.setCurrentRow(selected_index - 1,
                                     QItemSelectionModel.SelectCurrent)
        self.populate_plot_list()
        self.plot_item.refresh()

    def move_down_plot(self):
        """
        Moves the selected plot down and updates the plot list and the plot item
        """
        selected_index = self.plot_list.currentRow()
        if selected_index >= len(self.plot_item.plot_settings) - 1:
            return

        item = self.plot_item.plot_settings.pop(selected_index)
        self.plot_item.plot_settings.insert(selected_index + 1, item)
        self.plot_list.setCurrentRow(selected_index + 1,
                                     QItemSelectionModel.SelectCurrent)
        self.populate_plot_list()
        self.plot_item.refresh()

    def show_properties(self):
        """
        Shows the plot properties panel
        """
        selected_plot_index = self.plot_list.currentRow()
        if selected_plot_index < 0:
            return

        self.panel = DataPlotlyPanelWidget(
            mode=DataPlotlyPanelWidget.MODE_LAYOUT,
            message_bar=self.message_bar)

        # not quite right -- we ideally want to also add the source layer scope into the context given by plot item,
        # but that causes a hard lock in the Python GIL (because PyQt doesn't release the GIL when creating the menu
        # for the property override buttons). Nothing much we can do about that here (or in QGIS,
        # it's a Python/PyQt limitation)
        self.panel.registerExpressionContextGenerator(self.plot_item)
        self.panel.set_print_layout(self.plot_item.layout())

        self.panel.linked_map_combo.blockSignals(True)
        self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
        self.panel.linked_map_combo.blockSignals(False)

        self.panel.linked_map_combo.itemChanged.connect(
            self.linked_map_changed)

        self.panel.set_settings(
            self.plot_item.plot_settings[selected_plot_index])
        # self.panel.set_settings(self.layoutItem().plot_settings)
        self.openPanel(self.panel)
        self.panel.widgetChanged.connect(self.update_item_settings)
        self.panel.panelAccepted.connect(self.set_item_settings)

    def update_item_settings(self):
        """
        Updates the plot item without dismissing the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.plot_list.currentRow(),
                                         self.panel.get_settings())
        self.populate_plot_list()
        self.plot_item.update()

    def set_item_settings(self):
        """
        Updates the plot item based on the settings from the properties panel
        """
        if not self.panel:
            return

        self.plot_item.set_plot_settings(self.plot_list.currentRow(),
                                         self.panel.get_settings())
        self.populate_plot_list()
        self.panel = None
        self.plot_item.update()

    def linked_map_changed(self, linked_map):
        """
        Triggered when the linked map is changed
        """
        self.plot_item.set_linked_map(linked_map)
        self.plot_item.update()

    def setNewItem(self, item):  # pylint: disable=missing-docstring
        if item.type() != ITEM_TYPE:
            return False

        self.plot_item = item
        self.item_properties_widget.setItem(item)
        self.populate_plot_list()

        if self.panel is not None:
            self.panel.set_settings(self.plot_item.plot_settings[0])

            self.panel.linked_map_combo.blockSignals(True)
            self.panel.linked_map_combo.setItem(self.plot_item.linked_map)
            self.panel.linked_map_combo.blockSignals(False)

        return True

    def setDesignerInterface(self, iface):  # pylint: disable=missing-docstring
        super().setDesignerInterface(iface)
        self.message_bar = iface.messageBar()
        if self.panel:
            self.panel.message_bar = self.message_bar
Beispiel #17
0
class TreeSettingItem(QTreeWidgetItem):
    def __init__(self, parent, tree, name, value, action=None):
        QTreeWidgetItem.__init__(self, parent)
        self.parent = parent
        self.tree = tree
        self.name = name
        self._value = value
        self.combo = None
        self.list = None
        self.setText(0, name)
        widget = None
        if isinstance(value, QgsColorButton):
            widget = value
        elif isinstance(value, bool):
            if value:
                self.setCheckState(1, Qt.Checked)
            else:
                self.setCheckState(1, Qt.Unchecked)
        elif isinstance(value, tuple):
            self.combo = QComboBox()
            self.combo.setSizeAdjustPolicy(0)
            for option in value:
                self.combo.addItem(option)
            widget = self.combo
        elif isinstance(value, list):
            self.list = QListWidget()
            self.list.setSizeAdjustPolicy(0)
            self.list.setSelectionMode(QListWidget.MultiSelection)
            for option in value:
                self.list.addItem(option)
            widget = self.list
        else:
            self.setText(1, unicode(value))

        if action:
            layout = QHBoxLayout()
            layout.setMargin(0)
            if widget:
                layout.addWidget(widget)
            button = QToolButton()
            button.setDefaultAction(action)
            button.setText(action.text())
            layout.addWidget(button)
            layout.addStretch(1)
            widget = QWidget()
            widget.setLayout(layout)

        if widget:
            self.tree.setItemWidget(self, 1, widget)

    def setValue(self, value):
        if isinstance(value, bool):
            if value:
                self.setCheckState(1, Qt.Checked)
            else:
                self.setCheckState(1, Qt.Unchecked)
        elif self.combo:
            index = self.combo.findText(value)
            if index != -1:
                self.combo.setCurrentIndex(index)
        else:
            self.setText(1, str(value))

    def value(self):
        if isinstance(self._value, bool):
            return self.checkState(1) == Qt.Checked
        elif isinstance(self._value, (int, float)):
            return float(self.text(1))
        elif isinstance(self._value, tuple):
            return self.combo.currentText()
        else:
            return self.text(1)
class CommitSelectDialog(QDialog):
    def __init__(self, repo, until=None, path=None, parent=None):
        super(CommitSelectDialog, self).__init__(parent or iface.mainWindow())
        self.repo = repo
        self.ref = None
        self.path = path
        self.until = until
        self.initGui()

    def initGui(self):
        layout = QVBoxLayout()
        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok
                                     | QDialogButtonBox.Close)
        self.filterBox = QLineEdit()
        self.filterBox.setPlaceholderText(
            "[enter text or date in dd/mm/yyyy format to filter history]")
        self.filterBox.textChanged.connect(self.filterCommits)
        self.list = QListWidget()
        self.list.setAlternatingRowColors(True)
        self.list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.list.setSelectionBehavior(QAbstractItemView.SelectRows)
        log = self.repo.log(until=self.until, path=self.path, limit=100)
        for commit in log:
            item = CommitListItem(commit)
            self.list.addItem(item)
        layout.addWidget(self.filterBox)
        layout.addWidget(self.list)
        layout.addWidget(buttonBox)
        self.setLayout(layout)

        buttonBox.accepted.connect(self.okPressed)
        buttonBox.rejected.connect(self.cancelPressed)

        self.resize(500, 400)
        self.setWindowTitle("Select commit")

    def filterCommits(self):
        text = self.filterBox.text().strip()
        try:
            t = datetime.datetime.strptime(text, "%d/%m/%Y")
            found = False
            for i in range(self.list.count()):
                item = self.list.item(i)
                if found:
                    item.setHidden(True)
                else:
                    delta = item.commit.committerdate - t
                    found = delta.days < 0
                    item.setHidden(not found)

        except ValueError as e:
            for i in range(self.list.count()):
                item = self.list.item(i)
                msg = item.commit.message
                item.setHidden(text != "" and text not in msg)

    def okPressed(self):
        selected = self.list.selectedItems()
        if len(selected) == 0:
            QMessageBox.warning(self, 'No commit selected',
                                "Select 1 commits from the commit list.",
                                QMessageBox.Ok)
        else:
            self.ref = selected[0].commit
            self.close()

    def cancelPressed(self):
        self.ref = None
        self.close()