示例#1
0
    def _select_tags(self):
        """Select tags for the new plugin from the tags dialog"""
        tag_dialog = SelectTagsDialog()
        # if the user has their own taglist, use it
        user_tag_list = os.path.join(os.path.expanduser("~"),
                                     '.plugin_tags.txt')
        if os.path.exists(user_tag_list):
            tag_file = user_tag_list
        else:
            tag_file = os.path.join(str(self.plugin_builder_path),
                                    'taglist.txt')

        with open(tag_file) as tf:
            tags = tf.readlines()

        model = QStandardItemModel()

        for tag in tags:
            item = QStandardItem(tag[:-1])
            model.appendRow(item)

        tag_dialog.listView.setModel(model)
        tag_dialog.show()
        ok = tag_dialog.exec_()
        if ok:
            selected = tag_dialog.listView.selectedIndexes()
            seltags = []
            for tag in selected:
                seltags.append(tag.data())
            taglist = ", ".join(seltags)
            self.dialog.tags.setText(taglist)
示例#2
0
    def populateList(self):
        model = QStandardItemModel()
        for option in self.options:
            item = QStandardItem(option)
            model.appendRow(item)

        self.lstLayers.setModel(model)
示例#3
0
    def populateList(self):
        model = QStandardItemModel()
        for option in self.selectedoptions:
            item = QStandardItem(option)
            model.appendRow(item)

        self.lstLayers.setModel(model)
    def populate_trv(self, trv_widget, result, expand=False):

        model = QStandardItemModel()
        trv_widget.setModel(model)
        trv_widget.setUniformRowHeights(False)
        main_parent = QStandardItem('{}'.format('Giswater'))
        font = main_parent.font()
        font.setPointSize(8)
        main_parent.setFont(font)

        self.icon_folder = self.plugin_dir + os.sep + 'icons'
        path_icon_blue = self.icon_folder + os.sep + '36.png'
        path_icon_red = self.icon_folder + os.sep + '100.png'
        if os.path.exists(path_icon_blue):
            icon = QIcon(path_icon_blue)
            main_parent.setIcon(icon)

        for group, functions in result['fields'].items():
            parent1 = QStandardItem(
                f'{group}   [{len(functions)} Giswater algorithm]')
            self.no_clickable_items.append(
                f'{group}   [{len(functions)} Giswater algorithm]')
            functions.sort(key=self.sort_list, reverse=False)
            for function in functions:
                func_name = QStandardItem(str(function['functionname']))
                label = QStandardItem(str(function['alias']))
                font = label.font()
                font.setPointSize(8)
                label.setFont(font)
                row = self.controller.check_function(function['functionname'])
                if not row:
                    if os.path.exists(path_icon_red):
                        icon = QIcon(path_icon_red)
                        label.setIcon(icon)
                        label.setForeground(QColor(255, 0, 0))
                        msg = f"Function {function['functionname']}" \
                            f" configured on the table config_toolbox, but not found in the database"
                        label.setToolTip(msg)
                        self.no_clickable_items.append(str(function['alias']))
                else:
                    if os.path.exists(path_icon_blue):
                        icon = QIcon(path_icon_blue)
                        label.setIcon(icon)
                        label.setToolTip(function['functionname'])
                enable_run = QStandardItem("True")
                if function['input_params'] is not None:
                    if 'btnRunEnabled' in function['input_params']:
                        bool_dict = {True: "True", False: "False"}
                        enable_run = QStandardItem(bool_dict[
                            function['input_params']['btnRunEnabled']])

                parent1.appendRow([label, func_name, enable_run])
            main_parent.appendRow(parent1)
        model.appendRow(main_parent)
        index = model.indexFromItem(main_parent)
        trv_widget.expand(index)
        if expand:
            trv_widget.expandAll()
示例#5
0
    def populateList(self):
        model = QStandardItemModel()
        for i, option in enumerate(self.options):
            item = QStandardItem(option)
            item.setCheckState(Qt.Checked if i in self.selectedoptions else Qt.Unchecked)
            item.setCheckable(True)
            model.appendRow(item)

        self.lstLayers.setModel(model)
示例#6
0
    def populateList(self):
        model = QStandardItemModel()
        for i, option in enumerate(self.options):
            item = QStandardItem(option)
            item.setCheckState(Qt.Checked if i in self.selectedoptions else Qt.Unchecked)
            item.setCheckable(True)
            model.appendRow(item)

        self.lstLayers.setModel(model)
示例#7
0
 def build_list_positionable_class(self):
     model = QStandardItemModel()
     for obj in self.data.getClassName():
         item = QStandardItem(obj)
         item.setCheckState(Qt.Checked)
         item.setCheckable(True)
         model.appendRow(item)
     model.itemChanged.connect(self.on_positionable_class_list_changed)
     self.dlg.positionableClass.setModel(model)
示例#8
0
    def populateList(self):
        model = QStandardItemModel()
        for value, text in self.options:
            item = QStandardItem(text)
            item.setData(value, Qt.UserRole)
            item.setCheckState(Qt.Checked if value in self.selectedoptions else Qt.Unchecked)
            item.setCheckable(True)
            model.appendRow(item)

        self.lstLayers.setModel(model)
示例#9
0
    def populateList(self):
        model = QStandardItemModel()
        for value, text in self.options:
            item = QStandardItem(text)
            item.setData(value, Qt.UserRole)
            item.setCheckState(Qt.Checked if value in self.selectedoptions else Qt.Unchecked)
            item.setCheckable(True)
            model.appendRow(item)

        self.lstLayers.setModel(model)
示例#10
0
class HistoryDialog(QDialog, Ui_HistoryDialogPythonConsole):
    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.parent = parent
        self.setWindowTitle(
            QCoreApplication.translate("PythonConsole",
                                       "Python Console - Command History"))
        self.listView.setToolTip(
            QCoreApplication.translate("PythonConsole",
                                       "Double-click on item to execute"))
        self.model = QStandardItemModel(self.listView)

        self._reloadHistory()

        self.deleteScut = QShortcut(QKeySequence(Qt.Key_Delete), self)
        self.deleteScut.activated.connect(self._deleteItem)
        self.listView.doubleClicked.connect(self._runHistory)
        self.reloadHistory.clicked.connect(self._reloadHistory)
        self.saveHistory.clicked.connect(self._saveHistory)

    def _runHistory(self, item):
        cmd = item.data(Qt.DisplayRole)
        self.parent.runCommand(cmd)

    def _saveHistory(self):
        self.parent.writeHistoryFile(True)

    def _reloadHistory(self):
        self.model.clear()
        for i in self.parent.history:
            item = QStandardItem(i)
            if sys.platform.startswith('win'):
                item.setSizeHint(QSize(18, 18))
            self.model.appendRow(item)

        self.listView.setModel(self.model)
        self.listView.scrollToBottom()

    def _deleteItem(self):
        itemsSelected = self.listView.selectionModel().selectedIndexes()
        if itemsSelected:
            item = itemsSelected[0].row()
            # Remove item from the command history (just for the current session)
            self.parent.history.pop(item)
            self.parent.softHistory.pop(item)
            if item < self.parent.softHistoryIndex:
                self.parent.softHistoryIndex -= 1
            self.parent.setText(
                self.parent.softHistory[self.parent.softHistoryIndex])
            self.parent.move_cursor_to_end()
            # Remove row from the command history dialog
            self.model.removeRow(item)
示例#11
0
class CheckableComboBox:

    """Basic QCombobox with selectable items."""

    def __init__(self, combobox, select_all=None):
        """Constructor."""
        self.combo = combobox
        self.combo.setEditable(True)
        self.combo.lineEdit().setReadOnly(True)
        self.model = QStandardItemModel(self.combo)
        self.combo.setModel(self.model)
        self.combo.setItemDelegate(QStyledItemDelegate())
        self.model.itemChanged.connect(self.combo_changed)
        self.combo.lineEdit().textChanged.connect(self.text_changed)
        if select_all:
            self.select_all = select_all
            self.select_all.clicked.connect(self.select_all_clicked)

    def select_all_clicked(self):
        for item in self.model.findItems("*", Qt.MatchWildcard):
            item.setCheckState(Qt.Checked)

    def append_row(self, item: QStandardItem):
        """Add an item to the combobox."""
        item.setEnabled(True)
        item.setCheckable(True)
        item.setSelectable(False)
        self.model.appendRow(item)

    def combo_changed(self):
        """Slot when the combo has changed."""
        self.text_changed(None)

    def selected_items(self) -> list:
        checked_items = []
        for item in self.model.findItems("*", Qt.MatchWildcard):
            if item.checkState() == Qt.Checked:
                checked_items.append(item.data())
        return checked_items

    def set_selected_items(self, items):
        for item in self.model.findItems("*", Qt.MatchWildcard):
            checked = item.data() in items
            item.setCheckState(Qt.Checked if checked else Qt.Unchecked)

    def text_changed(self, text):
        """Update the preview with all selected items, separated by a comma."""
        label = ", ".join(self.selected_items())
        if text != label:
            self.combo.setEditText(label)
示例#12
0
 def change_positionable_class(self, state):
     model = QStandardItemModel()
     for className in self.data.getClassName():
         self.data.setSelected(className, state)
         item = QStandardItem(className)
         item.setCheckable(True)
         if state:
             self.data.setIds(className, "all")
             item.setCheckState(Qt.Checked)
         else:
             item.setCheckState(Qt.Unchecked)
         model.appendRow(item)
     model.itemChanged.connect(self.on_positionable_class_list_changed)
     self.dlg.positionableClass.setModel(model)
示例#13
0
 def build_list_positionable(self):
     model = QStandardItemModel()
     lu = 25 / len(self.loadedPositionable)
     completed = 75
     for pos in self.loadedPositionable:
         name = Utils.build_row_name_positionable(pos)
         item = QStandardItem(name)
         item.setCheckable(True)
         item.setCheckState(Qt.Checked)
         model.appendRow(item)
         completed = completed + lu
         self.dlg.progressBar.setValue(completed)
     model.itemChanged.connect(self.on_positionable_list_changed)
     self.dlg.positionable.setModel(model)
     self.dlg.progressBar.setValue(0)
示例#14
0
 def change_positionable(self, state):
     model = QStandardItemModel()
     for className in self.data.getClassName():
         for id in self.data.getIds(className):
             self.data.setIdValue(className, id, state)
     for pos in self.loadedPositionable:
         name = Utils.build_row_name_positionable(pos)
         item = QStandardItem(name)
         item.setCheckable(True)
         if state:
             item.setCheckState(Qt.Checked)
         else:
             item.setCheckState(Qt.Unchecked)
         model.appendRow(item)
     model.itemChanged.connect(self.on_positionable_list_changed)
     self.dlg.positionable.setModel(model)
示例#15
0
class HistoryDialog(QDialog, Ui_HistoryDialogPythonConsole):

    def __init__(self, parent):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.parent = parent
        self.setWindowTitle(QCoreApplication.translate("PythonConsole",
                                                       "Python Console - Command History"))
        self.listView.setToolTip(QCoreApplication.translate("PythonConsole",
                                                            "Double click on item to execute"))
        self.model = QStandardItemModel(self.listView)

        self._reloadHistory()

        self.deleteScut = QShortcut(QKeySequence(Qt.Key_Delete), self)
        self.deleteScut.activated.connect(self._deleteItem)
        self.listView.doubleClicked.connect(self._runHistory)
        self.reloadHistory.clicked.connect(self._reloadHistory)
        self.saveHistory.clicked.connect(self._saveHistory)

    def _runHistory(self, item):
        cmd = item.data(Qt.DisplayRole)
        self.parent.runCommand(cmd)

    def _saveHistory(self):
        self.parent.writeHistoryFile(True)

    def _reloadHistory(self):
        self.model.clear()
        for i in self.parent.history:
            item = QStandardItem(i)
            if sys.platform.startswith('win'):
                item.setSizeHint(QSize(18, 18))
            self.model.appendRow(item)

        self.listView.setModel(self.model)
        self.listView.scrollToBottom()

    def _deleteItem(self):
        itemsSelected = self.listView.selectionModel().selectedIndexes()
        if itemsSelected:
            item = itemsSelected[0].row()
            ## Remove item from the command history (just for the current session)
            self.parent.history.pop(item)
            self.parent.historyIndex -= 1
            ## Remove row from the command history dialog
            self.model.removeRow(item)
示例#16
0
 def build_list_attribute(self):
     model = QStandardItemModel()
     for attr in self.data.getAttributes(self.currentPositionableClass):
         item = QStandardItem(attr)
         if attr in self.alwaysSelectedAttribute:
             item.setCheckable(False)
             item.setCheckState(Qt.Checked)
         else:
             item.setCheckable(True)
             if self.data.getAttributes(
                     self.currentPositionableClass)[attr]:
                 item.setCheckState(Qt.Checked)
             else:
                 item.setCheckState(Qt.Unchecked)
         model.appendRow(item)
     model.itemChanged.connect(self.on_attribute_list_changed)
     self.dlg.attribute.setModel(model)
class HTMLFieldSelectionDialog(QDialog, HTML_FIELDS_CLASS):
    def __init__(self, iface, feat):
        super(HTMLFieldSelectionDialog, self).__init__(iface.mainWindow())
        self.setupUi(self)
        self.iface = iface
        self.feat = feat
        self.selected = []
        self.selectAllButton.clicked.connect(self.selectAll)
        self.clearButton.clicked.connect(self.clearAll)
        self.checkBox.stateChanged.connect(self.initModel)
        self.initModel()

    def initModel(self):
        self.model = QStandardItemModel(self.listView)
        state = self.checkBox.isChecked()
        for key in list(self.feat.keys()):
            if state == False or self.feat[key] > 0:
                item = QStandardItem()
                item.setText(key)
                item.setCheckable(True)
                item.setSelectable(False)
                self.model.appendRow(item)
        self.listView.setModel(self.model)
        self.listView.show()

    def selectAll(self):
        cnt = self.model.rowCount()
        for i in range(0, cnt):
            item = self.model.item(i)
            item.setCheckState(Qt.Checked)

    def clearAll(self):
        cnt = self.model.rowCount()
        for i in range(0, cnt):
            item = self.model.item(i)
            item.setCheckState(Qt.Unchecked)

    def accept(self):
        self.selected = []
        cnt = self.model.rowCount()
        for i in range(0, cnt):
            item = self.model.item(i)
            if item.checkState() == Qt.Checked:
                self.selected.append(item.text())
        self.close()
class StartWidget(uicls_start_page, basecls_start_page):
    """Widget for the Start page."""
    def __init__(self, parent_page):
        super().__init__()
        self.setupUi(self)
        self.parent_page = parent_page
        self.tv_revisions_model = QStandardItemModel()
        self.revisions_tv.setModel(self.tv_revisions_model)
        self.current_local_schematisation = self.parent_page.parent_wizard.current_local_schematisation
        self.schematisation = self.parent_page.parent_wizard.schematisation
        self.schematisation_sqlite = self.parent_page.parent_wizard.schematisation_sqlite
        self.available_revisions = self.parent_page.parent_wizard.available_revisions
        self.latest_revision = self.parent_page.parent_wizard.latest_revision
        organisation = self.parent_page.parent_wizard.plugin_dock.organisations[
            self.schematisation.owner]
        wip_revision = self.current_local_schematisation.wip_revision
        self.lbl_schematisation.setText(
            f"{self.schematisation.name} ({organisation.name})")
        self.lbl_model_dir.setText(wip_revision.schematisation_dir)
        self.lbl_revision_number.setText(str(wip_revision.number))
        self.populate_available_revisions()

    def populate_available_revisions(self):
        self.tv_revisions_model.clear()
        header = [
            "Revision number", "Committed by", "Commit date", "Commit message"
        ]
        self.tv_revisions_model.setHorizontalHeaderLabels(header)
        for revision in sorted(self.available_revisions,
                               key=attrgetter("number"),
                               reverse=True):
            number_item = QStandardItem(str(revision.number))
            commit_user_item = QStandardItem(revision.commit_user or "")
            commit_date = revision.commit_date.strftime(
                "%d-%m-%Y") if revision.commit_date else ""
            commit_date_item = QStandardItem(commit_date)
            commit_message_item = QStandardItem(revision.commit_message or "")
            self.tv_revisions_model.appendRow([
                number_item, commit_user_item, commit_date_item,
                commit_message_item
            ])
        for i in range(len(header)):
            self.revisions_tv.resizeColumnToContents(i)
示例#19
0
 def on_positionable_click(self, item):
     model = self.dlg.positionable.model()
     rowName = model.itemFromIndex(item)
     id = str(rowName.text()).split(' - ')[-1]
     selected = None
     for pos in self.loadedPositionable:
         if pos["_id"] == id:
             selected = pos
             break
     if selected is None:
         model.blockSignals(False)
         return
     model = QStandardItemModel()
     listStandardItem = []
     for s in selected:
         Utils.complete_model_from_positionable(s, selected[s],
                                                listStandardItem)
     for row in listStandardItem:
         model.appendRow(row)
     self.dlg.detail.setModel(model)
示例#20
0
    def comboboxselecionado(self):
        #saco de  aqui variables que estan en las cajitas
        global index_campo_seleccionado
        index_campo_seleccionado = self.dlg.mycomboBox.currentIndex()

        #para rellenar el texto de los puntos que tenemos
        layer = iface.activeLayer()
        features = layer.getFeatures()
        #idx2 = layer.fields().indexFromName("name")
        idx2 = index_campo_seleccionado
        todoslosnombres = []
        todaslascuadriculas = []
        for feature in features:
            print("feature")
            attrs = feature.attributes()
            # attrs is a list. It contains all the attribute values of this feature
            nombre = attrs[idx2]
            cuadric = nombre[:4]
            todoslosnombres.append(nombre)
            todaslascuadriculas.append(cuadric)

        frecuencia = []
        for w in todaslascuadriculas:
            frecuencia.append(todaslascuadriculas.count(w))

        print("Lista\n" + str(todaslascuadriculas) + "\n")
        print("Frecuencias\n" + str(frecuencia) + "\n")
        pares = list(zip(todaslascuadriculas, frecuencia))
        final = []
        for elemento in pares:
            if elemento not in final:
                final.append(elemento)
        print(final)
        model = QStandardItemModel()
        self.dlg.mylistview.setModel(model)
        for i in final:
            item = QStandardItem(str(i))
            model.appendRow(item)
示例#21
0
class TreeViewLogger(object):
    """Class with methods for handling messages using list view."""
    def __init__(self, tree_view=None, header=None):
        self.tree_view = tree_view
        self.header = header
        self.model = QStandardItemModel()
        self.tree_view.setModel(self.model)
        self.levels_colors = {
            LogLevels.INFO.value: QColor(Qt.black),
            LogLevels.WARNING.value: QColor(229, 144, 80),
            LogLevels.ERROR.value: QColor(Qt.red),
        }
        self.initialize_view()

    def clear(self):
        """Clear list view model."""
        self.tree_view.model().clear()

    def initialize_view(self):
        """Clear list view model and set header columns if available."""
        self.tree_view.model().clear()
        if self.header:
            self.tree_view.model().setHorizontalHeaderLabels(self.header)

    def log_result_row(self, row, log_level):
        """Show row data with proper log level styling."""
        text_color = self.levels_colors[log_level]
        if self.tree_view is not None:
            items = []
            for value in row:
                item = QStandardItem(str(value))
                item.setForeground(QBrush(text_color))
                items.append(item)
            self.model.appendRow(items)
            for i in range(len(self.header)):
                self.tree_view.resizeColumnToContents(i)
        else:
            print(row)
示例#22
0
class ListViewLogger(object):
    """Class with methods for handling messages using list view."""
    def __init__(self, list_view=None):
        self.list_view = list_view
        self.model = QStandardItemModel()
        self.list_view.setModel(self.model)

    def clear(self):
        """Clear list view model."""
        self.list_view.model().clear()

    def log_info(self, msg, log_text_color=QColor(Qt.darkGreen)):
        """Showing info message bar."""
        if self.list_view is not None:
            item = QStandardItem(msg)
            item.setForeground(QBrush(log_text_color))
            self.model.appendRow([item])
        else:
            print(msg)

    def log_warn(self, msg, log_text_color=QColor(Qt.darkYellow)):
        """Showing warning message bar."""
        if self.list_view is not None:
            item = QStandardItem(msg)
            item.setForeground(QBrush(log_text_color))
            self.model.appendRow([item])
        else:
            print(msg)

    def log_error(self, msg, log_text_color=QColor(Qt.red)):
        """Showing error message bar."""
        if self.list_view is not None:
            item = QStandardItem(msg)
            item.setForeground(QBrush(log_text_color))
            self.model.appendRow([item])
        else:
            print(msg)
示例#23
0
class DialListCheckBox(object):
    """
    Dialog with list check box
    example : 1,2,4,6,8
    """
    def __init__(self, values, checked_values=[]):
        self.dial = QDialog()
        self.result = ""

        # Layout Principal
        m_vbl = QVBoxLayout(self.dial)

        # List item checkable
        view = QListView()
        m_vbl.addWidget(view)

        self.m_sim = QStandardItemModel()
        view.setModel(self.m_sim)

        self._load_item(values, checked_values)

        # List buttons
        bt_all = QPushButton(self.tr("All"))
        bt_all.clicked.connect(lambda: self._check_all())

        bt_nothing = QPushButton(self.tr("Nothing"))
        bt_nothing.clicked.connect(lambda: self._check_nothing())

        bt_print = QPushButton(self.tr("Ok"))
        bt_print.clicked.connect(lambda: self._check_ok())

        # Sub layout for buttons
        m_vbh = QHBoxLayout()
        m_vbl.addLayout(m_vbh)

        m_vbh.addWidget(bt_all)
        m_vbh.addWidget(bt_nothing)
        m_vbh.addWidget(bt_print)

    def _load_item(self, values, checked_values):
        """Load item list"""
        for v in values:
            item = QStandardItem(str(v))
            if v in checked_values:
                item.setCheckState(Qt.Checked)
            else:
                item.setCheckState(Qt.Unchecked)
            item.setCheckable(True)
            self.m_sim.appendRow(item)

    def _check_all(self):
        """Check all item"""
        for index in range(self.m_sim.rowCount(
        )):  ## Iteration sur le model (contient la list des items)
            item = self.m_sim.item(index)
            if item.isCheckable() and item.checkState(
            ) == Qt.Unchecked:  # Si Unchecked
                item.setCheckState(Qt.Checked)

    def _check_nothing(self):
        """Uncheck all item"""
        for index in range(self.m_sim.rowCount(
        )):  ## Iteration sur le model (contient la list des items)
            item = self.m_sim.item(index)
            if item.isCheckable() and item.checkState(
            ) == Qt.Checked:  # Si Checked
                item.setCheckState(Qt.Unchecked)

    def _check_ok(self):
        """Get value of checked items and exit"""
        l_value = []
        for index in range(self.m_sim.rowCount(
        )):  ## Iteration sur le model (contient la list des items)
            item = self.m_sim.item(index)
            if item.isCheckable() and item.checkState(
            ) == Qt.Checked:  # Si Checked
                l_value.append(str(item.text()))

        if l_value:
            s_value = ";".join(l_value)
        else:
            s_value = ""

        self.result = s_value
        self.dial.close()

    def run(self):

        self.dial.setWindowTitle(self.tr("Select values"))

        self.dial.exec_()
        return self.result

    def tr(self, string, context=''):
        if context == '' or context == None:
            context = self.__class__.__name__
        return QCoreApplication.translate(context, string)
class PdokServicesPlugin(object):

    def __init__(self, iface):
        # Save reference to the QGIS interface
        self.iface = iface

        # docked or dialog, defaults to dialog
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if isinstance(QSettings().value("/pdokservicesplugin/docked"), QVariant):
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False))
        # else:
        #     self.docked = QSettings().value("/pdokservicesplugin/docked", False)
        #
        # # Create the dialog and keep reference
        # if "True" == self.docked or "true" == self.docked or True is self.docked:
        #     self.dlg = PdokServicesPluginDockWidget()
        #     self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg)
        # else:
        #     self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())

        self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow())
        # initialize plugin directory
        self.plugin_dir = QFileInfo(QgsApplication.qgisUserDatabaseFilePath()).path() + "/python/plugins/pdokservicesplugin"
        # initialize locale
        localePath = ""
        if isinstance(QSettings().value("locale/userLocale"), QVariant):
            locale = QSettings().value("locale/userLocale").value()[0:2]
        else:
            locale = QSettings().value("locale/userLocale")[0:2]

        if QFileInfo(self.plugin_dir).exists():
            localePath = self.plugin_dir + "/i18n/pdokservicesplugin_" + locale + ".qm"

        if QFileInfo(localePath).exists():
            self.translator = QTranslator()
            self.translator.load(localePath)
            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)
        self.currentLayer = None
        self.SETTINGS_SECTION = '/pdokservicesplugin/'
        self.pointer = None
        self.pdokgeocoder = PDOKGeoLocator(self.iface)
        self.geocoderSourceModel = None

    def getSettingsValue(self, key, default=''):
        if QSettings().contains(self.SETTINGS_SECTION + key):
            key = self.SETTINGS_SECTION + key
            if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8
                return str(QSettings().value(key).toString())
            else:
                return str(QSettings().value(key))
        else:
            return default

    def setSettingsValue(self, key, value):
        key = self.SETTINGS_SECTION + key
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue(key, QVariant(value))
        else:
            QSettings().setValue(key, value)

    def initGui(self):
        # Create action that will start plugin configuration
        self.run_action = QAction(QIcon(":/plugins/pdokservicesplugin/icon.png"), \
            u"Pdok Services Plugin", self.iface.mainWindow())

        self.servicesLoaded = False
        # connect the action to the run method
        # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway
        # if "True" == self.docked or "true" == self.docked or  True == self.docked:
        #     self.run_action.triggered.connect(self.showAndRaise)
        #     self.dlg.radioDocked.setChecked(True)
        #     # docked the dialog is immidiately visible, so should run NOW
        # else:
        #     self.run_action.triggered.connect(self.run)
        #     self.dlg.radioDocked.setChecked(False)
        #     self.setupfq()
        self.run_action.triggered.connect(self.run)
        #self.dlg.radioDocked.setChecked(False)
        self.setupfq()

        # Add toolbar button and menu item
        #self.iface.addToolBarIcon(self.action)

        self.toolbar = self.iface.addToolBar("PDOK services plugin")
        self.toolbar.setObjectName("PDOK services plugin")
        self.toolbar.addAction(self.run_action)
        self.toolbarSearch = QLineEdit()
        self.toolbarSearch.setMaximumWidth(200)
        self.toolbarSearch.setAlignment(Qt.AlignLeft)
        self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek")
        self.toolbar.addWidget(self.toolbarSearch)
        self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar)
        # address/point cleanup
        self.clean_action = QAction(QIcon(":/plugins/pdokservicesplugin/eraser.png"), \
            u"Cleanup", self.eraseAddress())
        self.toolbar.addAction(self.clean_action)
        self.clean_action.triggered.connect(self.eraseAddress)

        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action)

        # about
        self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/help.png"), \
                            "About", self.iface.mainWindow())
        self.aboutAction.setWhatsThis("Pdok Services Plugin About")
        self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction)

        self.aboutAction.triggered.connect(self.about)
        self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService)

        self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress)

        self.dlg.geocoderSearch.textEdited.connect(self.searchAddress)
        self.dlg.geocoderSearch.setPlaceholderText("PDOK Locatieserver zoek, bv postcode of postcode huisnummer")

        self.dlg.geocoderResultSearch.textChanged.connect(self.filterGeocoderResult)
        self.dlg.geocoderResultSearch.setPlaceholderText("een of meer zoekwoorden uit resultaat")

        #self.dlg.radioDocked.toggled.connect(self.set_docked)

        self.dlg.btnCheckPdokJson.clicked.connect(self.checkPdokJson)
        #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged)

        ui = self.dlg.ui
        cbxs = [ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr, ui.cbx_pcl, ui.cbx_hmp]
        # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search
        for cbx in cbxs:
            cbx.stateChanged.connect(self.searchAddress)

        self.run(True)

    # for now hiding the pointer as soon as the extent changes
    #def extentsChanged(self):
    #    self.removePointer()

    def checkPdokJson(self):
        myversion = self.getSettingsValue('pdokversion', '1')
        msgtxt = ''
        msglvl = 0  # QgsMessageBar.INFO
        try:
            response = urllib.request.urlopen('http://www.qgis.nl/pdok.version')
            str_response = response.read().decode('utf-8')
            pdokversion = json.loads(str_response)
            if pdokversion > int(myversion):
                response = urllib.request.urlopen('http://www.qgis.nl/pdok.json')
                str_response = response.read().decode('utf-8')
                pdokjson = json.loads(str_response)
                with open(self.plugin_dir +'/pdok.json', 'w') as outfile:
                    json.dump(pdokjson, outfile)
                msgtxt = "De laatste versie is opgehaald en zal worden gebruikt " + \
                    str(pdokversion) + ' (was ' + myversion +')'
                self.servicesLoaded = False # reset reading of json
                self.run()
                self.setSettingsValue('pdokversion', pdokversion)
            else:
                msgtxt = "Geen nieuwere versie beschikbaar dan " + str(pdokversion)
        except Exception as e:
            #print e
            msgtxt = "Fout bij ophalen van service info. Netwerk probleem?"
            msglvl = 2 # QgsMessageBar.CRITICAL
        # msg
        if hasattr(self.iface, 'messageBar'):
            self.iface.messageBar().pushMessage("PDOK services update", msgtxt, level=msglvl, duration=10)
        else: # 1.8
            QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin", msgtxt)

    # def set_docked(self, foo):
    #     self.setSettingsValue('docked', self.dlg.radioDocked.isChecked())
    #     #if Qgis.QGIS_VERSION_INT < 10900:
    #     #    # qgis <= 1.8
    #     #    QSettings().setValue("/pdokservicesplugin/docked", QVariant(self.dlg.radioDocked.isChecked()))
    #     #else:
    #     #    QSettings().setValue("/pdokservicesplugin/docked", self.dlg.radioDocked.isChecked())

    def showAndRaise(self):
        self.dlg.show()
        self.dlg.raise_()
        # also remove the pointer
        self.removePointer()

    def about(self):
        infoString =  "Written by Richard Duivenvoorde\nEmail - [email protected]\n"
        infoString += "Company - Zuidt - http://www.zuidt.nl\n"
        infoString += "Source: https://github.com/rduivenvoorde/pdokservicesplugin"
        QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin About", infoString)

    def unload(self):
        self.removePointer()
        # Remove the plugin menu item and icon
        self.iface.removePluginMenu(u"&Pdok Services Plugin",self.run_action)
        del self.toolbarSearch

    def showService(self, selectedIndexes):
        if len(selectedIndexes)==0:
            self.currentLayer = None
            self.dlg.ui.layerInfo.setHtml('')
            self.dlg.ui.comboSelectProj.clear()
            return
        # needed to scroll To the selected row incase of using the keyboard / arrows
        self.dlg.servicesView.scrollTo(self.dlg.servicesView.selectedIndexes()[0])
        # itemType holds the data (== column 1)
        self.currentLayer = self.dlg.servicesView.selectedIndexes()[1].data(Qt.UserRole)
        if isinstance(self.currentLayer, QVariant):
            self.currentLayer = self.currentLayer.toMap()
            # QGIS 1.8: QVariants
            currentLayer = {}
            for key in list(self.currentLayer.keys()):
                val = self.currentLayer[key]
                currentLayer[str(key)]=str(val.toString())
            self.currentLayer = currentLayer
        url = self.currentLayer['url']
        title = self.currentLayer['title']
        style = ''
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        servicetitle = self.currentLayer['servicetitle']
        layername = self.currentLayer['layers']
        abstract = self.currentLayer['abstract']
        stype = self.currentLayer['type'].upper()
        minscale =''
        if 'minscale' in self.currentLayer and self.currentLayer['minscale'] != None and self.currentLayer['minscale'] != '':
            minscale = "min. schaal 1:"+self.currentLayer['minscale']
        maxscale = ''
        if 'maxscale' in self.currentLayer and self.currentLayer['maxscale'] != None and self.currentLayer['maxscale'] != '':
            maxscale = "max. schaal 1:"+self.currentLayer['maxscale']
        self.dlg.ui.layerInfo.setText('')
        self.dlg.ui.btnLoadLayer.setEnabled(True)
        self.dlg.ui.layerInfo.setHtml('<h4>%s</h4><h3>%s</h3><lu><li>%s</li><li>&nbsp;</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li></lu>' % (servicetitle, title, abstract, stype, url, layername, style, minscale, maxscale))
        self.dlg.ui.comboSelectProj.clear()
        if stype=="WMS":
            try:
                crs = self.currentLayer['crs']
            except KeyError:
                crs = 'EPSG:28992'
            crs = crs.split(',')
            self.dlg.ui.comboSelectProj.addItems(crs)
            for i in range(len(crs)):
                if crs[i] == 'EPSG:28992':
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)
        if stype=="WMTS":
            tilematrixsets = self.currentLayer['tilematrixsets'].split(',')
            self.dlg.ui.comboSelectProj.addItems(tilematrixsets)
            for i in range(len(tilematrixsets)):
                if tilematrixsets[i].startswith('EPSG:28992'):
                    self.dlg.ui.comboSelectProj.setCurrentIndex(i)

    def loadService(self):
        if self.currentLayer == None:
            return
        servicetype = self.currentLayer['type']
        url = self.currentLayer['url']
        # some services have an url with query parameters in it, we have to urlencode those:
        location,query = urllib.parse.splitquery(url)
        url = location
        if query != None and query != '':
            url +=('?'+urllib.parse.quote_plus(query))
        title = self.currentLayer['title']
        if 'style' in self.currentLayer:
            style = self.currentLayer['style']
            title = title + ' [' + style + ']'
        else:
            style = '' # == default for this service
        layers = self.currentLayer['layers']
        # mmm, tricky: we take the first one while we can actually want png/gif or jpeg
        if servicetype == "wms":
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                crs = 'EPSG:28992'
            else:
                crs = self.dlg.ui.comboSelectProj.currentText()
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                uri = url
                self.iface.addRasterLayer(
                    uri, # service uri
                    title, # name for layer (as seen in QGIS)
                    "wms", # dataprovider key
                    [layers], # array of layername(s) for provider (id's)
                    [""], # array of stylename(s)  NOTE: ignoring styles here!!!
                    imgformat, # image format searchstring
                    crs) # crs code searchstring
            else:
                # qgis > 1.8
                uri = "crs="+crs+"&layers="+layers+"&styles="+style+"&format="+imgformat+"&url="+url;
                self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wmts":
            if Qgis.QGIS_VERSION_INT < 10900:
                QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen in deze versie van QGIS.\nMisschien kunt u QGIS 2.0 installeren (die kan het WEL)?\nOf is de laag niet ook beschikbaar als wms of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
                return
            if self.dlg.ui.comboSelectProj.currentIndex() == -1:
                tilematrixset = 'EPSG:28992'
            else:
                tilematrixset = self.dlg.ui.comboSelectProj.currentText()
            imgformat = self.currentLayer['imgformats'].split(',')[0]
            # special case for luchtfoto
            #if layers=="luchtfoto":
            #    # tileMatrixSet=nltilingschema&crs=EPSG:28992&layers=luchtfoto&styles=&format=image/jpeg&url=http://geodata1.nationaalgeoregister.nl/luchtfoto/wmts/1.0.0/WMTSCapabilities.xml
            #    # {u'layers': u'luchtfoto', u'imgformats': u'image/jpeg', u'title': u'PDOK-achtergrond luchtfoto', u'url': u'http://geodata1.nationaalgeoregister.nl/luchtfoto/wms', u'abstract': u'', u'tilematrixsets': u'nltilingschema', u'type': u'wmts'}
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url
            #else:
            #    uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url;
            #uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            if tilematrixset.startswith('EPSG:'):
                crs=tilematrixset
                i = crs.find(':', 5)
                if i > -1:
                    crs=crs[:i]
            elif tilematrixset.startswith('OGC:1.0'):
                crs='EPSG:3857'
            uri = "tileMatrixSet="+tilematrixset+"&crs="+crs+"&layers="+layers+"&styles=default&format="+imgformat+"&url="+url;
            #print "############ PDOK URI #################"
            #print uri
            self.iface.addRasterLayer(uri, title, "wms")
        elif servicetype == "wfs":
            location, query = urllib.parse.splitquery(url)
            #uri = location+"?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME="+layers+"&SRSNAME=EPSG:28992"
            #uri = location + "?SERVICE=WFS&REQUEST=GetFeature&TYPENAME=" + layers + "&SRSNAME=EPSG:28992"
            # adding a bbox paramater forces QGIS to NOT cache features but retrieve new features all the time
            # QGIS will update the BBOX to the right value
            #uri += "&BBOX=-10000,310000,290000,650000"
            uri = " pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:28992' typename='"+layers+"' url='"+url+"' version='2.0.0' "
            self.iface.addVectorLayer(uri, title, "WFS")
        elif servicetype == "wcs":
            # cache=AlwaysCache&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            uri = ''
            # cache=AlwaysCache
            # cache=PreferNetwork 
            # cache=AlwaysNetwork
            # cache=AlwaysNetwork&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs
            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.1&identifier="+layers+"&url="+url
            # working for ahn1 ahn2 and ahn3: GEOTIFF_FLOAT32
            format = 'GEOTIFF_FLOAT32'
            # working for ahn25m is only image/tiff
            if layers=='ahn25m':
                format = 'image/tiff'
            # we handcrated some wcs layers with 2 different image formats: tiff (RGB) and tiff (float32):
            if 'imgformats' in self.currentLayer:
                format = self.currentLayer['imgformats'].split(',')[0]
            uri = "cache=AlwaysNetwork&crs=EPSG:28992&format="+format+"&version=1.1.2&identifier=" + layers + "&url=" + url

            #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.2&identifier=" + layers + "&url=" + url
            self.iface.addRasterLayer(uri, title, "wcs")
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ("Sorry, dit type layer: '"+servicetype.upper()+"' \nkan niet worden geladen door de plugin of door QGIS.\nIs het niet beschikbaar als wms, wmts of wfs?"), QMessageBox.Ok, QMessageBox.Ok)
            return

    def filterGeocoderResult(self, string):
        #print "filtering geocoder results: %s" % string
        self.dlg.geocoderResultView.selectRow(0)
        self.geocoderProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.geocoderProxyModel.setFilterFixedString(string)

    def searchAddressFromToolbar(self):
        self.removePointer()
        self.geocoderSourceModel.clear()
        self.geocode()

    def searchAddress(self):
        self.removePointer()
        #print "search geocoder for: %s" % self.dlg.geocoderSearch.text()
        self.geocoderSourceModel.clear()
        #self.geocode(self.dlg.geocoderSearch.text())
        self.suggest()


    def eraseAddress(self):
        """
        clean the input and remove the pointer
        """
        self.removePointer()
        if self.geocoderSourceModel is not None:
            self.geocoderSourceModel.clear()
        if self.dlg.geocoderSearch is not None:
            self.dlg.geocoderSearch.clear()
        if self.toolbarSearch is not None:
            self.toolbarSearch.clear()

    def filterLayers(self, string):
        # remove selection if one row is selected
        self.dlg.servicesView.selectRow(0)
        #self.currentLayer = None
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxyModel.setFilterFixedString(string)

    #def addSourceRow(self, service, layer):
    def addSourceRow(self, serviceLayer):
        # you can attache different "data's" to to an QStandarditem
        # default one is the visible one:
        itemType = QStandardItem("%s" % (serviceLayer["type"].upper()) )
        # userrole is a free form one:
        # only attach the data to the first item
        # service layer = a dict/object with all props of the layer
        itemType.setData( serviceLayer, Qt.UserRole )
        itemType.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        # only wms services have styles (sometimes)
        layername = serviceLayer["title"]
        if 'style' in serviceLayer:
            itemLayername = QStandardItem("%s [%s]" % (serviceLayer["title"], serviceLayer["style"]) )
            layername = "%s [%s]" % (serviceLayer["title"], serviceLayer["style"])
        else:
            itemLayername = QStandardItem("%s" % (serviceLayer["title"]))
        itemLayername.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["servicetitle"] ))
        # itemFilter is the item used to search filter in. That is why layername is a combi of layername + filter here
        itemFilter = QStandardItem("%s %s %s %s" % (serviceLayer["type"], layername, serviceLayer["servicetitle"], serviceLayer["abstract"]) )
        itemServicetitle = QStandardItem("%s" % (serviceLayer["servicetitle"]))
        itemServicetitle.setToolTip("%s - %s" % (serviceLayer["type"].upper() ,serviceLayer["title"] ))
        self.sourceModel.appendRow( [ itemLayername, itemType, itemServicetitle, itemFilter ] )

    # run method that performs all the real work
    def run(self, hiddenDialog=False):

        # enable possible remote pycharm debugging
        #import pydevd
        #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)

        # last viewed/selected tab
        if QSettings().contains("/pdokservicesplugin/currenttab"):
            if Qgis.QGIS_VERSION_INT < 10900:
                # qgis <= 1.8
                self.dlg.tabs.widget(QSettings().value("/pdokservicesplugin/currenttab").toInt()[0])
            else:
                self.dlg.tabs.widget(int(QSettings().value("/pdokservicesplugin/currenttab")))

        if self.servicesLoaded == False:
            pdokjson = os.path.join(os.path.dirname(__file__), ".", "pdok.json")
            f = open(pdokjson, 'r', encoding='utf-8')
            self.pdok = json.load(f)
            f.close()

            self.proxyModel = QSortFilterProxyModel()
            self.sourceModel = QStandardItemModel()
            self.proxyModel.setSourceModel(self.sourceModel)
            # filter == search on itemFilter column:
            self.proxyModel.setFilterKeyColumn(3)
            self.dlg.servicesView.setModel(self.proxyModel)
            self.dlg.servicesView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            self.geocoderProxyModel = QSortFilterProxyModel()
            self.geocoderSourceModel = QStandardItemModel()

            self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel)
            self.geocoderProxyModel.setFilterKeyColumn(0)
            self.dlg.geocoderResultView.setModel(self.geocoderProxyModel)
            self.dlg.geocoderResultView.setEditTriggers(QAbstractItemView.NoEditTriggers)

            #{"services":[
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"},
            #   {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}
            # ]}
            # 
            for service in self.pdok["services"]:
                # service[layer] was an array
                if isinstance(service["layers"], str) or isinstance(service["layers"], str):
                    self.addSourceRow(service)

            self.dlg.layerSearch.textChanged.connect(self.filterLayers)
            self.dlg.layerSearch.setPlaceholderText("woord uit laagnaam, type of service ")
            self.dlg.servicesView.selectionModel().selectionChanged.connect(self.showService)
            self.dlg.servicesView.doubleClicked.connect(self.loadService)
            # actually I want to load a service when doubleclicked on header
            # but as I cannot get this to work, let's disable clicking it then
            self.dlg.servicesView.verticalHeader().setSectionsClickable(False)
            self.dlg.servicesView.horizontalHeader().setSectionsClickable(False)

            #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress)
            self.dlg.geocoderResultView.selectionModel().selectionChanged.connect(self.zoomToAddress)

            # hide itemFilter column:
            self.dlg.servicesView.hideColumn(3)
            self.servicesLoaded = True;

        self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service")
        self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]")
        self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
        self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        #self.dlg.servicesView.verticalHeader().hide()
        #self.dlg.servicesView.resizeColumnsToContents()
        self.dlg.servicesView.setColumnWidth(0, 300)  # set name to 300px (there are some huge layernames)
        self.dlg.servicesView.horizontalHeader().setStretchLastSection(True)
        # show the dialog ?
        if not hiddenDialog:
            self.dlg.show()
        # Run the dialog event loop
        #result = self.dlg.exec_()
        if Qgis.QGIS_VERSION_INT < 10900:
            # qgis <= 1.8
            QSettings().setValue("/pdokservicesplugin/currenttab", QVariant(self.dlg.tabs.currentIndex()))
        else:
            QSettings().setValue("/pdokservicesplugin/currenttab", self.dlg.tabs.currentIndex())
        self.removePointer()

    def setupfq(self):
        """
        Setup the fq checkboxes in the gui, by looking into the settings for the
        'pdokservicesplugin/checkedfqs' key, which contains a list of type strings
        like ['weg','adres']
        """
        checked_fqs = self.getSettingsValue('checkedfqs', [])
        #self.info('setup fq: {}'.format(checked_fqs))
        if len(checked_fqs) > 0:  # else there is not saved state... take gui defaults
            self.dlg.ui.cbx_gem.setChecked('gemeente' in checked_fqs)
            self.dlg.ui.cbx_wpl.setChecked('woonplaats' in checked_fqs)
            self.dlg.ui.cbx_weg.setChecked('weg' in checked_fqs)
            self.dlg.ui.cbx_pcd.setChecked('postcode' in checked_fqs)
            self.dlg.ui.cbx_adr.setChecked('adres' in checked_fqs)
            self.dlg.ui.cbx_pcl.setChecked('perceel' in checked_fqs)
            self.dlg.ui.cbx_hmp.setChecked('hectometerpaal' in checked_fqs)

    def createfq(self):
        """
        This creates a fq-string (Filter Query, see https://github.com/PDOK/locatieserver/wiki/Zoekvoorbeelden-Locatieserver)
        Based on the checkboxes in the dialog.
        Defaults to ''
        Example: 'fq=+type:adres+type:gemeente'  (only gemeente AND addresses)
        :return:
        """
        fqlist = []
        if self.dlg.ui.cbx_gem.isChecked():
            fqlist.append('gemeente')
        if self.dlg.ui.cbx_wpl.isChecked():
            fqlist.append('woonplaats')
        if self.dlg.ui.cbx_weg.isChecked():
            fqlist.append('weg')
        if self.dlg.ui.cbx_pcd.isChecked():
            fqlist.append('postcode')
        if self.dlg.ui.cbx_adr.isChecked():
            fqlist.append('adres')
        if self.dlg.ui.cbx_pcl.isChecked():
            fqlist.append('perceel')
        if self.dlg.ui.cbx_hmp.isChecked():
            fqlist.append('hectometerpaal')
        self.setSettingsValue('checkedfqs', fqlist)
        #self.info(self.getSettingsValue('checkedfqs', ['leeg?']))
        fq = ''
        if len(fqlist) > 0:
            fq = '&fq=+type:' + '+type:'.join(fqlist)
        return fq

    def suggest(self):
        self.dlg.ui.lookupinfo.setHtml('')
        search_text = self.dlg.geocoderSearch.text()
        if len(search_text) <= 1:
            # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
            #     "meer input aub: {}".format(search_text)
            #     ), QMessageBox.Ok, QMessageBox.Ok)
            return
        # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
        #     "zoeken: {}".format(search_text)
        # ), QMessageBox.Ok, QMessageBox.Ok)
        results = self.pdokgeocoder.suggest(search_text, self.createfq())
        if len(results) == 0:
            # ignore, as we are suggesting, maybe more characters will reveal something...
            return
        for result in results:
            #print address
            adrestekst = QStandardItem("%s" % (result["adrestekst"]))
            adrestekst.setData(result, Qt.UserRole)
            type = QStandardItem("%s" % (result["type"]))
            id = QStandardItem("%s" % (result["id"]))
            score = QStandardItem("%s" % (result["score"]))
            adrestekst.setData(result, Qt.UserRole)
            self.geocoderSourceModel.appendRow([adrestekst, type])
        self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
        self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Type")
        self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
        self.dlg.geocoderResultView.resizeColumnsToContents()
        self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def geocode(self):
        self.dlg.geocoderSearch.setText(self.toolbarSearch.text())
        self.suggest()
        if self.dlg.geocoderResultView.model().rowCount()>0:
            self.dlg.geocoderResultView.selectRow(0)
            self.zoomToAddress()
        else:
            QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
                "Niets gevonden.\nProbeer een andere spelling, of alleen postcode/huisnummer?\n\nSelecteer meer (Locatieserver) 'typen' in de PdokServicesPlugin dialoog.\n\nOf gebruik de 'PDOK geocoder'-tab in de PdokServicesPlugin dialoog."
                ), QMessageBox.Ok, QMessageBox.Ok)

    # def geocode(self):
    #     self.dlg.ui.lookupinfo.setHtml('')
    #     search_text = self.toolbarSearch.text()
    #     addresses = self.pdokgeocoder.search(search_text)
    #     if len(addresses) == 0:
    #         QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \
    #             "Niets gevonden. Probeer een andere spelling of alleen postcode/huisnummer."
    #             ), QMessageBox.Ok, QMessageBox.Ok)
    #         return
    #     for address in addresses:
    #         #print address
    #         adrestekst = QStandardItem("%s" % (address["adrestekst"]))
    #         adrestekst.setData(address, Qt.UserRole)
    #         straat = QStandardItem("%s" % (address["straat"]))
    #         nummer = QStandardItem("%s" % (address["nummer"]))
    #         postcode = QStandardItem("%s" % (address["postcode"]))
    #         plaats = QStandardItem("%s" % (address["plaats"]))
    #         gemeente = QStandardItem("%s" % (address["gemeente"]))
    #         provincie = QStandardItem("%s" % (address["provincie"]))
    #         self.geocoderSourceModel.appendRow([adrestekst, straat, nummer, postcode, plaats, gemeente, provincie])
    #
    #     self.dlg.geocoderResultView.selectRow(0)
    #     self.zoomToAddress()
    #
    #     self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat")
    #     self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Straat")
    #     self.geocoderSourceModel.setHeaderData(2, Qt.Horizontal, "Nr")
    #     self.geocoderSourceModel.setHeaderData(3, Qt.Horizontal, "Postcode")
    #     self.geocoderSourceModel.setHeaderData(4, Qt.Horizontal, "Plaats")
    #     self.geocoderSourceModel.setHeaderData(5, Qt.Horizontal, "Gemeente")
    #     self.geocoderSourceModel.setHeaderData(6, Qt.Horizontal, "Provincie")
    #
    #     self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(3).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(4).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(5).setTextAlignment(Qt.AlignLeft)
    #     self.geocoderSourceModel.horizontalHeaderItem(6).setTextAlignment(Qt.AlignLeft)
    #
    #     self.dlg.geocoderResultView.resizeColumnsToContents()
    #     self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True)

    def zoomToAddress(self):
        # get x,y from data of record
        self.removePointer()

        data = self.dlg.geocoderResultView.selectedIndexes()[0].data(Qt.UserRole)

        if 'centroide_rd' in data: # free OR lookup service
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
        else:
            # no centroid yet, probably only object id, retrieve it via lookup service
            id = data['id']
            data = self.pdokgeocoder.lookup(id)
            geom = QgsGeometry.fromWkt(data['centroide_rd'])
            adrestekst = data['adrestekst']
            lookup_data= data['data']
            lis = ''
            for key in lookup_data.keys():
                lis = lis + '<li>{}: {}</li>'.format(key, lookup_data[key])
            self.dlg.ui.lookupinfo.setHtml(
                '<h4>{}</h4><lu>{}</lu>'.format(adrestekst, lis))

        # just always transform from 28992 to mapcanvas crs
        crs = self.iface.mapCanvas().mapSettings().destinationCrs()
        crs28992 = QgsCoordinateReferenceSystem()
        crs28992.createFromId(28992)
        crsTransform = QgsCoordinateTransform(crs28992, crs, QgsProject.instance())
        z = 1587
        if adrestekst.lower().startswith('adres'):
            z = 794
        elif adrestekst.lower().startswith('perceel'):
            z = 794
        elif adrestekst.lower().startswith('hectometer'):
            z = 1587
        elif adrestekst.lower().startswith('straat'):
            z = 3175
        elif adrestekst.lower().startswith('postcode'):
            z = 6350
        elif adrestekst.lower().startswith('woonplaats'):
            z = 25398
        elif adrestekst.lower().startswith('gemeente'):
            z = 50797
        elif adrestekst.lower().startswith('provincie'):
            z = 812750
        geom.transform(crsTransform)
        center = geom.asPoint()
        self.setPointer(center)
        # zoom to with center is actually setting a point rectangle and then zoom
        rect = QgsRectangle(center, center)
        self.iface.mapCanvas().setExtent(rect)
        self.iface.mapCanvas().zoomScale(z)
        self.iface.mapCanvas().refresh()

    def setPointer(self, point):
        self.removePointer()
        self.pointer = QgsVertexMarker(self.iface.mapCanvas())
        self.pointer.setColor(QColor(255, 255, 0))
        self.pointer.setIconSize(10)
        self.pointer.setPenWidth(5)
        self.pointer.setCenter(point)

    def removePointer(self):
        if self.pointer is not None:
            self.iface.mapCanvas().scene().removeItem(self.pointer)

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin', Qgis.Info)
示例#25
0
class FKProperty(WIDGET, BASE):
    """
    Editor to create/edit ForeignKey column property
    """
    def __init__(self, parent, relation={}):
        """
        :param parent: Owner of the form
        :type parent: QWidget
        :param relation: Dictionary holding fields used to build foreign key column
         *entity_relation - EntityRelation object, if its None then
         this is a new column else its an edit
         *fk_entities - entities used for ForeignKey selection
         *profile - current profile
         *entity - current entity you are creating column for.
         *column_name - name of the column
        :type form_field: dictionary
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)

        self._entity_relation = relation['form_fields']['entity_relation']
        self.fk_entities = relation['fk_entities']
        self.profile = relation['profile']
        self.entity = relation['entity']
        self.column_name = relation['column_name']
        self.in_db = relation['form_fields']['in_db']
        self._show_in_parent = relation['show_in_parent']
        self._show_in_child = relation['show_in_child']
        self.column_model = QStandardItemModel()
        self.lvDisplayCol.setModel(self.column_model)

        self.init_gui()

    def init_gui(self):
        """
        Initializes form fields
        """
        self.cboPrimaryEntity.currentIndexChanged.connect( \
            self.load_entity_columns)

        self.load_fk_entities()
        if self._entity_relation:
            parent = self._entity_relation.parent.short_name
            parent_column = self._entity_relation.parent_column
            display_cols = self._entity_relation.display_cols

            self.cboPrimaryEntity.setCurrentIndex( \
                self.cboPrimaryEntity.findText(parent))

            self.cboPrimaryUKey.setCurrentIndex( \
                self.cboPrimaryUKey.findText(parent_column))

            self.show_display_cols(display_cols)

        # Disable controls if column exists in the database
        self.cboPrimaryEntity.setEnabled(not self.in_db)
        self.cboPrimaryUKey.setEnabled(not self.in_db)
        self.lvDisplayCol.setEnabled(not self.in_db)

        self.show_in_parent_chk.clicked.connect(self.on_show_in_parent_clicked)
        self.show_in_child_chk.clicked.connect(self.on_show_in_child_clicked)

    def on_show_in_parent_clicked(self):
        """
        A slot raised when show in parent is clicked.
        :return:
        :rtype:
        """
        if self.show_in_parent_chk.isChecked():
            self.show_in_child_chk.setChecked(False)
            self._show_in_parent = True

    def on_show_in_child_clicked(self):
        """
        A slot raised when show in child is clicked.
        :return:
        :rtype:
        """
        if self.show_in_child_chk.isChecked():
            self.show_in_parent_chk.setChecked(False)
            self._show_in_child = True

    def show_in_parent(self):
        """
        Returns show in parent.
        :return: Returns show in parent.
        :rtype: Boolean
        """
        return self._show_in_parent

    def show_in_child(self):
        """
        Returns show in child.
        :return: Returns show in child.
        :rtype: Boolean
        """
        return self._show_in_child

    def show_display_cols(self, display_cols):
        """
        checks previously selected display columns
        """
        for row in range(self.column_model.rowCount()):
            if str(self.column_model.item(row).text()) in display_cols:
                self.column_model.item(row).setCheckState(Qt.Checked)

    def load_fk_entities(self):
        """
        populates combobox with entities to select primary entity for the
        foreign key
        """
        self.cboPrimaryEntity.clear()
        self.cboPrimaryEntity.insertItems(
            0, [name[0] for name in self.fk_entities])

        self.cboPrimaryEntity.setCurrentIndex(0)

    def entity_columns(self):
        """
        returns: A list used to select child entity column when building
        a foreign key
        rtype: list
        """
        index = self.cboPrimaryEntity.currentIndex()

        entity_columns = \
            [column for column in self.fk_entities[index][1].columns.items()]

        column_names = [column[0] for column in entity_columns]

        return column_names

    def fk_display_columns(self):
        """
        returns: A list of columns used to select display columns
        in foreign key
        rtype: list
        """
        index = self.cboPrimaryEntity.currentIndex()
        entity_columns = \
            [column for column in self.fk_entities[index][1].columns.items()]

        columns = [column[0] for column in entity_columns \
                   if column[1].TYPE_INFO != 'SERIAL']

        return columns

    def load_entity_columns(self):
        """

        """
        columns = self.entity_columns()
        self.populate_column_combobox(columns)

        disp_columns = self.fk_display_columns()
        self.populate_column_listview(disp_columns)

    def populate_column_combobox(self, columns):
        """
        Populate combobox with column names
        param columns: List of entity columns to select your primary unique
        column for the foreign key
        type columns: list
        """
        self.cboPrimaryUKey.clear()
        self.cboPrimaryUKey.insertItems(0, columns)

    def populate_column_listview(self, columns):
        """
        Populates list view with columns used in selecting
        display columns for foreign key
        param columns: A list of column names
        type columns: list
        """
        self.column_model.clear()
        for column in columns:
            item = QStandardItem(column)
            item.setCheckable(True)
            self.column_model.appendRow(item)

    def add_values(self):
        """
        Construct an EntityRelation instance from form fields
        """
        er_fields = {}
        er_fields['parent'] = str(self.cboPrimaryEntity.currentText())
        er_fields['parent_column'] = str(self.cboPrimaryUKey.currentText())
        er_fields['display_columns'] = self.display_columns()
        er_fields['child'] = self.entity
        er_fields['child_column'] = self.column_name

        self._entity_relation = EntityRelation(self.profile, **er_fields)

    def display_columns(self):
        """
        Scans StandardItemModel for display columns, and returns a list of
        selected/checked columns for display in foreign key
        rtype: list
        """
        return [str(self.column_model.item(row).text()) \
                for row in range(self.column_model.rowCount()) \
                if self.column_model.item(row).checkState() == Qt.Checked]

    def entity_relation(self):
        """
        returns: entity relation instance
        rtype: EntityRelation
        """
        return self._entity_relation

    def accept(self):
        self.add_values()
        self.done(1)

    def reject(self):
        self.done(0)
class ResourceSharingDialog(QDialog, FORM_CLASS):
    TAB_ALL = 0
    TAB_INSTALLED = 1
    TAB_SETTINGS = 2

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

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        super(ResourceSharingDialog, self).__init__(parent)
        self.setupUi(self)
        self.iface = iface

        # Reconfigure UI
        self.setModal(True)
        self.button_edit.setEnabled(False)
        self.button_delete.setEnabled(False)
        self.button_install.setEnabled(False)
        self.button_open.setEnabled(False)
        self.button_uninstall.setEnabled(False)

        # Set up the "main menu" - QListWidgetItem
        # All collections
        icon_all = QIcon()
        icon_all.addFile(str(resources_path('img', 'plugin.svg')), QSize(),
                         QIcon.Normal, QIcon.Off)
        item_all = QListWidgetItem()
        item_all.setIcon(icon_all)
        item_all.setText(self.tr('All collections'))
        # Installed collections
        icon_installed = QIcon()
        icon_installed.addFile(
            str(resources_path('img', 'plugin-installed.svg')), QSize(),
            QIcon.Normal, QIcon.Off)
        item_installed = QListWidgetItem()
        item_installed.setIcon(icon_installed)
        item_installed.setText(self.tr('Installed collections'))
        item_all.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        # Settings / repositories
        icon_settings = QIcon()
        icon_settings.addFile(str(resources_path('img', 'settings.svg')),
                              QSize(), QIcon.Normal, QIcon.Off)
        item_settings = QListWidgetItem()
        item_settings.setIcon(icon_settings)
        item_settings.setText(self.tr('Settings'))
        item_all.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)

        # Add the items to the list widget
        self.menu_list_widget.addItem(item_all)
        self.menu_list_widget.addItem(item_installed)
        self.menu_list_widget.addItem(item_settings)

        # Init the message bar
        self.message_bar = QgsMessageBar(self)
        self.message_bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.vlayoutRightColumn.insertWidget(0, self.message_bar)

        # Progress dialog for long running processes
        self.progress_dialog = None

        # Init the repository manager dialog
        self.repository_manager = RepositoryManager()
        self.collection_manager = CollectionManager()
        # Collections list view
        self.collections_model = QStandardItemModel(0, 1)
        self.collections_model.sort(0, Qt.AscendingOrder)
        self.collection_proxy = CustomSortFilterProxyModel(self)
        self.collection_proxy.setSourceModel(self.collections_model)
        self.list_view_collections.setModel(self.collection_proxy)
        # Active selected collection
        self._selected_collection_id = None

        # Slots
        self.button_add.clicked.connect(self.add_repository)
        self.button_edit.clicked.connect(self.edit_repository)
        self.button_delete.clicked.connect(self.delete_repository)
        self.button_reload.clicked.connect(self.reload_repositories)
        self.menu_list_widget.currentRowChanged.connect(self.set_current_tab)
        self.list_view_collections.selectionModel().currentChanged.connect(
            self.on_list_view_collections_clicked)
        self.line_edit_filter.textChanged.connect(self.filter_collections)
        self.button_install.clicked.connect(self.install_collection)
        self.button_open.clicked.connect(self.open_collection)
        self.button_uninstall.clicked.connect(self.uninstall_collection)
        self.button_box.button(QDialogButtonBox.Help).clicked.connect(
            self.open_help)

        # Populate the repositories widget and collections list view
        self.populate_repositories_widget()
        self.reload_collections_model()

    def set_current_tab(self, index):
        """Set stacked widget based on the active tab.

        :param index: The index of the active widget (in the list widget).
        :type index: int
        """
        # Clear message bar
        self.message_bar.clearWidgets()
        if index == (self.menu_list_widget.count() - 1):
            # Last menu entry - Settings
            self.stacked_menu_widget.setCurrentIndex(1)
        else:
            # Not settings, must be Collections (all or installed)
            if index == 1:
                # Installed collections
                self.collection_proxy.accepted_status = \
                    COLLECTION_INSTALLED_STATUS
                # Set the web view
                title = self.tr('Installed Collections')
                description = self.tr(
                    'On the left you see the list of all the '
                    'installed collections.')
            else:
                # All collections (0)
                self.collection_proxy.accepted_status = COLLECTION_ALL_STATUS
                # Set the web view
                title = self.tr('All Collections')
                description = self.tr(
                    'On the left you see a list of all the collections '
                    'that are available from the registered repositories.<br> '
                    'Installed collections are emphasized (in <b>bold</b>).')

            context = {
                'resources_path': str(resources_path()),
                'title': title,
                'description': description
            }
            self.web_view_details.setHtml(
                render_template('tab_description.html', context))
            self.stacked_menu_widget.setCurrentIndex(0)

    def add_repository(self):
        """Open add repository dialog."""
        dlg = ManageRepositoryDialog(self)
        if not dlg.exec_():
            return

        for repoName, repo in self.repository_manager.directories.items():
            if dlg.line_edit_url.text().strip() == repo['url']:
                self.message_bar.pushMessage(
                    self.tr(
                        'Unable to add another repository with the same URL!'),
                    Qgis.Warning, 5)
                return
            if dlg.line_edit_name.text().strip() == repoName:
                self.message_bar.pushMessage(
                    self.tr('Repositories must have unique names!'),
                    Qgis.Warning, 5)
                return

        repo_name = dlg.line_edit_name.text()
        repo_url = dlg.line_edit_url.text().strip()
        repo_auth_cfg = dlg.line_edit_auth_id.text().strip()
        if repo_name in self.repository_manager.directories:
            repo_name += '(2)'

        # Show progress dialog
        self.show_progress_dialog("Fetching repository's metadata")

        # Add repository
        try:
            status, adderror = self.repository_manager.add_directory(
                repo_name, repo_url, repo_auth_cfg)
            if status:
                self.message_bar.pushMessage(
                    self.tr('Repository was successfully added'), Qgis.Success,
                    5)
            else:
                self.message_bar.pushMessage(
                    self.tr('Unable to add repository: %s') % adderror,
                    Qgis.Warning, 5)
        except Exception as e:
            self.message_bar.pushMessage(self.tr('%s') % e, Qgis.Warning, 5)
        finally:
            self.progress_dialog.hide()

        # Reload data and widget
        self.reload_data_and_widget()

        # Deactivate edit and delete button
        self.button_edit.setEnabled(False)
        self.button_delete.setEnabled(False)

    def edit_repository(self):
        """Open edit repository dialog."""
        selected_item = self.tree_repositories.currentItem()
        if selected_item:
            repo_name = selected_item.text(0)

        if not repo_name:
            return

        # Check if it is among the officially approved QGIS repositories
        settings = QgsSettings()
        settings.beginGroup(repo_settings_group())
        if settings.value(repo_name + '/url') in \
                self.repository_manager._online_directories.values():
            self.message_bar.pushMessage(
                self.tr('You can not edit the official repositories!'),
                Qgis.Warning, 5)
            return

        dlg = ManageRepositoryDialog(self)
        dlg.line_edit_name.setText(repo_name)
        dlg.line_edit_url.setText(
            self.repository_manager.directories[repo_name]['url'])
        dlg.line_edit_auth_id.setText(
            self.repository_manager.directories[repo_name]['auth_cfg'])

        if not dlg.exec_():
            return

        # Check if the changed URL is already present and that
        # the new repository name is unique
        new_url = dlg.line_edit_url.text().strip()
        old_url = self.repository_manager.directories[repo_name]['url']
        new_name = dlg.line_edit_name.text().strip()
        for repoName, repo in self.repository_manager.directories.items():
            if new_url == repo['url'] and (old_url != new_url):
                self.message_bar.pushMessage(
                    self.tr('Unable to add another repository with the same '
                            'URL!'), Qgis.Warning, 5)
                return
            if new_name == repoName and (repo_name != new_name):
                self.message_bar.pushMessage(
                    self.tr('Repositories must have unique names!'),
                    Qgis.Warning, 5)
                return

        # Redundant
        if (new_name in self.repository_manager.directories) and (new_name !=
                                                                  repo_name):
            new_name += '(2)'

        new_auth_cfg = dlg.line_edit_auth_id.text()

        # Show progress dialog
        self.show_progress_dialog("Fetching repository's metadata")

        # Edit repository
        try:
            status, editerror = self.repository_manager.edit_directory(
                repo_name, new_name, old_url, new_url, new_auth_cfg)
            if status:
                self.message_bar.pushMessage(
                    self.tr('Repository is successfully updated'),
                    Qgis.Success, 5)
            else:
                self.message_bar.pushMessage(
                    self.tr('Unable to edit repository: %s') % editerror,
                    Qgis.Warning, 5)
        except Exception as e:
            self.message_bar.pushMessage(self.tr('%s') % e, Qgis.Warning, 5)
        finally:
            self.progress_dialog.hide()

        # Reload data and widget
        self.reload_data_and_widget()

        # Deactivate the edit and delete buttons
        self.button_edit.setEnabled(False)
        self.button_delete.setEnabled(False)

    def delete_repository(self):
        """Delete a repository in the tree widget."""
        selected_item = self.tree_repositories.currentItem()
        if selected_item:
            repo_name = selected_item.text(0)

        if not repo_name:
            return
        # Check if it is among the offical repositories
        repo_url = self.repository_manager.directories[repo_name]['url']
        if repo_url in self.repository_manager._online_directories.values():
            self.message_bar.pushMessage(
                self.tr('You can not remove official repositories!'),
                Qgis.Warning, 5)
            return

        warning = self.tr('Are you sure you want to remove the following '
                          'repository?') + '\n' + repo_name
        if QMessageBox.warning(self, self.tr('QGIS Resource Sharing'), warning,
                               QMessageBox.Yes,
                               QMessageBox.No) == QMessageBox.No:
            return

        # Remove repository
        installed_collections = \
            self.collection_manager.get_installed_collections(repo_url)
        if installed_collections:
            message = ('You have installed collections from this '
                       'repository. Please uninstall them first!')
            self.message_bar.pushMessage(message, Qgis.Warning, 5)
        else:
            self.repository_manager.remove_directory(repo_name)
            # Reload data and widget
            self.reload_data_and_widget()
            # Deactivate the edit and delete buttons
            self.button_edit.setEnabled(False)
            self.button_delete.setEnabled(False)

    def reload_repositories(self):
        """Slot for when user clicks reload repositories button."""
        # Show progress dialog
        self.show_progress_dialog('Reloading all repositories')

        for repo_name in self.repository_manager.directories:
            directory = self.repository_manager.directories[repo_name]
            url = directory['url']
            auth_cfg = directory['auth_cfg']
            try:
                status, reloaderror = self.repository_manager.reload_directory(
                    repo_name, url, auth_cfg)
                if status:
                    self.message_bar.pushMessage(
                        self.tr('Repository %s is successfully reloaded') %
                        repo_name, Qgis.Info, 5)
                else:
                    self.message_bar.pushMessage(
                        self.tr('Unable to reload %s: %s') %
                        (repo_name, reloaderror), Qgis.Warning, 5)
            except Exception as e:
                self.message_bar.pushMessage(
                    self.tr('%s') % e, Qgis.Warning, 5)

        self.progress_dialog.hide()
        # Reload data and widget
        self.reload_data_and_widget()

    def install_collection(self):
        """Slot for when the user clicks the install/reinstall button."""
        # Save the current index to enable selection after installation
        self.current_index = self.list_view_collections.currentIndex()
        self.show_progress_dialog('Starting installation...')
        self.progress_dialog.canceled.connect(self.install_canceled)

        self.installer_thread = QThread()
        self.installer_worker = CollectionInstaller(
            self.collection_manager, self._selected_collection_id)
        self.installer_worker.moveToThread(self.installer_thread)
        self.installer_worker.finished.connect(self.install_finished)
        self.installer_worker.aborted.connect(self.install_aborted)
        self.installer_worker.progress.connect(self.install_progress)
        self.installer_thread.started.connect(self.installer_worker.run)
        self.installer_thread.start()

    def install_finished(self):
        # Process the result
        self.progress_dialog.hide()
        installStatus = self.installer_worker.install_status
        if not installStatus:
            message = self.installer_worker.error_message
        # Clean up the worker and thread
        self.installer_worker.deleteLater()
        self.installer_thread.quit()
        self.installer_thread.wait()
        self.installer_thread.deleteLater()

        if installStatus:
            self.reload_collections_model()
            # Report what has been installed
            message = '<b>%s</b> was successfully installed, containing:\n<ul>' % (
                config.COLLECTIONS[self._selected_collection_id]['name'])
            number = 0
            if 'style' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['style']
                message = message + '\n<li> ' + str(
                    number) + ' Layer style (QML) file'
                if number > 1:
                    message = message + 's'
            if 'symbol' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['symbol']
                message = message + '\n<li> ' + str(
                    number) + ' XML symbol file'
                if number > 1:
                    message = message + 's'
            if 'svg' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['svg']
                message = message + '\n<li> ' + str(number) + ' SVG file'
                if number > 1:
                    message = message + 's'
            if 'models' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['models']
                message = message + '\n<li> ' + str(number) + ' model'
                if number > 1:
                    message = message + 's'
            if 'expressions' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['expressions']
                message = message + '\n<li> ' + str(
                    number) + ' expression file'
                if number > 1:
                    message = message + 's'
            if 'processing' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['processing']
                message = message + '\n<li> ' + str(
                    number) + ' processing script'
                if number > 1:
                    message = message + 's'
            if 'rscripts' in config.COLLECTIONS[
                    self._selected_collection_id].keys():
                number = config.COLLECTIONS[
                    self._selected_collection_id]['rscripts']
                message = message + '\n<li> ' + str(number) + ' R script'
                if number > 1:
                    message = message + 's'
            message = message + '\n</ul>'
        QMessageBox.information(self, 'Resource Sharing', message)
        self.populate_repositories_widget()
        # Set the selection
        oldRow = self.current_index.row()
        newIndex = self.collections_model.createIndex(oldRow, 0)
        selection_model = self.list_view_collections.selectionModel()
        selection_model.setCurrentIndex(newIndex,
                                        selection_model.ClearAndSelect)
        selection_model.select(newIndex, selection_model.ClearAndSelect)
        # Update the buttons
        self.button_install.setEnabled(True)
        self.button_install.setText('Reinstall')
        self.button_open.setEnabled(True)
        self.button_uninstall.setEnabled(True)

        self.show_collection_metadata(self._selected_collection_id)

    def install_canceled(self):
        self.progress_dialog.hide()
        self.show_progress_dialog('Cancelling installation...')
        self.installer_worker.abort()

    def install_aborted(self):
        if self.installer_thread.isRunning():
            self.installer_thread.quit()
        self.installer_thread.finished.connect(self.progress_dialog.hide)

    def install_progress(self, text):
        self.progress_dialog.setLabelText(text)

    def uninstall_collection(self):
        """Slot called when user clicks the uninstall button."""
        # get the QModelIndex for the item to be uninstalled
        uninstall_index = self.list_view_collections.currentIndex()
        coll_id = self._selected_collection_id
        try:
            self.collection_manager.uninstall(coll_id)
        except Exception as e:
            LOGGER.error('Could not uninstall collection ' +
                         config.COLLECTIONS[coll_id]['name'] + ':\n' + str(e))
        else:
            QMessageBox.information(
                self, 'Resource Sharing',
                'The collection was successfully uninstalled!')
            self.reload_collections_model()
            # Fix the GUI
            currentMenuRow = self.menu_list_widget.currentRow()
            self.set_current_tab(currentMenuRow)
            self.populate_repositories_widget()

            rowCount = self.collection_proxy.rowCount()
            if rowCount > 0:
                # Set the current (and selected) row in the listview
                newRow = uninstall_index.row()
                # Check if this was the last element
                rowCount = self.collection_proxy.rowCount()
                if newRow == rowCount:
                    newRow = newRow - 1
                # Select the new current element
                newIndex = self.collections_model.createIndex(newRow, 0)
                selection_model = self.list_view_collections.selectionModel()
                selection_model.setCurrentIndex(newIndex,
                                                selection_model.ClearAndSelect)
                # Get the id of the current collection
                proxyModel = self.list_view_collections.model()
                proxyIndex = proxyModel.index(newRow, 0)
                current_coll_id = proxyIndex.data(COLLECTION_ID_ROLE)
                self._selected_collection_id = current_coll_id
                # Update buttons
                status = config.COLLECTIONS[current_coll_id]['status']
                if status == COLLECTION_INSTALLED_STATUS:
                    self.button_install.setEnabled(True)
                    self.button_install.setText('Reinstall')
                    self.button_open.setEnabled(True)
                    self.button_uninstall.setEnabled(True)
                else:
                    self.button_install.setEnabled(True)
                    self.button_install.setText('Install')
                    self.button_open.setEnabled(False)
                    self.button_uninstall.setEnabled(False)
                # Update the web_view_details frame
                self.show_collection_metadata(current_coll_id)
            else:
                self.button_install.setEnabled(False)
                self.button_install.setText('Install')
                self.button_open.setEnabled(False)
                self.button_uninstall.setEnabled(False)

    def open_collection(self):
        """Slot for when user clicks 'Open' button."""
        collection_path = local_collection_path(self._selected_collection_id)
        directory_url = QUrl.fromLocalFile(str(collection_path))
        QDesktopServices.openUrl(directory_url)

    def reload_data_and_widget(self):
        """Reload repositories and collections and update widgets related."""
        self.reload_repositories_widget()
        self.reload_collections_model()

    def reload_repositories_widget(self):
        """Refresh tree repositories using new repositories data."""
        self.repository_manager.load_directories()
        self.populate_repositories_widget()

    def populate_repositories_widget(self):
        """Populate the current dictionary repositories to the tree widget."""
        # Clear the current tree widget
        self.tree_repositories.clear()
        installed_collections = \
            self.collection_manager.get_installed_collections()
        # Export the updated ones from the repository manager
        for repo_name in self.repository_manager.directories:
            url = self.repository_manager.directories[repo_name]['url']
            item = QTreeWidgetItem(self.tree_repositories, REPOSITORY_ITEM)
            item.setText(0, repo_name)
            item.setText(1, url)
            for coll_id in config.COLLECTIONS:
                if ('repository_name' in config.COLLECTIONS[coll_id].keys()
                        and config.COLLECTIONS[coll_id]['repository_name']
                        == repo_name):
                    coll_name = config.COLLECTIONS[coll_id]['name']
                    coll_tags = config.COLLECTIONS[coll_id]['tags']
                    collectionItem = QTreeWidgetItem(item, COLLECTION_ITEM)
                    collitemtext = coll_name
                    if installed_collections and coll_id in installed_collections.keys(
                    ):
                        collitemtext = coll_name + ' (installed)'
                        collectionFont = QFont()
                        collectionFont.setWeight(60)
                        collectionItem.setFont(0, collectionFont)
                    collectionItem.setText(0, collitemtext)
                    collectionItem.setText(1, coll_tags)
        self.tree_repositories.resizeColumnToContents(0)
        self.tree_repositories.resizeColumnToContents(1)
        self.tree_repositories.sortItems(1, Qt.AscendingOrder)

    def reload_collections_model(self):
        """Reload the collections model with the current collections."""
        self.collections_model.clear()
        installed_collections = \
            self.collection_manager.get_installed_collections()
        for id in config.COLLECTIONS:
            collection_name = config.COLLECTIONS[id]['name']
            collection_author = config.COLLECTIONS[id]['author']
            collection_tags = config.COLLECTIONS[id]['tags']
            collection_description = config.COLLECTIONS[id]['description']
            collection_status = config.COLLECTIONS[id]['status']
            repository_name = ''
            if 'repository_name' in config.COLLECTIONS[id].keys():
                repository_name = config.COLLECTIONS[id]['repository_name']
            item = QStandardItem(collection_name + ' (' + repository_name +
                                 ')')
            item.setEditable(False)
            item.setData(id, COLLECTION_ID_ROLE)
            item.setData(collection_name, COLLECTION_NAME_ROLE)
            item.setData(collection_description, COLLECTION_DESCRIPTION_ROLE)
            item.setData(collection_author, COLLECTION_AUTHOR_ROLE)
            item.setData(collection_tags, COLLECTION_TAGS_ROLE)
            item.setData(collection_status, COLLECTION_STATUS_ROLE)
            # Make installed collections stand out
            if installed_collections and id in installed_collections.keys():
                collectionFont = QFont()
                collectionFont.setWeight(60)
                item.setFont(collectionFont)
            self.collections_model.appendRow(item)
        self.collections_model.sort(0, Qt.AscendingOrder)

    def on_tree_repositories_itemSelectionChanged(self):
        """Slot for the itemSelectionChanged signal of tree_repositories."""
        selected_item = self.tree_repositories.currentItem()
        if selected_item and selected_item.type() == REPOSITORY_ITEM:
            if selected_item:
                repo_name = selected_item.text(0)
            if not repo_name:
                return
            if not repo_name in self.repository_manager.directories.keys():
                return
            repo_url = self.repository_manager.directories[repo_name]['url']
            # Disable the edit and delete buttons for "official" repositories
            if repo_url in self.repository_manager._online_directories.values(
            ):
                self.button_edit.setEnabled(False)
                self.button_delete.setEnabled(False)
            else:
                # Activate the edit and delete buttons
                self.button_edit.setEnabled(True)
                self.button_delete.setEnabled(True)
        elif selected_item and selected_item.type() == COLLECTION_ITEM:
            self.button_edit.setEnabled(False)
            self.button_delete.setEnabled(False)
        else:
            self.button_edit.setEnabled(False)
            self.button_delete.setEnabled(False)

    def on_list_view_collections_clicked(self, index):
        """Slot for when the list_view_collections is clicked."""
        real_index = self.collection_proxy.mapToSource(index)
        if real_index.row() != -1:
            collection_item = self.collections_model.itemFromIndex(real_index)
            collection_id = collection_item.data(COLLECTION_ID_ROLE)
            self._selected_collection_id = collection_id

            # Enable / disable buttons
            status = config.COLLECTIONS[self._selected_collection_id]['status']
            is_installed = status == COLLECTION_INSTALLED_STATUS
            if is_installed:
                self.button_install.setEnabled(True)
                self.button_install.setText('Reinstall')
                self.button_open.setEnabled(True)
                self.button_uninstall.setEnabled(True)
            else:
                self.button_install.setEnabled(True)
                self.button_install.setText('Install')
                self.button_open.setEnabled(False)
                self.button_uninstall.setEnabled(False)

            # Show  metadata
            self.show_collection_metadata(collection_id)

    @pyqtSlot(str)
    def filter_collections(self, text):
        search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
        self.collection_proxy.setFilterRegExp(search)

    def show_collection_metadata(self, id):
        """Show the collection metadata given the ID."""
        html = self.collection_manager.get_html(id)
        self.web_view_details.setHtml(html)

    def reject(self):
        """Slot when the dialog is closed."""
        # Serialize collections to settings
        self.repository_manager.serialize_repositories()
        self.done(0)

    def open_help(self):
        """Open help."""
        doc_url = QUrl('http://qgis-contribution.github.io/' +
                       'QGIS-ResourceSharing/')
        QDesktopServices.openUrl(doc_url)

    def show_progress_dialog(self, text):
        """Show infinite progress dialog with given text.

        :param text: Text as the label of the progress dialog
        :type text: str
        """
        if self.progress_dialog is None:
            self.progress_dialog = QProgressDialog(self)
            self.progress_dialog.setWindowModality(Qt.WindowModal)
            self.progress_dialog.setAutoClose(False)
            title = self.tr('Resource Sharing')
            self.progress_dialog.setWindowTitle(title)
            # Just use an infinite progress bar here
            self.progress_dialog.setMaximum(0)
            self.progress_dialog.setMinimum(0)
            self.progress_dialog.setValue(0)
            self.progress_dialog.setLabelText(text)

        self.progress_dialog.show()
示例#27
0
class DialogImportData(QDialog, DIALOG_UI):
    def __init__(self, iface, db, qgis_utils):
        QDialog.__init__(self)
        self.setupUi(self)

        QgsGui.instance().enableAutoGeometryRestore(self)
        self.iface = iface
        self.db = db
        self.qgis_utils = qgis_utils
        self.base_configuration = BaseConfiguration()

        self.ilicache = IliCache(self.base_configuration)
        self.ilicache.refresh()

        self._conf_db = ConfigDbSupported()
        self._params = None
        self._current_db = None

        self.xtf_file_browse_button.clicked.connect(
            make_file_selector(
                self.xtf_file_line_edit,
                title=QCoreApplication.translate(
                    "DialogImportData", 'Open Transfer or Catalog File'),
                file_filter=QCoreApplication.translate(
                    "DialogImportData",
                    'Transfer File (*.xtf *.itf);;Catalogue File (*.xml *.xls *.xlsx)'
                )))

        self.validators = Validators()
        self.xtf_file_line_edit.setPlaceholderText(
            QCoreApplication.translate("DialogImportData",
                                       "[Name of the XTF to be created]"))
        fileValidator = FileValidator(pattern=['*.xtf', '*.itf', '*.xml'])
        self.xtf_file_line_edit.setValidator(fileValidator)
        self.xtf_file_line_edit.textChanged.connect(self.update_import_models)
        self.xtf_file_line_edit.textChanged.emit(
            self.xtf_file_line_edit.text())

        # db
        self.connection_setting_button.clicked.connect(self.show_settings)

        self.connection_setting_button.setText(
            QCoreApplication.translate("DialogImportData",
                                       'Connection Settings'))

        # LOG
        self.log_config.setTitle(
            QCoreApplication.translate("DialogImportData", "Show log"))

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop)

        self.buttonBox.accepted.disconnect()
        self.buttonBox.accepted.connect(self.accepted)
        self.buttonBox.clear()
        self.buttonBox.addButton(QDialogButtonBox.Cancel)
        self._accept_button = self.buttonBox.addButton(
            QCoreApplication.translate("DialogImportData", "Import data"),
            QDialogButtonBox.AcceptRole)
        self.buttonBox.addButton(QDialogButtonBox.Help)
        self.buttonBox.helpRequested.connect(self.show_help)

        self.update_connection_info()
        self.restore_configuration()

    def update_connection_info(self):
        db_description = self.db.get_description_conn_string()
        if db_description:
            self.db_connect_label.setText(db_description)
            self.db_connect_label.setToolTip(self.db.get_display_conn_string())
            self._accept_button.setEnabled(True)
        else:
            self.db_connect_label.setText(
                QCoreApplication.translate("DialogImportData",
                                           "The database is not defined!"))
            self.db_connect_label.setToolTip('')
            self._accept_button.setEnabled(False)

    def update_import_models(self):
        message_error = None

        if not self.xtf_file_line_edit.text().strip():
            color = '#ffd356'  # Light orange
            self.import_models_qmodel = QStandardItemModel()
            self.import_models_list_view.setModel(self.import_models_qmodel)
        else:

            if os.path.isfile(self.xtf_file_line_edit.text().strip()):
                color = '#fff'  # White

                self.import_models_qmodel = QStandardItemModel()
                models_name = self.find_models_xtf(
                    self.xtf_file_line_edit.text().strip())

                for model_name in models_name:
                    if not model_name in DEFAULT_HIDDEN_MODELS:
                        item = QStandardItem(model_name)
                        item.setCheckable(False)
                        item.setEditable(False)
                        self.import_models_qmodel.appendRow(item)

                if self.import_models_qmodel.rowCount() > 0:
                    self.import_models_list_view.setModel(
                        self.import_models_qmodel)
                else:
                    message_error = QCoreApplication.translate(
                        "DialogImportData",
                        "No models were found in the XTF. Is it a valid file?")
                    color = '#ffd356'  # Light orange
                    self.import_models_qmodel = QStandardItemModel()
                    self.import_models_list_view.setModel(
                        self.import_models_qmodel)
            else:
                message_error = QCoreApplication.translate(
                    "DialogImportData", "Please set a valid XTF file")
                color = '#ffd356'  # Light orange
                self.import_models_qmodel = QStandardItemModel()
                self.import_models_list_view.setModel(
                    self.import_models_qmodel)
        self.xtf_file_line_edit.setStyleSheet(
            'QLineEdit {{ background-color: {} }}'.format(color))

        if message_error:
            self.txtStdout.setText(message_error)
            self.show_message(message_error, Qgis.Warning)
            self.import_models_list_view.setFocus()
            return

    def find_models_xtf(self, xtf_path):
        models_name = list()
        pattern = re.compile(r'<MODEL[^>]*>(?P<text>[^<]*)</MODEL>')
        with open(xtf_path, 'r') as f:
            for txt in pattern.finditer(f.read()):
                model_tag = str(txt.group(0))
                name = re.findall('NAME="(.*?)"', model_tag, re.IGNORECASE)
                models_name.extend(name)
        return models_name

    def get_ili_models(self):
        ili_models = list()
        for index in range(self.import_models_qmodel.rowCount()):
            item = self.import_models_qmodel.item(index)
            ili_models.append(item.text())
        return ili_models

    def show_settings(self):
        dlg = self.qgis_utils.get_settings_dialog()
        dlg.set_action_type(EnumDbActionType.IMPORT)
        dlg.tabWidget.setCurrentIndex(SETTINGS_CONNECTION_TAB_INDEX)
        if dlg.exec_():
            self.db = dlg.get_db_connection()
            self.update_connection_info()

    def accepted(self):
        configuration = self.update_configuration()

        if not os.path.isfile(self.xtf_file_line_edit.text().strip()):
            message_error = 'Please set a valid XTF file before importing data. XTF file does not exist'
            self.txtStdout.setText(
                QCoreApplication.translate("DialogImportData", message_error))
            self.show_message(message_error, Qgis.Warning)
            self.xtf_file_line_edit.setFocus()
            return

        if not self.xtf_file_line_edit.validator().validate(
                configuration.xtffile, 0)[0] == QValidator.Acceptable:
            message_error = 'Please set a valid XTF before importing data.'
            self.txtStdout.setText(
                QCoreApplication.translate("DialogImportData", message_error))
            self.show_message(message_error, Qgis.Warning)
            self.xtf_file_line_edit.setFocus()
            return

        if not self.get_ili_models():
            message_error = QCoreApplication.translate(
                "DialogImportData",
                "The selected XTF file does not have information according to the LADM-COL model to import."
            )
            self.txtStdout.setText(message_error)
            self.show_message(message_error, Qgis.Warning)
            self.import_models_list_view.setFocus()
            return

        with OverrideCursor(Qt.WaitCursor):
            self.progress_bar.show()
            self.progress_bar.setValue(0)

            self.disable()
            self.txtStdout.setTextColor(QColor('#000000'))
            self.txtStdout.clear()

            dataImporter = iliimporter.Importer(dataImport=True)

            item_db = self._conf_db.get_db_items()[self.db.mode]

            dataImporter.tool_name = item_db.get_model_baker_tool_name()
            dataImporter.configuration = configuration

            self.save_configuration(configuration)

            dataImporter.stdout.connect(self.print_info)
            dataImporter.stderr.connect(self.on_stderr)
            dataImporter.process_started.connect(self.on_process_started)
            dataImporter.process_finished.connect(self.on_process_finished)

            self.progress_bar.setValue(25)

            try:
                if dataImporter.run() != iliimporter.Importer.SUCCESS:
                    self.enable()
                    self.progress_bar.hide()
                    self.show_message(
                        QCoreApplication.translate(
                            "DialogImportData",
                            "An error occurred when importing the data. For more information see the log..."
                        ), Qgis.Warning)
                    return
            except JavaNotFoundError:

                # Set JAVA PATH
                get_java_path_dlg = DialogGetJavaPath()
                get_java_path_dlg.setModal(True)
                if get_java_path_dlg.exec_():
                    configuration = self.update_configuration()

                if not get_java_path_from_qgis_model_baker():
                    message_error_java = QCoreApplication.translate(
                        "DialogImportData",
                        """Java could not be found. You can configure the JAVA_HOME environment variable, restart QGIS and try again."""
                    )
                    self.txtStdout.setTextColor(QColor('#000000'))
                    self.txtStdout.clear()
                    self.txtStdout.setText(message_error_java)
                    self.show_message(message_error_java, Qgis.Warning)
                self.enable()
                self.progress_bar.hide()
                return

            self.buttonBox.clear()
            self.buttonBox.setEnabled(True)
            self.buttonBox.addButton(QDialogButtonBox.Close)
            self.progress_bar.setValue(100)
            self.show_message(
                QCoreApplication.translate(
                    "DialogImportData",
                    "Import of the data was successfully completed"),
                Qgis.Success)

    def save_configuration(self, configuration):
        settings = QSettings()
        settings.setValue(
            'Asistente-LADM_COL/QgisModelBaker/ili2pg/xtffile_import',
            configuration.xtffile)
        settings.setValue('Asistente-LADM_COL/QgisModelBaker/show_log',
                          not self.log_config.isCollapsed())

    def restore_configuration(self):
        settings = QSettings()
        self.xtf_file_line_edit.setText(
            settings.value(
                'Asistente-LADM_COL/QgisModelBaker/ili2pg/xtffile_import'))

        # Show log
        value_show_log = settings.value(
            'Asistente-LADM_COL/QgisModelBaker/show_log', False, type=bool)
        self.log_config.setCollapsed(not value_show_log)

        # set model repository
        # if there is no option  by default use online model repository
        self.use_local_models = settings.value(
            'Asistente-LADM_COL/models/custom_model_directories_is_checked',
            type=bool)
        if self.use_local_models:
            self.custom_model_directories = settings.value(
                'Asistente-LADM_COL/models/custom_models') if settings.value(
                    'Asistente-LADM_COL/models/custom_models') else None

    def update_configuration(self):
        """
        Get the configuration that is updated with the user configuration changes on the dialog.
        :return: Configuration
        """
        item_db = self._conf_db.get_db_items()[self.db.mode]

        configuration = ImportDataConfiguration()
        item_db.set_db_configuration_params(self.db.dict_conn_params,
                                            configuration)

        configuration.xtffile = self.xtf_file_line_edit.text().strip()
        configuration.delete_data = False

        configuration.epsg = DEFAULT_EPSG
        configuration.inheritance = DEFAULT_INHERITANCE
        configuration.create_basket_col = CREATE_BASKET_COL
        configuration.create_import_tid = CREATE_IMPORT_TID
        configuration.stroke_arcs = STROKE_ARCS

        java_path = get_java_path_from_qgis_model_baker()
        if java_path:
            self.base_configuration.java_path = java_path

        # Check custom model directories
        if self.use_local_models:
            if self.custom_model_directories is None:
                self.base_configuration.custom_model_directories_enabled = False
            else:
                self.base_configuration.custom_model_directories = self.custom_model_directories
                self.base_configuration.custom_model_directories_enabled = True

        configuration.base_configuration = self.base_configuration
        if self.get_ili_models():
            configuration.ilimodels = ';'.join(self.get_ili_models())

        configuration.disable_validation = not QSettings().value(
            'Asistente-LADM_COL/advanced_settings/validate_data_importing_exporting',
            True, bool)

        return configuration

    def print_info(self, text, text_color='#000000', clear=False):
        self.txtStdout.setTextColor(QColor(text_color))
        self.txtStdout.append(text)
        QCoreApplication.processEvents()

    def on_stderr(self, text):
        color_log_text(text, self.txtStdout)
        self.advance_progress_bar_by_text(text)

    def on_process_started(self, command):
        self.disable()
        self.txtStdout.setTextColor(QColor('#000000'))
        self.txtStdout.clear()
        self.txtStdout.setText(command)
        QCoreApplication.processEvents()

    def on_process_finished(self, exit_code, result):
        color = '#004905' if exit_code == 0 else '#aa2222'
        self.txtStdout.setTextColor(QColor(color))
        self.txtStdout.append('Finished ({})'.format(exit_code))
        if result == iliimporter.Importer.SUCCESS:
            self.buttonBox.clear()
            self.buttonBox.setEnabled(True)
            self.buttonBox.addButton(QDialogButtonBox.Close)
        else:
            self.show_message(
                QCoreApplication.translate("DialogImportData",
                                           "Error when importing data"),
                Qgis.Warning)
            self.enable()

            # Open log
            if self.log_config.isCollapsed():
                self.log_config.setCollapsed(False)

    def advance_progress_bar_by_text(self, text):
        if text.strip() == 'Info: compile models...':
            self.progress_bar.setValue(50)
            QCoreApplication.processEvents()
        elif text.strip() == 'Info: create table structure...':
            self.progress_bar.setValue(55)
            QCoreApplication.processEvents()
        elif text.strip() == 'Info: first validation pass...':
            self.progress_bar.setValue(60)
            QCoreApplication.processEvents()
        elif text.strip() == 'Info: second validation pass...':
            self.progress_bar.setValue(80)
            QCoreApplication.processEvents()

    def show_help(self):
        self.qgis_utils.show_help("import_data")

    def disable(self):
        self.db_config.setEnabled(False)
        self.ili_config.setEnabled(False)
        self.buttonBox.setEnabled(False)

    def enable(self):
        self.db_config.setEnabled(True)
        self.ili_config.setEnabled(True)
        self.buttonBox.setEnabled(True)

    def show_message(self, message, level):
        self.bar.pushMessage("Asistente LADM_COL", message, level, duration=0)
示例#28
0
class MultipleInputDialog(BASE, WIDGET):
    def __init__(self, options, selectedoptions=None, datatype=None):
        super(MultipleInputDialog, self).__init__(None)
        self.setupUi(self)
        self.datatype = datatype
        self.model = None

        self.options = []
        for i, option in enumerate(options):
            if option is None or isinstance(option, str):
                self.options.append((i, option))
            else:
                self.options.append((option[0], option[1]))

        self.selectedoptions = selectedoptions or []

        # Additional buttons
        self.btnSelectAll = QPushButton(self.tr('Select All'))
        self.buttonBox.addButton(self.btnSelectAll,
                                 QDialogButtonBox.ActionRole)
        self.btnClearSelection = QPushButton(self.tr('Clear Selection'))
        self.buttonBox.addButton(self.btnClearSelection,
                                 QDialogButtonBox.ActionRole)
        self.btnToggleSelection = QPushButton(self.tr('Toggle Selection'))
        self.buttonBox.addButton(self.btnToggleSelection,
                                 QDialogButtonBox.ActionRole)
        if self.datatype is not None:
            btnAddFile = QPushButton(
                QCoreApplication.translate("MultipleInputDialog",
                                           'Add File(s)…'))
            btnAddFile.clicked.connect(self.addFiles)
            self.buttonBox.addButton(btnAddFile, QDialogButtonBox.ActionRole)

        self.btnSelectAll.clicked.connect(lambda: self.selectAll(True))
        self.btnClearSelection.clicked.connect(lambda: self.selectAll(False))
        self.btnToggleSelection.clicked.connect(self.toggleSelection)

        self.settings = QgsSettings()
        self.restoreGeometry(
            self.settings.value("/Processing/multipleInputDialogGeometry",
                                QByteArray()))

        self.lstLayers.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.lstLayers.setDragDropMode(QAbstractItemView.InternalMove)

        self.populateList()
        self.finished.connect(self.saveWindowGeometry)

    def saveWindowGeometry(self):
        self.settings.setValue("/Processing/multipleInputDialogGeometry",
                               self.saveGeometry())

    def populateList(self):
        self.model = QStandardItemModel()
        for value, text in self.options:
            item = QStandardItem(text)
            item.setData(value, Qt.UserRole)
            item.setCheckState(Qt.Checked if value in
                               self.selectedoptions else Qt.Unchecked)
            item.setCheckable(True)
            item.setDropEnabled(False)
            self.model.appendRow(item)

        # add extra options (e.g. manually added layers)
        for t in [o for o in self.selectedoptions if not isinstance(o, int)]:
            if isinstance(t, QgsProcessingModelChildParameterSource):
                item = QStandardItem(t.staticValue())
            else:
                item = QStandardItem(t)
            item.setData(item.text(), Qt.UserRole)
            item.setCheckState(Qt.Checked)
            item.setCheckable(True)
            item.setDropEnabled(False)
            self.model.appendRow(item)

        self.lstLayers.setModel(self.model)

    def accept(self):
        self.selectedoptions = []
        model = self.lstLayers.model()
        for i in range(model.rowCount()):
            item = model.item(i)
            if item.checkState() == Qt.Checked:
                self.selectedoptions.append(item.data(Qt.UserRole))
        QDialog.accept(self)

    def reject(self):
        self.selectedoptions = None
        QDialog.reject(self)

    def getItemsToModify(self):
        items = []
        if len(self.lstLayers.selectedIndexes()) > 1:
            for i in self.lstLayers.selectedIndexes():
                items.append(self.model.itemFromIndex(i))
        else:
            for i in range(self.model.rowCount()):
                items.append(self.model.item(i))
        return items

    def selectAll(self, value):
        for item in self.getItemsToModify():
            item.setCheckState(Qt.Checked if value else Qt.Unchecked)

    def toggleSelection(self):
        for item in self.getItemsToModify():
            checked = item.checkState() == Qt.Checked
            item.setCheckState(Qt.Unchecked if checked else Qt.Checked)

    def getFileFilter(self, datatype):
        """
        Returns a suitable file filter pattern for the specified parameter definition
        :param param:
        :return:
        """
        if datatype == QgsProcessing.TypeRaster:
            return QgsProviderRegistry.instance().fileRasterFilters()
        elif datatype == QgsProcessing.TypeFile:
            return self.tr('All files (*.*)')
        else:
            exts = QgsVectorFileWriter.supportedFormatExtensions()
            for i in range(len(exts)):
                exts[i] = self.tr('{0} files (*.{1})').format(
                    exts[i].upper(), exts[i].lower())
            return self.tr('All files (*.*)') + ';;' + ';;'.join(exts)

    def addFiles(self):
        filter = self.getFileFilter(self.datatype)

        settings = QgsSettings()
        path = str(settings.value('/Processing/LastInputPath'))

        ret, selected_filter = QFileDialog.getOpenFileNames(
            self, self.tr('Select File(s)'), path, filter)
        if ret:
            files = list(ret)
            settings.setValue('/Processing/LastInputPath',
                              os.path.dirname(str(files[0])))
            for filename in files:
                item = QStandardItem(filename)
                item.setData(filename, Qt.UserRole)
                item.setCheckState(Qt.Checked)
                item.setCheckable(True)
                item.setDropEnabled(False)
                self.model.appendRow(item)
示例#29
0
class MultipleSelectTreeView(QListView):
    """
    Custom QListView implementation that displays checkable items from a
    multiple select column type.
    """
    def __init__(self, column, parent=None):
        """
        Class constructor.
        :param column: Multiple select column object.
        :type column: MultipleSelectColumn
        :param parent: Parent widget for the control.
        :type parent: QWidget
        """
        QListView.__init__(self, parent)

        # Disable editing of lookup values
        self.setEditTriggers(QAbstractItemView.NoEditTriggers)

        self.column = column

        self._item_model = QStandardItemModel(self)

        self._value_list = self.column.value_list

        # Stores lookup objects based on primary keys
        self._lookup_cache = {}

        self._initialize()

        self._association = self.column.association

        self._first_parent_col = self._association.first_reference_column.name
        self._second_parent_col = self._association.second_reference_column.name

        # Association model
        self._assoc_cls = entity_model(self._association)

    def reset_model(self):
        """
        Resets the item model.
        """
        self._item_model.clear()
        self._item_model.setColumnCount(2)

    def clear(self):
        """
        Clears all items in the model.
        """
        self._item_model.clear()

    @property
    def association(self):
        """
        :return: Returns the association object corresponding to the column.
        :rtype: AssociationEntity
        """
        return self._association

    @property
    def value_list(self):
        """
        :return: Returns the ValueList object corresponding to the configured
        column object.
        :rtype: ValueList
        """
        return self._value_list

    @property
    def item_model(self):
        """
        :return: Returns the model corresponding to the checkable items.
        :rtype: QStandardItemModel
        """
        return self._item_model

    def _add_item(self, id, value):
        """
        Adds a row corresponding to id and corresponding value from a lookup
        table.
        :param id: Primary key of a lookup record.
        :type id: int
        :param value: Lookup value
        :type value: str
        """
        value_item = QStandardItem(value)
        value_item.setCheckable(True)
        id_item = QStandardItem(str(id))

        self._item_model.appendRow([value_item, id_item])

    def _initialize(self):
        # Populate list with lookup items
        self.reset_model()

        # Add all lookup values in the value list table
        vl_cls = entity_model(self._value_list)
        if not vl_cls is None:
            vl_obj = vl_cls()
            res = vl_obj.queryObject().all()
            for r in res:
                self._lookup_cache[r.id] = r
                self._add_item(r.id, r.value)

        self.setModel(self._item_model)

    def clear_selection(self):
        """
        Unchecks all items in the view.
        """
        for i in range(self._item_model.rowCount()):
            value_item = self._item_model.item(i, 0)

            if value_item.checkState() == Qt.Checked:
                value_item.setCheckState(Qt.Unchecked)

                if value_item.rowCount() > 0:
                    value_item.removeRow(0)

    def selection(self):
        """
        :return: Returns a list of selected items.
        :rtype: list
        """
        selection = []

        for i in range(self._item_model.rowCount()):
            value_item = self._item_model.item(i, 0)

            if value_item.checkState() == Qt.Checked:
                id_item = self._item_model.item(i, 1)
                id = int(id_item.text())

                # Get item from the lookup cache and append to selection
                if id in self._lookup_cache:
                    lookup_rec = self._lookup_cache[id]
                    selection.append(lookup_rec)

        return selection

    def set_selection(self, models):
        """
        Checks items corresponding to the specified models.
        :param models: List containing model values in the view for selection.
        :type models: list
        """
        for m in models:
            search_value = m.value
            v_items = self._item_model.findItems(search_value)

            # Loop through result and check items
            for vi in v_items:
                if vi.checkState() == Qt.Unchecked:
                    vi.setCheckState(Qt.Checked)
class ResourceSharingDialog(QDialog, FORM_CLASS):
    TAB_ALL = 0
    TAB_INSTALLED = 1
    TAB_SETTINGS = 2

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

        :param parent: Optional widget to use as parent
        :type parent: QWidget

        :param iface: An instance of QGisInterface
        :type iface: QGisInterface
        """
        super(ResourceSharingDialog, self).__init__(parent)
        self.setupUi(self)
        self.iface = iface

        # Reconfigure UI
        self.setModal(True)
        self.button_edit.setEnabled(False)
        self.button_delete.setEnabled(False)
        self.button_install.setEnabled(False)
        self.button_open.setEnabled(False)
        self.button_uninstall.setEnabled(False)

        # Set QListWidgetItem
        # All
        icon_all = QIcon()
        icon_all.addFile(
            resources_path('img', 'plugin.svg'),
            QSize(),
            QIcon.Normal,
            QIcon.Off)
        item_all = QListWidgetItem()
        item_all.setIcon(icon_all)
        item_all.setText(self.tr('All'))
        # Installed
        icon_installed = QIcon()
        icon_installed.addFile(
            resources_path('img', 'plugin-installed.svg'),
            QSize(),
            QIcon.Normal,
            QIcon.Off)
        item_installed = QListWidgetItem()
        item_installed.setIcon(icon_installed)
        item_installed.setText(self.tr('Installed'))
        item_all.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
        # Settings
        icon_settings = QIcon()
        icon_settings.addFile(
            resources_path('img', 'settings.svg'),
            QSize(),
            QIcon.Normal,
            QIcon.Off)
        item_settings = QListWidgetItem()
        item_settings.setIcon(icon_settings)
        item_settings.setText(self.tr('Settings'))
        item_all.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)

        # Add the list widget item to the widget
        self.menu_list_widget.addItem(item_all)
        self.menu_list_widget.addItem(item_installed)
        self.menu_list_widget.addItem(item_settings)

        # Init the message bar
        self.message_bar = QgsMessageBar(self)
        self.message_bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.vlayoutRightColumn.insertWidget(0, self.message_bar)

        # Progress dialog for any long running process
        self.progress_dialog = None

        # Init repository manager
        self.repository_manager = RepositoryManager()
        self.collection_manager = CollectionManager()
        # Collections list view
        self.collections_model = QStandardItemModel(0, 1)
        self.collections_model.sort(0, Qt.AscendingOrder)
        self.collection_proxy = CustomSortFilterProxyModel(self)
        self.collection_proxy.setSourceModel(self.collections_model)
        self.list_view_collections.setModel(self.collection_proxy)
        # Active selected collection
        self._selected_collection_id = None

        # Slots
        self.button_add.clicked.connect(self.add_repository)
        self.button_edit.clicked.connect(self.edit_repository)
        self.button_delete.clicked.connect(self.delete_repository)
        self.button_reload.clicked.connect(self.reload_repositories)
        self.menu_list_widget.currentRowChanged.connect(self.set_current_tab)
        self.list_view_collections.selectionModel().currentChanged.connect(
            self.on_list_view_collections_clicked)
        self.line_edit_filter.textChanged.connect(self.filter_collections)
        self.button_install.clicked.connect(self.install_collection)
        self.button_open.clicked.connect(self.open_collection)
        self.button_uninstall.clicked.connect(self.uninstall_collection)
        self.button_box.button(QDialogButtonBox.Help).clicked.connect(
            self.open_help)

        # Populate repositories widget and collections list view
        self.populate_repositories_widget()
        self.reload_collections_model()

    def set_current_tab(self, index):
        """Set stacked widget based on active tab.

        :param index: The index of the active list widget item.
        :type index: int
        """
        # Clear message bar first
        self.message_bar.clearWidgets()
        if index == (self.menu_list_widget.count() - 1):
            # Switch to settings tab
            self.stacked_menu_widget.setCurrentIndex(1)
        else:
            # Switch to plugins tab
            if index == 1:
                # Installed
                self.collection_proxy.accepted_status = \
                    COLLECTION_INSTALLED_STATUS
                # Set the web view
                title = self.tr('Installed Collections')
                description = self.tr(
                    'On the left you see the list of all collections '
                    'installed on your QGIS')
            else:
                # All
                self.collection_proxy.accepted_status = COLLECTION_ALL_STATUS
                # Set the web view
                title = self.tr('All Collections')
                description = self.tr(
                    'On the left you see the list of all collections '
                    'available from the repositories registered in the '
                    'settings.')

            context = {
                'resources_path': resources_path(),
                'title': title,
                'description': description
            }
            self.web_view_details.setHtml(
                render_template('tab_description.html', context))
            self.stacked_menu_widget.setCurrentIndex(0)

    def add_repository(self):
        """Open add repository dialog."""
        dlg = ManageRepositoryDialog(self)
        if not dlg.exec_():
            return

        for repo in self.repository_manager.directories.values():
            if dlg.line_edit_url.text().strip() == repo['url']:
                self.message_bar.pushMessage(
                    self.tr(
                        'Unable to add another repository with the same URL!'),
                    Qgis.Critical, 5)
                return

        repo_name = dlg.line_edit_name.text()
        repo_url = dlg.line_edit_url.text().strip()
        repo_auth_cfg = dlg.line_edit_auth_id.text().strip()
        if repo_name in self.repository_manager.directories:
            repo_name += '(2)'

        # Show progress dialog
        self.show_progress_dialog("Fetching repository's metadata")

        # Add repository
        try:
            status, description = self.repository_manager.add_directory(
                repo_name, repo_url, repo_auth_cfg)
            if status:
                self.message_bar.pushMessage(
                    self.tr(
                        'Repository is successfully added'),
                    Qgis.Success, 5)
            else:
                self.message_bar.pushMessage(
                    self.tr(
                        'Unable to add repository: %s') % description,
                    Qgis.Critical, 5)
        except Exception as e:
            self.message_bar.pushMessage(
                self.tr('%s') % e,
                Qgis.Critical, 5)
        finally:
            self.progress_dialog.hide()

        # Reload data and widget
        self.reload_data_and_widget()

        # Deactivate edit and delete button
        self.button_edit.setEnabled(False)
        self.button_delete.setEnabled(False)

    def edit_repository(self):
        """Open edit repository dialog."""
        selected_item = self.tree_repositories.currentItem()
        if selected_item:
            repo_name = selected_item.text(0)

        if not repo_name:
            return

        # Check if it's the approved online dir repository
        settings = QSettings()
        settings.beginGroup(repo_settings_group())
        if settings.value(repo_name + '/url') in \
                self.repository_manager._online_directories.values():
            self.message_bar.pushMessage(
                self.tr(
                    'You can not edit the official repositories!'),
                Qgis.Warning, 5)
            return

        dlg = ManageRepositoryDialog(self)
        dlg.line_edit_name.setText(repo_name)
        dlg.line_edit_url.setText(
            self.repository_manager.directories[repo_name]['url'])
        dlg.line_edit_auth_id.setText(
            self.repository_manager.directories[repo_name]['auth_cfg'])

        if not dlg.exec_():
            return

        # Check if the changed URL is already there in the repo
        new_url = dlg.line_edit_url.text().strip()
        old_url = self.repository_manager.directories[repo_name]['url']
        for repo in self.repository_manager.directories.values():
            if new_url == repo['url'] and (old_url != new_url):
                self.message_bar.pushMessage(
                    self.tr('Unable to add another repository with the same '
                            'URL!'),
                    Qgis.Critical, 5)
                return

        new_name = dlg.line_edit_name.text()
        if (new_name in self.repository_manager.directories) and (
                    new_name != repo_name):
            new_name += '(2)'

        new_auth_cfg = dlg.line_edit_auth_id.text()

        # Show progress dialog
        self.show_progress_dialog("Fetching repository's metadata")

        # Edit repository
        try:
            status, description = self.repository_manager.edit_directory(
                repo_name,
                new_name,
                old_url,
                new_url,
                new_auth_cfg
            )
            if status:
                self.message_bar.pushMessage(
                    self.tr('Repository is successfully updated'),
                    Qgis.Success, 5)
            else:
                self.message_bar.pushMessage(
                    self.tr('Unable to add repository: %s') % description,
                    Qgis.Critical, 5)
        except Exception as e:
            self.message_bar.pushMessage(
                self.tr('%s') % e, Qgis.Critical, 5)
        finally:
            self.progress_dialog.hide()

        # Reload data and widget
        self.reload_data_and_widget()

        # Deactivate edit and delete button
        self.button_edit.setEnabled(False)
        self.button_delete.setEnabled(False)

    def delete_repository(self):
        """Delete a repository in the tree widget."""
        selected_item = self.tree_repositories.currentItem()
        if selected_item:
            repo_name = selected_item.text(0)

        if not repo_name:
            return
        # Check if it's the approved online dir repository
        repo_url = self.repository_manager.directories[repo_name]['url']
        if repo_url in self.repository_manager._online_directories.values():
            self.message_bar.pushMessage(
                self.tr(
                    'You can not remove the official repositories!'),
                Qgis.Warning, 5)
            return

        warning = self.tr('Are you sure you want to remove the following '
                          'repository?') + '\n' + repo_name
        if QMessageBox.warning(
                self,
                self.tr('QGIS Resource Sharing'),
                warning,
                QMessageBox.Yes,
                QMessageBox.No) == QMessageBox.No:
            return

        # Remove repository
        installed_collections = \
            self.collection_manager.get_installed_collections(repo_url)
        if installed_collections:
            message = ('You have some installed collections from this '
                       'repository. Please uninstall them first!')
            self.message_bar.pushMessage(message, Qgis.Warning, 5)
        else:
            self.repository_manager.remove_directory(repo_name)
            # Reload data and widget
            self.reload_data_and_widget()
            # Deactivate edit and delete button
            self.button_edit.setEnabled(False)
            self.button_delete.setEnabled(False)

    def reload_repositories(self):
        """Slot for when user clicks reload repositories button."""
        # Show progress dialog
        self.show_progress_dialog('Reloading all repositories')

        for repo_name in self.repository_manager.directories:
            directory = self.repository_manager.directories[repo_name]
            url = directory['url']
            auth_cfg = directory['auth_cfg']
            try:
                status, description = self.repository_manager.reload_directory(
                    repo_name, url, auth_cfg)
                if status:
                    self.message_bar.pushMessage(
                        self.tr(
                            'Repository %s is successfully reloaded') %
                        repo_name, Qgis.Info, 5)
                else:
                    self.message_bar.pushMessage(
                        self.tr(
                            'Unable to reload %s: %s') % (
                            repo_name, description),
                        Qgis.Critical, 5)
            except Exception as e:
                self.message_bar.pushMessage(
                    self.tr('%s') % e,
                    Qgis.Critical, 5)

        self.progress_dialog.hide()
        # Reload data and widget
        self.reload_data_and_widget()

    def install_collection(self):
        """Slot for when user clicks download button."""
        self.show_progress_dialog('Starting installation process...')
        self.progress_dialog.canceled.connect(self.install_canceled)

        self.installer_thread = QThread()
        self.installer_worker = CollectionInstaller(
            self.collection_manager, self._selected_collection_id)
        self.installer_worker.moveToThread(self.installer_thread)
        self.installer_worker.finished.connect(self.install_finished)
        self.installer_worker.aborted.connect(self.install_aborted)
        self.installer_worker.progress.connect(self.install_progress)
        self.installer_thread.started.connect(self.installer_worker.run)
        self.installer_thread.start()

    def install_finished(self):
        # Process the result
        self.progress_dialog.hide()
        if self.installer_worker.install_status:
            self.reload_collections_model()
            message = '%s is installed successfully' % (
                config.COLLECTIONS[self._selected_collection_id]['name'])
        else:
            message = self.installer_worker.error_message
        QMessageBox.information(self, 'Resource Sharing', message)
        # Clean up the worker and thread
        self.installer_worker.deleteLater()
        self.installer_thread.quit()
        self.installer_thread.wait()
        self.installer_thread.deleteLater()

    def install_canceled(self):
        self.progress_dialog.hide()
        self.show_progress_dialog('Cancelling installation...')
        self.installer_worker.abort()

    def install_aborted(self):
        if self.installer_thread.isRunning():
            self.installer_thread.quit()
        self.installer_thread.finished.connect(self.progress_dialog.hide)

    def install_progress(self, text):
        self.progress_dialog.setLabelText(text)

    def uninstall_collection(self):
        """Slot called when user clicks uninstall button."""
        try:
            self.collection_manager.uninstall(self._selected_collection_id)
        except Exception as e:
            raise
        self.reload_collections_model()
        QMessageBox.information(
            self,
            'Resource Sharing',
            'The collection is uninstalled succesfully!')

    def open_collection(self):
        """Slot for when user clicks 'Open' button."""
        collection_path = local_collection_path(self._selected_collection_id)
        directory_url = QUrl.fromLocalFile(collection_path)
        QDesktopServices.openUrl(directory_url)

    def reload_data_and_widget(self):
        """Reload repositories and collections and update widgets related."""
        self.reload_repositories_widget()
        self.reload_collections_model()

    def reload_repositories_widget(self):
        """Refresh tree repositories using new repositories data."""
        self.repository_manager.load_directories()
        self.populate_repositories_widget()

    def populate_repositories_widget(self):
        """Populate the current dictionary repositories to the tree widget."""
        # Clear the current tree widget
        self.tree_repositories.clear()

        # Export the updated ones from the repository manager
        for repo_name in self.repository_manager.directories:
            url = self.repository_manager.directories[repo_name]['url']
            item = QTreeWidgetItem(self.tree_repositories)
            item.setText(0, repo_name)
            item.setText(1, url)
        self.tree_repositories.resizeColumnToContents(0)
        self.tree_repositories.resizeColumnToContents(1)
        self.tree_repositories.sortItems(1, Qt.AscendingOrder)

    def reload_collections_model(self):
        """Reload the collections model with the current collections."""
        self.collections_model.clear()
        for id in config.COLLECTIONS:
            collection_name = config.COLLECTIONS[id]['name']
            collection_author = config.COLLECTIONS[id]['author']
            collection_tags = config.COLLECTIONS[id]['tags']
            collection_description = config.COLLECTIONS[id]['description']
            collection_status = config.COLLECTIONS[id]['status']
            item = QStandardItem(collection_name)
            item.setEditable(False)
            item.setData(id, COLLECTION_ID_ROLE)
            item.setData(collection_name, COLLECTION_NAME_ROLE)
            item.setData(collection_description, COLLECTION_DESCRIPTION_ROLE)
            item.setData(collection_author, COLLECTION_AUTHOR_ROLE)
            item.setData(collection_tags, COLLECTION_TAGS_ROLE)
            item.setData(collection_status, COLLECTION_STATUS_ROLE)
            self.collections_model.appendRow(item)
        self.collections_model.sort(0, Qt.AscendingOrder)

    def on_tree_repositories_itemSelectionChanged(self):
        """Slot for when the itemSelectionChanged signal emitted."""
        # Activate edit and delete button
        self.button_edit.setEnabled(True)
        self.button_delete.setEnabled(True)

    def on_list_view_collections_clicked(self, index):
        """Slot for when the list_view_collections is clicked."""
        real_index = self.collection_proxy.mapToSource(index)
        if real_index.row() != -1:
            collection_item = self.collections_model.itemFromIndex(real_index)
            collection_id = collection_item.data(COLLECTION_ID_ROLE)
            self._selected_collection_id = collection_id

            # Enable/disable button
            status = config.COLLECTIONS[self._selected_collection_id]['status']
            is_installed = status == COLLECTION_INSTALLED_STATUS
            if is_installed:
                self.button_install.setEnabled(True)
                self.button_install.setText('Reinstall')
                self.button_open.setEnabled(True)
                self.button_uninstall.setEnabled(True)
            else:
                self.button_install.setEnabled(True)
                self.button_install.setText('Install')
                self.button_open.setEnabled(False)
                self.button_uninstall.setEnabled(False)

            # Show  metadata
            self.show_collection_metadata(collection_id)

    @pyqtSlot(str)
    def filter_collections(self, text):
        search = QRegExp(
            text,
            Qt.CaseInsensitive,
            QRegExp.RegExp)
        self.collection_proxy.setFilterRegExp(search)

    def show_collection_metadata(self, id):
        """Show the collection metadata given the id."""
        html = self.collection_manager.get_html(id)
        self.web_view_details.setHtml(html)

    def reject(self):
        """Slot when the dialog is closed."""
        # Serialize collections to settings
        self.repository_manager.serialize_repositories()
        self.done(0)

    def open_help(self):
        """Open help."""
        doc_url = QUrl('http://www.akbargumbira.com/qgis_resources_sharing')
        QDesktopServices.openUrl(doc_url)

    def show_progress_dialog(self, text):
        """Show infinite progress dialog with given text.

        :param text: Text as the label of the progress dialog
        :type text: str
        """
        if self.progress_dialog is None:
            self.progress_dialog = QProgressDialog(self)
            self.progress_dialog.setWindowModality(Qt.WindowModal)
            self.progress_dialog.setAutoClose(False)
            title = self.tr('Resource Sharing')
            self.progress_dialog.setWindowTitle(title)
            # Just use infinite progress bar here
            self.progress_dialog.setMaximum(0)
            self.progress_dialog.setMinimum(0)
            self.progress_dialog.setValue(0)
            self.progress_dialog.setLabelText(text)

        self.progress_dialog.show()
示例#31
0
class ListWidget(EditorWidget):
    widgettype = 'List'

    def __init__(self, *args, **kwargs):
        super(ListWidget, self).__init__(*args, **kwargs)
        self.listmodel = QStandardItemModel()
        self._bindvalue = None

    def createWidget(self, parent):
        return QComboBox(parent)

    def _buildfromlist(self, widget, listconfig):
        items = listconfig['items']
        for item in items:
            parts = item.split(';')
            data = parts[0]
            try:
                desc = parts[1]
            except IndexError:
                desc = data

            try:
                path = parts[2]
                path = path.strip()
                icon = QIcon(path)
            except:
                icon = QIcon()

            item = QStandardItem(desc)
            item.setData(data, Qt.UserRole)
            item.setIcon(icon)
            self.listmodel.appendRow(item)

    def _buildfromlayer(self, widget, layerconfig):
        layername = layerconfig['layer']
        keyfield = layerconfig['key']
        valuefield = layerconfig['value']
        filterexp = layerconfig.get('filter', None)

        try:
            layer = utils.layer_by_name(layername)
        except IndexError:
            roam.utils.warning(
                "Can't find layer {} in project".format(layername))
            return

        keyfieldindex = layer.fields().lookupField(keyfield)
        valuefieldindex = layer.fields().lookupField(valuefield)
        if keyfieldindex == -1 or valuefieldindex == -1:
            roam.utils.warning(f"Can't find key or value column for widget "
                               f"Id: {self.id} "
                               f"Layer: {layername} "
                               f"Key: {keyfield} - {keyfieldindex} "
                               f"Value: {valuefield} - {valuefieldindex} ")
            return

        if self.allownulls:
            item = QStandardItem('(no selection)')
            item.setData(None, Qt.UserRole)
            self.listmodel.appendRow(item)

        fields = [keyfieldindex, valuefieldindex]
        iconfieldindex = layer.fields().lookupField('icon')
        if iconfieldindex > -1:
            fields.append("icon")

        if not filterexp and valuefieldindex == keyfieldindex and iconfieldindex == -1:
            values = layer.uniqueValues(keyfieldindex)
            values = sorted(values)
            for value in values:
                value = nullconvert(value)
                item = QStandardItem(value)
                item.setData(value, Qt.UserRole)
                self.listmodel.appendRow(item)
            return

        features = roam.api.utils.search_layer(layer,
                                               filterexp,
                                               fields,
                                               with_geometry=False)
        # Sort the fields based on value field
        features = sorted(features, key=lambda f: f[keyfield])
        for feature in features:
            keyvalue = nullconvert(feature[keyfieldindex])
            valuvalue = nullconvert(feature[valuefield])
            try:
                path = feature["icon"]
                icon = QIcon(path)
            except KeyError:
                icon = QIcon()

            item = QStandardItem(keyvalue)
            item.setData(str(valuvalue), Qt.UserRole)
            item.setIcon(icon)
            self.listmodel.appendRow(item)

    def initWidget(self, widget, config):
        if widget.isEditable():
            widget.editTextChanged.connect(self.emitvaluechanged)

        widget.currentIndexChanged.connect(self.emitvaluechanged)
        widget.setModel(self.listmodel)
        widget.showPopup = self.showpopup
        widget.setIconSize(QSize(24, 24))
        widget.setStyleSheet(
            "QComboBox::drop-down {border-width: 0px;} QComboBox::down-arrow {image: url(noimg); border-width: 0px;}"
        )
        widget.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)

    def showpopup(self):
        if self.listmodel.rowCount() == 0:
            return

        self.largewidgetrequest.emit(
            BigListWidget, self.widget.currentIndex(), self._biglistitem,
            dict(model=self.listmodel, label=self.labeltext))

    def updatefromconfig(self):
        super(ListWidget, self).updatefromconfig()

        self.listmodel.clear()
        if 'list' in self.config:
            listconfig = self.config['list']
            self._buildfromlist(self.widget, listconfig)
        elif 'layer' in self.config:
            layerconfig = self.config['layer']
            self._buildfromlayer(self.widget, layerconfig)

        super(ListWidget, self).endupdatefromconfig()

    @property
    def allownulls(self):
        return self.config.get('allownull', False)

    def validate(self, *args):
        if (not self.widget.currentText() == ''
                and not self.widget.currentText() == "(no selection)"):
            return True
        else:
            return False

    def _biglistitem(self, index):
        self.widget.setCurrentIndex(index.row())

    def setvalue(self, value):
        self._bindvalue = value
        index = self.widget.findData(value)
        self.widget.setCurrentIndex(index)
        if index == -1 and self.widget.isEditable():
            if value is None and not self.config['allownull']:
                return

            self.widget.addItem(str(value))
            index = self.widget.count() - 1
            self.widget.setCurrentIndex(index)

    def value(self):
        index = self.widget.currentIndex()
        value = self.widget.itemData(index)
        text = self.widget.currentText()
        if value is None and self.widget.isEditable(
        ) and not text == '(no selection)':
            return self.widget.currentText()

        return value
class ThinGreyscaleDialog(QDialog, FORM_CLASS):
    def __init__(self, iface, parent=None):
        """Constructor."""
        self.iface = iface
        self.plugin_dir = dirname(__file__)
        self.THINGREYSCALE = self.tr('ThinGreyscale')
        self.BROWSE = self.tr('Browse')
        self.CANCEL = self.tr('Cancel')
        self.CLOSE = self.tr('Close')
        self.HELP = self.tr('Help')
        self.OK = self.tr('OK')
        self.DEFAULTPROVIDER = 'GTiff'
        self.DEFAULTEXTENSION = '.tif'
        self.EXTRAEXTENSION = ' *.tiff'
        super(ThinGreyscaleDialog, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)

        self.showInfo("Connecting UI components")
        okButton = self.button_box.button(QDialogButtonBox.Ok)
        okButton.setText(self.OK)
        cancelButton = self.button_box.button(QDialogButtonBox.Cancel)
        cancelButton.setText(self.CANCEL)
        cancelButton.setEnabled(False)
        closeButton = self.button_box.button(QDialogButtonBox.Close)
        closeButton.setText(self.CLOSE)
        browseButton = self.browseButton
        browseButton.setText(self.BROWSE)
        self.calcHistPushButton.setEnabled(False)
        self.listModel = QStandardItemModel(self.levelsListView)
        self.levelsListView.setModel(self.listModel)
        self.levelsListView.sizeHintForColumn(20)
        #self.levelValuesCheckBox.setEnabled(False)
        # Help button
        helpButton = self.helpButton
        helpButton.setText(self.HELP)

        # Connect signals
        self.showInfo("Connecting signals")
        okButton.clicked.connect(self.startWorker)
        cancelButton.clicked.connect(self.killWorker)
        closeButton.clicked.connect(self.reject)
        helpButton.clicked.connect(self.help)
        browseButton.clicked.connect(self.browse)

        inpIndexCh = self.inputRaster.currentIndexChanged['QString']
        inpIndexCh.connect(self.layerchanged)
        bandCh = self.bandComboBox.currentIndexChanged['QString']
        bandCh.connect(self.bandChanged)
        #self.iface.legendInterface().itemAdded.connect(
        #    self.layerlistchanged)
        #self.iface.legendInterface().itemRemoved.connect(
        #    self.layerlistchanged)
        #QObject.disconnect(self.button_box, SIGNAL("rejected()"), self.reject)
        self.button_box.rejected.disconnect(self.reject)
        calchistPr = self.calcHistPushButton.clicked
        calchistPr.connect(self.calculateHistogram)
        sugglevPr = self.suggestlevelsPushButton.clicked
        sugglevPr.connect(self.suggestLevels)
        addlevPr = self.addlevelPushButton.clicked
        addlevPr.connect(self.addLevel)
        dellevPr = self.deletelevelsPushButton.clicked
        dellevPr.connect(self.removeLevel)

        maxvalCh = self.maxValueSpinBox.valueChanged
        maxvalCh.connect(self.minmaxvalueChanged)
        maxvalFi = self.maxValueSpinBox.editingFinished
        maxvalFi.connect(self.minmaxvalueEdFinished)
        minvalCh = self.minValueSpinBox.valueChanged
        minvalCh.connect(self.minmaxvalueChanged)
        minvalFi = self.minValueSpinBox.editingFinished
        minvalFi.connect(self.minmaxvalueEdFinished)

        # Set instance variables
        #self.mem_layer = None
        self.worker = None
        self.inputlayerid = None
        self.inputlayer = None
        self.layerlistchanging = False
        self.minvalue = 1
        self.inputrasterprovider = None
        self.histobins = 50
        self.setupScene = QGraphicsScene(self)
        self.histoGraphicsView.setScene(self.setupScene)
        # Is the layer band of an integer type
        self.intband = False
        self.histogramAvailable = False
        self.histo = None
        self.histopadding = 1

    def startWorker(self):
        """Initialises and starts the worker thread."""
        try:
            layerindex = self.inputRaster.currentIndex()
            layerId = self.inputRaster.itemData(layerindex)
            inputlayer = QgsProject.instance().mapLayer(layerId)
            #inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
            if inputlayer is None:
                self.showError(self.tr('No input layer defined'))
                return
            # create a reference to the layer that is being processed
            # (for use when creating the resulting raster layer)
            self.thinninglayer = inputlayer
            self.levels = []
            #self.levelsListView.selectAll()
            #selected = self.levelsListView.selectedIndexes()
            if self.levelsListView.model().rowCount() == 0:
                self.showInfo("Levels must be specified!")
                return
            for i in range(self.levelsListView.model().rowCount()):
                levelstring = self.levelsListView.model().item(i).text()
            #for i in selected:
            #    levelstring = self.levelsListView.model().itemData(i)[0]
                if self.intband:
                    self.levels.append(int(levelstring))
                else:
                    self.levels.append(float(levelstring))
            #self.levelsListView.clearSelection()
            # create a new worker instance
            worker = Worker(inputlayer, self.levels, self.intband)
            # configure the QgsMessageBar
            msgBar = self.iface.messageBar().createMessage(
                                        self.tr('Skeletonising'), '')
            self.aprogressBar = QProgressBar()
            self.aprogressBar.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
            acancelButton = QPushButton()
            acancelButton.setText(self.CANCEL)
            acancelButton.clicked.connect(self.killWorker)
            msgBar.layout().addWidget(self.aprogressBar)
            msgBar.layout().addWidget(acancelButton)
            # Has to be popped after the thread has finished (in
            # workerFinished).
            self.iface.messageBar().pushWidget(msgBar,
                                        Qgis.Info)
            self.messageBar = msgBar
            # start the worker in a new thread
            thread = QThread(self)
            worker.moveToThread(thread)
            worker.finished.connect(self.workerFinished)
            worker.error.connect(self.workerError)
            worker.status.connect(self.workerInfo)
            worker.progress.connect(self.progressBar.setValue)
            worker.progress.connect(self.aprogressBar.setValue)
            worker.iterprogress.connect(self.iterProgressBar.setValue)
            thread.started.connect(worker.run)
            thread.start()
            self.thread = thread
            self.worker = worker
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
            self.button_box.button(QDialogButtonBox.Close).setEnabled(False)
            self.button_box.button(QDialogButtonBox.Cancel).setEnabled(True)
        except:
            import traceback
            self.showError(traceback.format_exc())
        else:
            pass

    def workerFinished(self, ok, ret):
        """Handles the output from the worker and cleans up after the
           worker has finished."""
        # clean up the worker and thread
        self.showInfo("Handling the result")
        self.worker.deleteLater()
        self.thread.quit()
        self.thread.wait()
        self.thread.deleteLater()
        # remove widget from message bar (pop)
        self.iface.messageBar().popWidget(self.messageBar)
        if ok and ret is not None:
            #self.showInfo("Ret: "+str(ret[10,]))
            # Transformation:
            self.minx = self.thinninglayer.extent().xMinimum()
            self.maxx = self.thinninglayer.extent().xMaximum()
            self.miny = self.thinninglayer.extent().yMinimum()
            self.maxy = self.thinninglayer.extent().yMaximum()
            self.rows = self.thinninglayer.height()
            self.cols = self.thinninglayer.width()
            self.xres = (self.maxx - self.minx) / float(self.cols)
            self.yres = (self.maxy - self.miny) / float(self.rows)
            geotransform = (self.minx, self.xres, 0, self.maxy, 0, -self.yres)
            try:
                format = self.DEFAULTPROVIDER
                driver = gdal.GetDriverByName(format)
                NOVALUE = 0
                metadata = driver.GetMetadata()
                fileName = self.outputRaster.text()
                if self.outputRaster.text() == "":
                    self.showInfo("No output file specified, " +
                                         "creating a temporary file")
                    # Get a temporary file
                    fileName = mktemp(prefix='greyskel',
                           suffix=self.DEFAULTEXTENSION)
                fileInfo = QFileInfo(fileName)
                filepath = fileInfo.absolutePath()
                baseName = fileInfo.baseName()
                suffix = fileInfo.suffix()
                thisfilename = filepath + baseName + '.' + suffix
                thisfilename = fileName
                self.showInfo("File name: " + thisfilename)
                gdaldatatype = gdal.GDT_Byte
                skelmatrix = None
                if self.levelValuesCheckBox.isChecked():
                    # Transform the pixel values back to the original
                    # level values
                    my_dict = {}
                    # Add zero to handle the "empty" pixels
                    my_dict[0] = 0
                    for i in range(len(self.levels)):
                        my_dict[i + 1] = self.levels[i]
                    skelmatrix = np.vectorize(my_dict.__getitem__,
                                              otypes=[np.float])(ret)
                    gdaldatatype = gdal.GDT_Int32
                    if not self.intband:
                        gdaldatatype = gdal.GDT_Float32
                else:
                    skelmatrix = ret
                outDataset = driver.Create(thisfilename, self.cols,
                                           self.rows, 1, gdaldatatype)
                if self.thinninglayer.dataProvider().crs() is not None:
                    srs = self.thinninglayer.dataProvider().crs()
                    outDataset.SetProjection(srs.toWkt().encode('ascii',
                                                               'ignore'))
                skeletonband = outDataset.GetRasterBand(1)
                skeletonband.WriteArray(skelmatrix)
                skeletonband.SetNoDataValue(NOVALUE)
                #stats = skeletonband.GetStatistics(False, True)
                #skeletonband.SetStatistics(stats[0], stats[1],
                #                                 stats[2], stats[3])
                outDataset.SetGeoTransform(geotransform)
                outDataset = None  # To close the file
                # report the result
                rlayer = QgsRasterLayer(thisfilename, baseName)
                self.layerlistchanging = True
                #QgsMapLayerRegistry.instance().addMapLayer(rlayer)
                QgsProject.instance().addMapLayer(rlayer)
                self.layerlistchanging = False
            except:
                import traceback
                self.showError("Can't write the skeleton file:  %s" %
                                   self.outputRaster.text() + ' - ' +
                                   traceback.format_exc())
                okb = self.button_box.button(QDialogButtonBox.Ok)
                okb.setEnabled(True)
                closb = self.button_box.button(QDialogButtonBox.Close)
                closb.setEnabled(True)
                cancb = self.button_box.button(QDialogButtonBox.Cancel)
                cancb.setEnabled(False)
                return
            QgsMessageLog.logMessage(self.tr('ThinGreyscale finished'),
                                self.THINGREYSCALE, Qgis.Info)
        else:
            # notify the user that something went wrong
            if not ok:
                self.showError(self.tr('Aborted') + '!')
            else:
                self.showError(self.tr('No skeleton created') + '!')
        self.progressBar.setValue(0.0)
        #self.aprogressBar.setValue(0.0)
        self.iterProgressBar.setValue(0.0)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
        self.button_box.button(QDialogButtonBox.Close).setEnabled(True)
        self.button_box.button(QDialogButtonBox.Cancel).setEnabled(False)

    def workerError(self, exception_string):
        """Report an error from the worker."""
        #QgsMessageLog.logMessage(self.tr('Worker failed - exception') +
        #                         ': ' + str(exception_string),
        #                         self.THINGREYSCALE,
        #                         QgsMessageLog.CRITICAL)
        self.showError(exception_string)

    def workerInfo(self, message_string):
        """Report an info message from the worker."""
        QgsMessageLog.logMessage(self.tr('Worker') + ': ' + message_string,
                                 self.THINGREYSCALE, Qgis.Info)

    def layerchanged(self, number=0):
        """Do the necessary updates after a layer selection has
           been changed."""
        self.showInfo("Layer changed")
        # If the layer list is being updated, don't do anything
        if self.layerlistchanging:
            return
        layerindex = self.inputRaster.currentIndex()
        layerId = self.inputRaster.itemData(layerindex)
        self.inputlayerid = layerId
        #self.inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        self.inputlayer = QgsProject.instance().mapLayer(layerId)
        if self.inputlayer is not None:
            self.inputrasterprovider = self.inputlayer.dataProvider()
            self.bandComboBox.clear()
            bandcount = self.inputlayer.bandCount()
            #self.showInfo("Layer bandcount: "+str(bandcount))
            for i in range(bandcount):
                self.bandComboBox.addItem(self.inputlayer.bandName(i + 1), i)
                #self.showInfo("Band " + str(i) + ": " +
                #                self.inputlayer.bandName(i+1))
            # Check if the driver supports Create() or CreateCopy()
            #gdalmetadata = self.inputlayer.metadata()
            #self.showInfo("Layer metadata: " +
            #                str(gdalmetadata.encode('utf-8')))
            #provstring = '<p>GDAL provider</p>\n'
            #providerpos = gdalmetadata.find(provstring)
            #brpos = gdalmetadata.find('<br>', providerpos + len(provstring))
            #self.gdalprovider = gdalmetadata[int(providerpos +
            #                             len(provstring)):int(brpos)]
            #self.showInfo('GDAL provider: '+self.gdalprovider)
            #drivername = self.gdalprovider.encode('ascii', 'ignore')
            #theDriver = gdal.GetDriverByName(drivername)
            #if theDriver is None:
            #    self.showInfo("Unable to get the raster driver")
            #else:
            #data    theMetadata = theDriver.GetMetadata()
                #self.showInfo("Driver metadata: "+str(theMetadata))
                #if ((gdal.DCAP_CREATE in theMetadata) and
                #        theMetadata[gdal.DCAP_CREATE] == 'YES'):
                #    self.canCreate = True
                #if (theMetadata.has_key(gdal.DCAP_CREATECOPY) and
                #if ((gdal.DCAP_CREATECOPY in theMetadata) and
                #        theMetadata[gdal.DCAP_CREATECOPY] == 'YES'):
                #    self.canCreateCopy = True
                #self.showInfo('raster provider type: ' +
                #                str(self.inputlayer.providerType()))
                # Determine the file suffix
                #self.gdalext = ""
                #if gdal.DMD_EXTENSION in theMetadata:
                #    self.gdalext = "." + theMetadata[gdal.DMD_EXTENSION]
                #else:
                #    self.showInfo("No extension available in GDAL metadata")
                # by parsing the layer metadata looking for
                #           "Dataset Description"
                #descstring = 'Dataset Description</p>\n<p>'
                #descpos = gdalmetadata.find(descstring)
                #ppos = gdalmetadata.find('</p>',descpos+len(descstring))
                #filename = gdalmetadata[descpos+len(descstring):ppos]
                #self.gdalext = splitext(filename)[1]
                #self.showInfo('GDAL extension: '+self.gdalext)
                # Determine the datatype
                #datatypestring = 'Data Type</p>\n<p>'
                #datatypepos = gdalmetadata.find(datatypestring)
                #ppos = gdalmetadata.find('</p>',
                #                   datatypepos + len(datatypestring))
                #datatypedesc = gdalmetadata[datatypepos +
                #                            len(datatypestring):ppos]
                #shortdesc = datatypedesc.split()[0]
                #self.showInfo('GDAL data type: GDT_'+shortdesc)
                # Call the findGdalDatatype function
                #self.findGdalDatatype(shortdesc)
            #   self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            self.calcHistPushButton.setEnabled(True)
            self.suggestlevelsPushButton.setEnabled(True)

    def bandChanged(self):
        band = self.bandComboBox.currentIndex() + 1
        self.showInfo("Band changed: " + str(band))
        statistics = self.inputrasterprovider.bandStatistics(band)
        #self.showInfo("Band statistics: " + str(statistics.minimumValue) +
        #                            " - " + str(statistics.maximumValue) +
        #                            " - " + str(statistics.mean))
        self.bandmin = statistics.minimumValue
        self.bandmax = statistics.maximumValue
        dt = self.inputrasterprovider.dataType(band)
        # Integer data type
        if (dt == Qgis.Byte or dt == Qgis.UInt16 or dt == Qgis.Int16
                            or dt == Qgis.UInt32 or dt == Qgis.Int32):
            self.intband = True
            self.minValueSpinBox.setDecimals(0)
            self.maxValueSpinBox.setDecimals(0)
            self.levelSpinBox.setDecimals(0)
            self.bandMinLabel.setText(str(int(statistics.minimumValue)))
            self.bandMaxLabel.setText(str(int(statistics.maximumValue)))
        else:
            self.intband = False
            self.minValueSpinBox.setDecimals(5)
            self.maxValueSpinBox.setDecimals(5)
            self.levelSpinBox.setDecimals(5)
            minlabtext = "{0:.5f}".format(statistics.minimumValue)
            self.bandMinLabel.setText(minlabtext)
            maxlabtext = "{0:.5f}".format(statistics.maximumValue)
            self.bandMaxLabel.setText(maxlabtext)
        #self.minValueSpinBox.setMinimum(statistics.minimumValue)
        self.maxValueSpinBox.setMinimum(statistics.minimumValue)
        #self.minValueSpinBox.setMaximum(statistics.maximumValue)
        self.maxValueSpinBox.setMaximum(statistics.maximumValue)
        #self.minValueSpinBox.setValue(statistics.minimumValue)
        if not (statistics.statsGathered & statistics.Mean):
            bandmean = (statistics.minimumValue + statistics.maximumValue) / 2
        else:
            #self.showInfo("statsgathered: " + str(statistics.statsGathered))
            bandmean = statistics.mean
        if self.intband:
            self.minValueSpinBox.setValue(int(ceil(bandmean)))
        else:
            self.minValueSpinBox.setValue(bandmean)
        self.maxValueSpinBox.setValue(statistics.maximumValue)
        self.histMinValue.setText(str(statistics.minimumValue))
        self.histMaxValue.setText(str(statistics.maximumValue))
        self.levelSpinBox.setMinimum(statistics.minimumValue)
        self.levelSpinBox.setMaximum(statistics.maximumValue)
        self.histogramAvailable = False
        #if self.inputrasterprovider.hasStatistics(band):
        #if statistics.statsGathered:
            #histogram = statistics.histogramVector
            #self.showInfo("Histogram: " + str(histogram))
            #range = min to max
            #np.histogram(band, 50, range)

    def minmaxvalueChanged(self):
        #if self.minValueSpinBox is None:
        #    return
        minvalue = self.minValueSpinBox.value()
        #if minvalue is None:
        #    return
        #if self.maxValueSpinBox is None:
        #    return
        maxvalue = self.maxValueSpinBox.value()
        #if maxvalue is None:
        #   return
        if isnan(maxvalue) or isnan(minvalue):
            return
        self.showInfo("minvalue: " + str(minvalue) + " Maxvalue: " +
                                                       str(maxvalue))
        #if self.intband:
        #    minvalue = int(minvalue)
        #    maxvalue = int(maxvalue)
        if abs(maxvalue - minvalue) < 0.00001:
        #if maxvalue == maxvalue:
            self.calcHistPushButton.setEnabled(False)
        else:
            self.calcHistPushButton.setEnabled(True)
        # Update the min and max value spinboxes
        self.minValueSpinBox.setMaximum(maxvalue)
        self.maxValueSpinBox.setMinimum(minvalue)
        self.minValueSpinBox.setMinimum(self.bandmin)

    def minmaxvalueEdFinished(self):
        minvalue = self.minValueSpinBox.value()
        maxvalue = self.maxValueSpinBox.value()
        if self.intband:
            minvalue = int(minvalue)
            maxvalue = int(maxvalue)
        self.showInfo("minvalue: " + str(minvalue) + " Maxvalue: " +
                                    str(maxvalue))
        # Update the spin box for adding levels
        self.levelSpinBox.setMinimum(minvalue)
        self.levelSpinBox.setMaximum(maxvalue)
        if self.levelSpinBox.value() < minvalue:
            self.levelSpinBox.setValue(minvalue)
        if self.levelSpinBox.value() > maxvalue:
            self.levelSpinBox.setValue(maxvalue)
        # Update the min and max value spinboxes
        self.minValueSpinBox.setMaximum(maxvalue)
        self.maxValueSpinBox.setMinimum(minvalue)

        # Adjust the levels:
        i = 0
        while self.levelsListView.model().item(i):
        #for i in range(self.levelsListView.model().rowCount()):
            #self.showInfo("Element: " +
            #       str(self.levelsListView.model().item(i).text()))
            #continue
            value = float(self.levelsListView.model().item(i).text())
            if value < minvalue:
                if i == 0:
                    self.levelsListView.model().item(i).setText(str(minvalue))
                    i = i + 1
                else:
                    self.levelsListView.model().removeRow(i)
            elif value > maxvalue:
                if i == self.levelsListView.model().rowCount() - 1:
                    self.levelsListView.model().item(i).setText(str(maxvalue))
                    i = i + 1
                else:
                    self.levelsListView.model().removeRow(i)
            else:
                i = i + 1
        self.drawHistogram()

    def calculateHistogram(self):
        self.showInfo("Calculating histogram...")
        if self.inputlayer is None:
            return
        
        self.showInfo("Calculating histogram...")
        # Check if there is only one value
        myrange = (self.minValueSpinBox.value(),
                   self.maxValueSpinBox.value())
        self.inputextent = self.inputlayer.extent()
        self.inputrdp = self.inputlayer.dataProvider()
        width = self.inputlayer.width()
        height = self.inputlayer.height()
        if width == 0 or height == 0:
            self.showInfo("Image has zero width or height")
            return
        extwidth = self.inputextent.width()
        extheight = self.inputextent.height()
        # Read the raster block and get the maximum value
        rasterblock = self.inputrdp.block(1, self.inputextent,
                                          width, height)
        # Create a numpy array version of the image
        imageMat = np.zeros((height, width), dtype=np.float16)
        # This one takes a lot of time!
        for row in range(height):
            for column in range(width):
                imageMat[row, column] = rasterblock.value(row, column)
                self.showInfo("Image: " + str(height) + ", " + str(width) + " - " + str(imageMat[row, column]))
        self.histo = np.histogram(imageMat, self.histobins, myrange)
        #relevantpixels = imageMat[np.where(imageMat >= bandval)]
        minlevel = float(self.bandMinLabel.text())
        relevantpixels = imageMat[np.where(imageMat >= minlevel)]
        #self.showInfo("Histogram: " + str(self.histo))
        nanpercentage = 100.0 - 100.0 * len(relevantpixels) / (width * height)
        self.bandNANLabel.setText("{0:.1f}".format(nanpercentage))
        #self.showInfo("Percentage NAN: " + str(100.0 - 100.0 *
        #                    len(relevantpixels) / (width * height)))
        #self.showInfo("First element: " + str(self.histo[0]))
        #self.showInfo("First element, first: " + str(self.histo[0][0]))
        #self.showInfo("First element, second: " + str(self.histo[0][1]))
        self.histMinValue.setText(str(self.minValueSpinBox.value()))
        self.histMaxValue.setText(str(self.maxValueSpinBox.value()))
        if self.intband:
            self.histMinValue.setText(str(int(self.minValueSpinBox.value())))
            self.histMaxValue.setText(str(int(self.maxValueSpinBox.value())))
        self.histogramAvailable = True
        self.drawHistogram()

    def drawHistogram(self):
        #if self.inputlayer is None:
        #    return
        self.showInfo("Drawing histogram...")
        viewprect = QRectF(self.histoGraphicsView.viewport().rect())
        self.histoGraphicsView.setSceneRect(viewprect)
        self.setupScene.clear()
        self.setupScene.update()
        histbottom = self.histoGraphicsView.sceneRect().bottom()
        histtop = self.histoGraphicsView.sceneRect().top()
        left = self.histoGraphicsView.sceneRect().left() + self.histopadding
        right = self.histoGraphicsView.sceneRect().right() - self.histopadding
        histheight = histbottom - histtop
        histwidth = right - left
        step = 1.0 * histwidth / self.histobins
        maxlength = histheight
        padding = 1
        ll = QPoint(self.histopadding - 1, histheight - padding)
        start = QPointF(self.histoGraphicsView.mapToScene(ll))

        # Check if there is only one value
        #myrange = (self.minValueSpinBox.value(),self.maxValueSpinBox.value())
        if self.histogramAvailable:
            maxvalue = 0.0
            for i in range(len(self.histo[0])):
                if self.histo[0][i] > maxvalue:
                    maxvalue = self.histo[0][i]
            if maxvalue == 0:
                return
            self.maxBinNumber.setText(str(maxvalue))
            # Create the histogram:
            #self.showInfo("maxvalue: " + str(maxvalue))
            #self.showInfo("maxlength: " + str(maxlength))
            #self.showInfo("step: " + str(step))
            for i in range(self.histobins):
                binnumber = self.histo[0][i]
                if binnumber == 0:
                    continue
                height = (1.0 * self.histo[0][i] / maxvalue *
                                          (maxlength - padding))
                rectangle = QGraphicsRectItem(start.x() + step * i,
                                          start.y(),
                                          step,
                                          -height)
                rectangle.setPen(QPen(QColor(102, 102, 102)))
                rectangle.setBrush(QBrush(QColor(240, 240, 240)))
                self.setupScene.addItem(rectangle)
                #self.showInfo(str(i) + ": " + str(height))
            #if self.levelsListView.model().rowCount() > 0:
        # Add lines for the levels
        minvalue = float(self.histMinValue.text())
        maxvalue = float(self.histMaxValue.text())
        datarange = maxvalue - minvalue
        if datarange == 0:
            return
        i = 0
        while self.levelsListView.model().item(i):
            #self.showInfo("Element: " +
            #       str(self.levelsListView.model().item(i).text()))
            #continue
            value = float(self.levelsListView.model().item(i).text())
            xvalue = start.x() + histwidth * (value - minvalue) / datarange
            line = QGraphicsLineItem(xvalue, 0, xvalue, histheight)
            if i == 0 or i == (self.levelsListView.model().rowCount() - 1):
                line.setPen(QPen(QColor(204, 0, 0)))
            else:
                line.setPen(QPen(QColor(0, 204, 0)))
            self.setupScene.addItem(line)
            i = i + 1

    def suggestLevels(self):
        self.listModel.clear()
        self.showInfo("Suggesting levels")
        levels = self.levelsSpinBox.value()
        startvalue = self.minValueSpinBox.value()
        endvalue = self.maxValueSpinBox.value()
        increment = (endvalue - startvalue) / levels
        for i in range(levels + 1):
            value = startvalue + increment * i
            if self.intband:
                value = int(value)
            item = QStandardItem(str(value))
            self.listModel.appendRow(item)
        self.drawHistogram()

    def addLevel(self):
        newvalue = self.levelSpinBox.value()
        if self.intband:
            newvalue = int(newvalue)
        for i in range(self.listModel.rowCount()):
            # Check if the value is already in the list
            if self.listModel.item(i).text() == str(newvalue):
                return
            else:
                # Maintain a sorted list of distances
                if (float(self.listModel.item(i).text()) >
                                 float(str(newvalue))):
                    item = QStandardItem(str(newvalue))
                    self.listModel.insertRow(i, item)
                    self.drawHistogram()
                    return
        item = QStandardItem(str(newvalue))
        self.listModel.appendRow(item)
        #if self.histogramAvailable:
        #    addLevelsToHistogram()
        self.drawHistogram()

    def removeLevel(self):
        self.levelsListView.setUpdatesEnabled(False)
        indexes = self.levelsListView.selectedIndexes()
        indexes.sort()
        for i in range(len(indexes) - 1, -1, -1):
            self.listModel.removeRow(indexes[i].row())
        self.levelsListView.setUpdatesEnabled(True)
        #if self.histogramAvailable:
        #    removeLevelFromHistogram()
        self.drawHistogram()

    def layerlistchanged(self):
        self.layerlistchanging = True
        self.showInfo("Layer list changed")
        # Repopulate the input layer combo box
        # Save the currently selected input layer
        inputlayerid = self.inputlayerid
        self.inputRaster.clear()
        for alayer in self.iface.legendInterface().layers():
            if alayer.type() == QgsMapLayer.RasterLayer:
                gdalmetadata = alayer.metadata()
                # Skip WMS layers
                WMSstring = 'Web Map Service'
                wmspos = gdalmetadata.find(WMSstring)
                if wmspos != -1:
                    continue
                self.inputRaster.addItem(alayer.name(), alayer.id())
        # Set the previous selection
        for i in range(self.inputRaster.count()):
            if self.inputRaster.itemData(i) == inputlayerid:
                self.inputRaster.setCurrentIndex(i)
        self.layerlistchanging = False
        #self.updateui()

    def updateui(self):
        """Do the necessary updates after a layer selection has
           been changed."""
        #if self.layerlistchanged:
        #    return
        #self.outputRaster.setText(self.inputRaster.currentText() +
        #                           '_' + 'thinned')
        layerindex = self.inputRaster.currentIndex()
        layerId = self.inputRaster.itemData(layerindex)
        #inputlayer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        inputlayer = QgsProject.instance().mapLayer(layerId)
        if inputlayer is not None:
            pass
        else:
            pass

    def findGdalDatatype(self, shortdesc):
            gdaldatatype = None
            # // Unknown or unspecified type
            # GDT_Unknown = GDALDataType(C.GDT_Unknown)
            if shortdesc == 'Unknown':
                gdaldatatype = gdal.GDT_Unknown
            # // Eight bit unsigned integer
            # GDT_Byte = GDALDataType(C.GDT_Byte)
            elif shortdesc == 'Byte':
                gdaldatatype = gdal.GDT_Byte
            # // Sixteen bit unsigned integer
            # GDT_UInt16 = GDALDataType(C.GDT_UInt16)
            elif shortdesc == 'UInt16':
                gdaldatatype = gdal.GDT_UInt16
            # // Sixteen bit signed integer
            # GDT_Int16 = GDALDataType(C.GDT_Int16)
            elif shortdesc == 'Int16':
                gdaldatatype = gdal.GDT_Int16
            # // Thirty two bit unsigned integer
            # GDT_UInt32 = GDALDataType(C.GDT_UInt32)
            elif shortdesc == 'UInt32':
                gdaldatatype = gdal.GDT_UInt32
            # // Thirty two bit signed integer
            # GDT_Int32 = GDALDataType(C.GDT_Int32)
            elif shortdesc == 'Int32':
                gdaldatatype = gdal.GDT_Int32
            # // Thirty two bit floating point
            # GDT_Float32 = GDALDataType(C.GDT_Float32)
            elif shortdesc == 'Float32':
                gdaldatatype = gdal.GDT_Float32
            # // Sixty four bit floating point
            # GDT_Float64 = GDALDataType(C.GDT_Float64)
            elif shortdesc == 'Float64':
                gdaldatatype = gdal.GDT_Float64
            # // Complex Int16
            # GDT_CInt16 = GDALDataType(C.GDT_CInt16)
            elif shortdesc == 'CInt16':
                gdaldatatype = gdal.CInt16
            # // Complex Int32
            # GDT_CInt32 = GDALDataType(C.GDT_CInt32)
            elif shortdesc == 'CInt32':
                gdaldatatype = gdal.CInt32
            # // Complex Float32
            # GDT_CFloat32 = GDALDataType(C.GDT_CFloat32)
            elif shortdesc == 'CFloat32':
                gdaldatatype = gdal.CFloat32
            # // Complex Float64
            # GDT_CFloat64 = GDALDataType(C.GDT_CFloat64)
            elif shortdesc == 'CFloat64':
                gdaldatatype = gdal.CFloat64
            # // maximum type # + 1
            # GDT_TypeCount = GDALDataType(C.GDT_TypeCount)
            elif shortdesc == 'TypeCount':
                gdaldatatype = gdal.TypeCount
            self.gdaldatatype = gdaldatatype

    def killWorker(self):
        """Kill the worker thread."""
        if self.worker is not None:
            QgsMessageLog.logMessage(self.tr('Killing worker'),
                                     self.THINGREYSCALE, Qgis.Info)
            self.worker.kill()

    def showError(self, text):
        """Show an error."""
        self.iface.messageBar().pushMessage(self.tr('Error'), text,
                                            level=QgsMessageBar.CRITICAL,
                                            duration=3)
        QgsMessageLog.logMessage('Error: ' + text, self.THINGREYSCALE,
                                 QgsMessageLog.CRITICAL)

    def showWarning(self, text):
        """Show a warning."""
        self.iface.messageBar().pushMessage(self.tr('Warning'), text,
                                            level=QgsMessageBar.WARNING,
                                            duration=2)
        QgsMessageLog.logMessage('Warning: ' + text, self.THINGREYSCALE,
                                 QgsMessageLog.WARNING)

    def showInfo(self, text):
        """Show info."""
        self.iface.messageBar().pushMessage(self.tr('Info'), text,
                                            level=Qgis.Info,
                                            duration=2)
        QgsMessageLog.logMessage('Info: ' + text, self.THINGREYSCALE,
                                 Qgis.Info)

    # def help(self):
        # #QDesktopServices.openUrl(QUrl.fromLocalFile(self.plugin_dir +
        #                                 "/help/build/html/index.html"))
        # QDesktopServices.openUrl(QUrl.fromLocalFile(self.plugin_dir +
        #                                            "/help/index.html"))
        # #showPluginHelp()

    def tr(self, message):
        """Get the translation for a string using Qt translation API.

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

        :returns: Translated version of message.
        :rtype: QString
        """
        return QCoreApplication.translate('ThinGreyScaleDialog', message)

    def browse(self):
        settings = QSettings()
        key = '/UI/lastShapefileDir'
        outDir = settings.value(key)
        home = outDir
        #outDir = expanduser("~")
        #filter = (self.DEFAULTPROVIDER + " (*" +
        #             self.DEFAULTEXTENSION + ");;All files (*)")
        filter = (self.DEFAULTPROVIDER + " (*" +
                     self.DEFAULTEXTENSION + self.EXTRAEXTENSION + ")")
        #if (self.gdalprovider != self.DEFAULTPROVIDER and
        #                                     (self.canCreateCopy or
        #                                           self.canCreate)):
        #    filter = (self.gdalprovider + " (*" + self.gdalext +
        #                                          ");;" + filter)
        outFilePath = QFileDialog.getSaveFileName(self,
                                   'Specify file name for skeleton',
                                                     outDir, filter)
        outFilePath = unicode(outFilePath)
        if outFilePath:
            root, ext = splitext(outFilePath)
            if ext.lower() != '.tif' and ext.lower() != '.tiff':
                outFilePath = '%s.tif' % outFilePath
            outDir = dirname(outFilePath)
            settings.setValue(key, outDir)
        #        (self.canCreateCopy or self.canCreate):
        #    fileName = splitext(str(fileName))[0]+self.gdalext
        self.outputRaster.setText(outFilePath)

    # Overriding
    def resizeEvent(self, event):
        #self.showInfo("resizeEvent")
        self.calculateHistogram()

    def help(self):
        #QDesktopServices.openUrl(QUrl.fromLocalFile(
        #                 self.plugin_dir + "/help/html/index.html"))
        showPluginHelp(None, "help/html/index")

    # Implement the accept method to avoid exiting the dialog when
    # starting the work
    def accept(self):
        """Accept override."""
        pass

    # Implement the reject method to have the possibility to avoid
    # exiting the dialog when cancelling
    def reject(self):
        """Reject override."""
        # exit the dialog
        QDialog.reject(self)
示例#33
0
class checkableMapLayerList(QWidget):

    # create a checkable list of the map layers

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        layerList = QgsProject.instance().layerTreeRoot().findLayers()
        self.iface = iface
        """for layer in layerList:
            print(layer.name())"""

        self.selectedLayers = []

        layout = QVBoxLayout()
        self.model = QStandardItemModel()

        self.select_all_cb = QCheckBox('Check All')
        self.select_all_cb.setChecked(True)
        self.select_all_cb.setStyleSheet('margin-left: 5px; font: bold')
        #self.select_all_cb.stateChanged.connect(lambda: selectAllCheckChanged(select_all_cb, model))
        layout.addWidget(self.select_all_cb)

        self.view = QListView()
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.view.setSelectionMode(QAbstractItemView.NoSelection)
        self.view.setSelectionRectVisible(False)

        for layer in layerList:
            item = QStandardItem(layer.name())
            # item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
            # item.setData(QVariant(Qt.Checked), Qt.CheckStateRole)
            item.setCheckable(True)
            item.setSelectable(False)
            item.setCheckState(QtCore.Qt.Checked)
            self.model.appendRow(item)
            self.selectedLayers.append(item)

        self.view.setModel(self.model)

        #view.clicked.connect(lambda: listviewCheckChanged(item, model, select_all_cb))

        layout.addWidget(self.view)

        self.setLayout(layout)
        """if parent:
            parent.setLayout(layout)
        else:
            window = QWidget()
            window.setLayout(layout)"""
        #window.show()

    def selectAllCheckChanged(self, select_all_cb, model):
        TOMsMessageLog.logMessage("IN selectAllCheckChanged", level=Qgis.Info)
        for index in range(model.rowCount()):
            item = model.item(index)
            if item.isCheckable():
                if select_all_cb.isChecked():
                    item.setCheckState(QtCore.Qt.Checked)
                    self.selectedLayers.append(item)
                else:
                    item.setCheckState(QtCore.Qt.Unchecked)
                    self.selectedLayers.remove(item)

        TOMsMessageLog.logMessage(
            "IN selectAllCheckChanged: len list {}".format(
                len(self.selectedLayers)),
            level=Qgis.Info)

    def listviewCheckChanged(self, model, select_all_cb):
        ''' updates the select all checkbox based on the listview '''
        # model = self.listview.model()
        TOMsMessageLog.logMessage("IN listviewCheckChanged", level=Qgis.Info)
        items = [model.item(index) for index in range(model.rowCount())]
        if all(item.checkState() == QtCore.Qt.Checked for item in items):
            select_all_cb.setTristate(False)
            select_all_cb.setCheckState(QtCore.Qt.Checked)
        elif any(item.checkState() == QtCore.Qt.Checked for item in items):
            select_all_cb.setTristate(True)
            select_all_cb.setCheckState(QtCore.Qt.PartiallyChecked)
        else:
            select_all_cb.setTristate(False)
            select_all_cb.setCheckState(QtCore.Qt.Unchecked)

    def updateSelectedLayers(self, index):
        #QMessageBox.information(self.iface.mainWindow(), "debug", "IN updateSelectedLayers: {}".format(self.model.itemFromIndex(index)))
        TOMsMessageLog.logMessage("IN updateSelectedLayers: {}".format(index),
                                  level=Qgis.Info)
        item = self.model.itemFromIndex(index)
        if item.checkState() == QtCore.Qt.Checked:
            self.selectedLayers.append(item)
        else:
            self.selectedLayers.remove(item)

    def getSelectedLayers(self):
        return self.selectedLayers
示例#34
0
class ModelAtrributesView(QListView):
    """
    Custom QListView implementation that displays checkable model attributes.
    """
    def __init__(self, parent=None, dataModel=None):
        QListView.__init__(self, parent)

        self._dataModel = dataModel
        self._selectedDisplayMapping = OrderedDict()
        self._modelDisplayMapping = OrderedDict()
        self._attrModel = QStandardItemModel(self)

    def dataModel(self):
        """
        Returns the data model instance.
        """
        return self._dataModel

    def setDataModel(self, dataModel):
        """
        Sets the data model. Should be a callable class rather than the class.
        instance.
        """
        if callable(dataModel):
            self._dataModel = dataModel

        else:
            self._dataModel = dataModel.__class__

    def modelDisplayMapping(self):
        """
        Returns the column name and display name collection.
        """
        return self._modelDisplayMapping

    def setModelDisplayMapping(self, dataMapping):
        """
        Sets the mapping dictionary for the table object
        """
        if dataMapping != None:
            self._modelDisplayMapping = dataMapping

    def load(self, sort=False):
        """
        Load the model's attributes into the list view.
        """
        if self._dataModel == None:
            return

        try:
            self._loadAttrs(self._dataModel.displayMapping(), sort)
        except AttributeError:
            # Ignore error if model does not contain
            # the displayMapping static method
            pass

    def load_mapping(self, mapping, sort=False):
        """
        Load collection containing column name and corresponding display name.
        """
        self._modelDisplayMapping = mapping

        self._loadAttrs(mapping, sort)

    def sort(self):
        """
        Sorts display name in ascending order.
        """
        self._attrModel.sort(0)

    def _loadAttrs(self, attrMapping, sort=False):
        """
        Loads display mapping into the list view.
        Specify to sort display names in ascending order once items have been
        added to the model.
        """
        self._attrModel.clear()
        self._attrModel.setColumnCount(2)

        for attrName, displayName in attrMapping.items():
            # Exclude row ID in the list, other unique identifier attributes in the model can be used
            if attrName != "id":
                displayNameItem = QStandardItem(displayName)
                displayNameItem.setCheckable(True)
                attrNameItem = QStandardItem(attrName)

                self._attrModel.appendRow([displayNameItem, attrNameItem])

        self.setModel(self._attrModel)

        if sort:
            self._attrModel.sort(0)

    def selectedMappings(self):
        """
        Return a dictionary of field names and their corresponding display values.
        """
        selectedAttrs = OrderedDict()

        for i in range(self._attrModel.rowCount()):
            displayNameItem = self._attrModel.item(i, 0)

            if displayNameItem.checkState() == Qt.Checked:
                attrNameItem = self._attrModel.item(i, 1)

                selectedAttrs[attrNameItem.text()] = displayNameItem.text()

        return selectedAttrs
示例#35
0
class MultipleInputDialog(BASE, WIDGET):

    def __init__(self, options, selectedoptions=None, datatype=None):
        super(MultipleInputDialog, self).__init__(None)
        self.setupUi(self)
        self.datatype = datatype
        self.model = None

        self.options = []
        for i, option in enumerate(options):
            if option is None or isinstance(option, str):
                self.options.append((i, option))
            else:
                self.options.append((option[0], option[1]))

        self.selectedoptions = selectedoptions or []

        # Additional buttons
        self.btnSelectAll = QPushButton(self.tr('Select All'))
        self.buttonBox.addButton(self.btnSelectAll,
                                 QDialogButtonBox.ActionRole)
        self.btnClearSelection = QPushButton(self.tr('Clear Selection'))
        self.buttonBox.addButton(self.btnClearSelection,
                                 QDialogButtonBox.ActionRole)
        self.btnToggleSelection = QPushButton(self.tr('Toggle Selection'))
        self.buttonBox.addButton(self.btnToggleSelection,
                                 QDialogButtonBox.ActionRole)
        if self.datatype is not None:
            btnAddFile = QPushButton(QCoreApplication.translate("MultipleInputDialog", 'Add File(s)…'))
            btnAddFile.clicked.connect(self.addFiles)
            self.buttonBox.addButton(btnAddFile,
                                     QDialogButtonBox.ActionRole)

        self.btnSelectAll.clicked.connect(lambda: self.selectAll(True))
        self.btnClearSelection.clicked.connect(lambda: self.selectAll(False))
        self.btnToggleSelection.clicked.connect(self.toggleSelection)

        self.settings = QgsSettings()
        self.restoreGeometry(self.settings.value("/Processing/multipleInputDialogGeometry", QByteArray()))

        self.lstLayers.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.lstLayers.setDragDropMode(QAbstractItemView.InternalMove)

        self.populateList()
        self.finished.connect(self.saveWindowGeometry)

    def saveWindowGeometry(self):
        self.settings.setValue("/Processing/multipleInputDialogGeometry", self.saveGeometry())

    def populateList(self):
        self.model = QStandardItemModel()
        for value, text in self.options:
            item = QStandardItem(text)
            item.setData(value, Qt.UserRole)
            item.setCheckState(Qt.Checked if value in self.selectedoptions else Qt.Unchecked)
            item.setCheckable(True)
            item.setDropEnabled(False)
            self.model.appendRow(item)

        # add extra options (e.g. manually added layers)
        for t in [o for o in self.selectedoptions if not isinstance(o, int)]:
            if isinstance(t, QgsProcessingModelChildParameterSource):
                item = QStandardItem(t.staticValue())
            else:
                item = QStandardItem(t)
            item.setData(item.text(), Qt.UserRole)
            item.setCheckState(Qt.Checked)
            item.setCheckable(True)
            item.setDropEnabled(False)
            self.model.appendRow(item)

        self.lstLayers.setModel(self.model)

    def accept(self):
        self.selectedoptions = []
        model = self.lstLayers.model()
        for i in range(model.rowCount()):
            item = model.item(i)
            if item.checkState() == Qt.Checked:
                self.selectedoptions.append(item.data(Qt.UserRole))
        QDialog.accept(self)

    def reject(self):
        self.selectedoptions = None
        QDialog.reject(self)

    def getItemsToModify(self):
        items = []
        if len(self.lstLayers.selectedIndexes()) > 1:
            for i in self.lstLayers.selectedIndexes():
                items.append(self.model.itemFromIndex(i))
        else:
            for i in range(self.model.rowCount()):
                items.append(self.model.item(i))
        return items

    def selectAll(self, value):
        for item in self.getItemsToModify():
            item.setCheckState(Qt.Checked if value else Qt.Unchecked)

    def toggleSelection(self):
        for item in self.getItemsToModify():
            checked = item.checkState() == Qt.Checked
            item.setCheckState(Qt.Unchecked if checked else Qt.Checked)

    def getFileFilter(self, datatype):
        """
        Returns a suitable file filter pattern for the specified parameter definition
        :param param:
        :return:
        """
        if datatype == QgsProcessing.TypeRaster:
            return QgsProviderRegistry.instance().fileRasterFilters()
        elif datatype == QgsProcessing.TypeFile:
            return self.tr('All files (*.*)')
        else:
            exts = QgsVectorFileWriter.supportedFormatExtensions()
            for i in range(len(exts)):
                exts[i] = self.tr('{0} files (*.{1})').format(exts[i].upper(), exts[i].lower())
            return self.tr('All files (*.*)') + ';;' + ';;'.join(exts)

    def addFiles(self):
        filter = self.getFileFilter(self.datatype)

        settings = QgsSettings()
        path = str(settings.value('/Processing/LastInputPath'))

        ret, selected_filter = QFileDialog.getOpenFileNames(self, self.tr('Select File(s)'),
                                                            path, filter)
        if ret:
            files = list(ret)
            settings.setValue('/Processing/LastInputPath',
                              os.path.dirname(str(files[0])))
            for filename in files:
                item = QStandardItem(filename)
                item.setData(filename, Qt.UserRole)
                item.setCheckState(Qt.Checked)
                item.setCheckable(True)
                item.setDropEnabled(False)
                self.model.appendRow(item)
示例#36
0
class ModelDeletionDialog(uicls, basecls):
    """Dialog for model(s) deletion."""
    def __init__(self, plugin_dock, parent):
        super().__init__(parent)
        self.setupUi(self)
        self.parent_widget = parent
        self.plugin_dock = plugin_dock
        self.communication = self.plugin_dock.communication
        self.threedi_api = self.plugin_dock.threedi_api
        self.local_schematisation = self.plugin_dock.current_local_schematisation
        self.threedi_models = None
        self.models_model = QStandardItemModel()
        self.models_tv.setModel(self.models_model)
        self.pb_delete.clicked.connect(self.delete_models)
        self.pb_cancel.clicked.connect(self.reject)
        self.models_tv.selectionModel().selectionChanged.connect(
            self.toggle_delete_models)
        self.fetch_3di_models()

    def toggle_delete_models(self):
        """Toggle delete button if any model is selected."""
        selection_model = self.models_tv.selectionModel()
        if selection_model.hasSelection():
            self.pb_delete.setEnabled(True)
        else:
            self.pb_delete.setDisabled(True)

    def fetch_3di_models(self):
        """Fetching 3Di models list."""
        try:
            tc = ThreediCalls(self.threedi_api)
            threedi_models, models_count = tc.fetch_3di_models_with_count(
                limit=tc.FETCH_LIMIT,
                schematisation_name=self.local_schematisation.name,
                show_invalid=True)
            self.models_model.clear()
            if models_count < self.parent_widget.MAX_SCHEMATISATION_MODELS:
                self.accept()
            header = [
                "ID", "Model", "Schematisation", "Revision", "Last updated",
                "Updated by"
            ]
            self.models_model.setHorizontalHeaderLabels(header)
            for sim_model in sorted(threedi_models,
                                    key=attrgetter("revision_commit_date"),
                                    reverse=True):
                if sim_model.schematisation_id != self.local_schematisation.id:
                    continue
                id_item = QStandardItem(str(sim_model.id))
                name_item = QStandardItem(sim_model.name)
                name_item.setData(sim_model, role=Qt.UserRole)
                schema_item = QStandardItem(sim_model.schematisation_name)
                rev_item = QStandardItem(sim_model.revision_number)
                last_updated_day = sim_model.revision_commit_date.split("T")[0]
                lu_datetime = QDateTime.fromString(last_updated_day,
                                                   "yyyy-MM-dd")
                lu_item = QStandardItem(lu_datetime.toString("dd-MMMM-yyyy"))
                ub_item = QStandardItem(sim_model.user)
                self.models_model.appendRow([
                    id_item, name_item, schema_item, rev_item, lu_item, ub_item
                ])
            self.threedi_models = threedi_models
        except ApiException as e:
            error_msg = extract_error_message(e)
            self.communication.show_error(error_msg)
        except Exception as e:
            error_msg = f"Error: {e}"
            self.communication.show_error(error_msg)

    def delete_models(self):
        """Deleting selected model(s)."""
        selection_model = self.models_tv.selectionModel()
        if not selection_model.hasSelection():
            return
        try:
            tc = ThreediCalls(self.threedi_api)
            for index in selection_model.selectedRows():
                current_row = index.row()
                model_id_item = self.models_model.item(current_row, 0)
                model_id = int(model_id_item.text())
                tc.delete_3di_model(model_id)
        except ApiException as e:
            error_msg = extract_error_message(e)
            self.communication.show_error(error_msg)
        except Exception as e:
            error_msg = f"Error: {e}"
            self.communication.show_error(error_msg)
        finally:
            self.fetch_3di_models()
示例#37
0
class QQuakeDialog(QDialog, FORM_CLASS):
    """
    The main plugin dialog
    """
    def __init__(self, iface, parent=None):  # pylint:disable=too-many-statements
        """Constructor."""
        super().__init__(parent)

        self.setupUi(self)

        self.setObjectName('QQuakeDialog')
        QgsGui.enableAutoGeometryRestore(self)

        self.scrollArea.setStyleSheet("""
            QScrollArea { background: transparent; }
            QScrollArea > QWidget > QWidget { background: transparent; }
            QScrollArea > QWidget > QScrollBar { background: 1; }
        """)
        self.scrollArea_2.setStyleSheet(self.scrollArea.styleSheet())
        self.scrollArea_3.setStyleSheet(self.scrollArea.styleSheet())
        self.scrollArea_4.setStyleSheet(self.scrollArea.styleSheet())

        self.splitter.setStretchFactor(0, 0)
        self.splitter_2.setStretchFactor(0, 0)
        self.splitter_3.setStretchFactor(0, 0)
        self.splitter_4.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)
        self.splitter_2.setStretchFactor(1, 1)
        self.splitter_3.setStretchFactor(1, 1)
        self.splitter_4.setStretchFactor(1, 1)

        self.fdsn_event_filter = FilterParameterWidget(
            iface, SERVICE_MANAGER.FDSNEVENT)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.fdsn_event_filter)
        self.fdsn_event_filter_container.setLayout(vl)
        self.earthquake_service_info_widget = ServiceInformationWidget(iface)
        self.fdsn_by_id_filter = FilterByIdWidget(iface,
                                                  SERVICE_MANAGER.FDSNEVENT)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.fdsn_by_id_filter)
        self.fdsn_by_id_container.setLayout(vl)
        self.fdsn_by_url_widget = FetchByUrlWidget(iface,
                                                   SERVICE_MANAGER.FDSNEVENT)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.fdsn_by_url_widget)
        self.fdsn_by_url_container.setLayout(vl)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.earthquake_service_info_widget)
        self.earthquake_service_info_container.setLayout(vl)

        self.macro_filter = FilterParameterWidget(iface,
                                                  SERVICE_MANAGER.MACROSEISMIC)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.macro_filter)
        self.macro_filter_container.setLayout(vl)
        self.macro_by_id_filter = FilterByIdWidget(
            iface, SERVICE_MANAGER.MACROSEISMIC)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.macro_by_id_filter)
        self.macro_by_id_container.setLayout(vl)
        self.macro_by_url_widget = FetchByUrlWidget(
            iface, SERVICE_MANAGER.MACROSEISMIC)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.macro_by_url_widget)
        self.macro_by_url_container.setLayout(vl)
        self.macro_service_info_widget = ServiceInformationWidget(iface)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.macro_service_info_widget)
        self.macro_service_info_container.setLayout(vl)

        self.station_filter = FilterParameterWidget(
            iface, SERVICE_MANAGER.FDSNSTATION)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.station_filter)
        self.station_filter_container.setLayout(vl)
        self.station_by_id_filter = FilterStationByIdWidget(
            iface, SERVICE_MANAGER.FDSNSTATION)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.station_by_id_filter)
        self.station_by_id_container.setLayout(vl)
        self.station_service_info_widget = ServiceInformationWidget(iface)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.station_service_info_widget)
        self.station_service_info_container.setLayout(vl)

        self.station_by_url_widget = FetchByUrlWidget(
            iface, SERVICE_MANAGER.FDSNSTATION)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.station_by_url_widget)
        self.station_by_url_container.setLayout(vl)

        self.ogc_service_widget = OgcServiceWidget(iface)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.ogc_service_widget)
        self.ogc_widget_container.setLayout(vl)
        self.ogc_service_info_widget = ServiceInformationWidget(iface)
        vl = QVBoxLayout()
        vl.setContentsMargins(0, 0, 0, 0)
        vl.addWidget(self.ogc_service_info_widget)
        self.ogc_service_info_container.setLayout(vl)

        self.message_bar = QgsMessageBar()
        self.message_bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.insertWidget(0, self.message_bar)

        self.fdsn_event_url_text_browser.viewport().setAutoFillBackground(
            False)
        self.fdsn_macro_url_text_browser.viewport().setAutoFillBackground(
            False)
        self.fdsn_station_url_text_browser.viewport().setAutoFillBackground(
            False)

        self.button_box.button(QDialogButtonBox.Ok).setText(
            self.tr('Fetch Data'))
        self.button_box.rejected.connect(self._save_settings)

        self.iface = iface

        # OGC
        self.ogc_combo.addItem(self.tr('Web Map Services (WMS)'),
                               SERVICE_MANAGER.WMS)
        self.ogc_combo.addItem(self.tr('Web Feature Services (WFS)'),
                               SERVICE_MANAGER.WFS)
        self.ogc_combo.currentIndexChanged.connect(self.refreshOgcWidgets)

        self.ogc_list_model = QStandardItemModel(self.ogc_list)
        self.ogc_list.setModel(self.ogc_list_model)
        self.ogc_list.selectionModel().selectionChanged.connect(
            self._ogc_service_changed)

        self._refresh_services()
        SERVICE_MANAGER.refreshed.connect(self._refresh_services)

        # connect to refreshing function to refresh the UI depending on the WS
        self._refresh_fdsnevent_widgets()
        self.refreshFdsnMacroseismicWidgets()
        self.refreshFdsnStationWidgets()

        # change the UI parameter according to the web service chosen
        self.fdsn_event_list.currentRowChanged.connect(
            self._refresh_fdsnevent_widgets)
        self.fdsn_macro_list.currentRowChanged.connect(
            self.refreshFdsnMacroseismicWidgets)
        self.fdsn_station_list.currentRowChanged.connect(
            self.refreshFdsnStationWidgets)

        self.fdsn_event_filter.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNEVENT))
        self.fdsn_by_id_filter.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNEVENT))
        self.fdsn_by_url_widget.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNEVENT))
        self.fdsn_event_list.currentRowChanged.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNEVENT))
        self.macro_filter.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.MACROSEISMIC))
        self.macro_by_id_filter.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.MACROSEISMIC))
        self.macro_by_url_widget.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.MACROSEISMIC))
        self.fdsn_macro_list.currentRowChanged.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.MACROSEISMIC))
        self.station_filter.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNSTATION))
        self.station_by_id_filter.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNSTATION))
        self.fdsn_station_list.currentRowChanged.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNSTATION))
        self.station_by_url_widget.changed.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNSTATION))

        self.button_box.accepted.connect(self._getEventList)

        self.service_tab_widget.currentChanged.connect(
            lambda: self._refresh_url(None))

        self.fetcher = None

        QgsGui.enableAutoGeometryRestore(self)

        self.fdsn_tab_widget.currentChanged.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNEVENT))
        self.macro_tab_widget.currentChanged.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.MACROSEISMIC))
        self.fdsnstation_tab_widget.currentChanged.connect(
            lambda: self._refresh_url(SERVICE_MANAGER.FDSNSTATION))

        for b in [
                self.button_fdsn_new_service, self.button_macro_new_service,
                self.button_station_new_service, self.button_ogc_new_service
        ]:
            self._build_add_service_menu(b)

        for b in [
                self.button_fdsn_edit_service, self.button_macro_edit_service,
                self.button_station_edit_service, self.button_ogc_edit_service
        ]:
            b.clicked.connect(self._edit_service)

        for b in [
                self.button_fdsn_rename_service,
                self.button_macro_rename_service,
                self.button_station_rename_service,
                self.button_ogc_rename_service
        ]:
            b.clicked.connect(self._rename_service)

        for b in [
                self.button_fdsn_remove_service,
                self.button_macro_remove_service,
                self.button_station_remove_service,
                self.button_ogc_remove_service
        ]:
            b.clicked.connect(self._remove_service)

        for b in [
                self.button_fdsn_export_service,
                self.button_macro_export_service,
                self.button_station_export_service,
                self.button_ogc_export_service
        ]:
            b.clicked.connect(self._export_service)

        self._restore_settings()
        self._refresh_url(SERVICE_MANAGER.FDSNEVENT)
        self._refresh_url(SERVICE_MANAGER.MACROSEISMIC)
        self._refresh_url(SERVICE_MANAGER.FDSNSTATION)

    def closeEvent(self, e):  # pylint: disable=missing-function-docstring
        self._save_settings()
        super().closeEvent(e)

    def _build_add_service_menu(self, widget):
        """
        Builds the add service menu for a specific widget
        """
        menu = QMenu()
        save_action = QAction(self.tr('Save Current Configuration As…'),
                              parent=menu)
        save_action.setObjectName('save_action')
        menu.addAction(save_action)
        save_action.triggered.connect(self._save_configuration)

        import_action = QAction(self.tr('Import from File…'), parent=menu)
        menu.addAction(import_action)
        import_action.triggered.connect(self._import_configuration)

        create_new_action = QAction(self.tr('Create New Service…'),
                                    parent=menu)
        menu.addAction(create_new_action)
        create_new_action.triggered.connect(self._create_configuration)

        menu.aboutToShow.connect(lambda: self._menu_about_to_show(menu))
        widget.setMenu(menu)

    def _menu_about_to_show(self, menu):
        """
        Triggered when the Add Service menu is about to show
        """
        save_current_action = menu.findChild(QAction, 'save_action')

        service_type = self.get_current_service_type()
        filter_widget = self.get_service_filter_widget(service_type)

        save_current_action.setEnabled(
            hasattr(filter_widget, 'to_service_definition'))

    def _refresh_services(self):
        """
        Refreshes the list of available services
        """

        # fill the FDSN listWidget with the dictionary keys
        self.fdsn_event_list.clear()
        self.fdsn_event_list.addItems(
            SERVICE_MANAGER.available_services(SERVICE_MANAGER.FDSNEVENT))
        self.fdsn_event_list.setCurrentRow(0)

        # fill the FDSN listWidget with the dictionary keys
        self.fdsn_macro_list.clear()
        self.fdsn_macro_list.addItems(
            SERVICE_MANAGER.available_services(SERVICE_MANAGER.MACROSEISMIC))
        self.fdsn_macro_list.setCurrentRow(0)

        # fill the FDSN listWidget with the dictionary keys
        self.fdsn_station_list.clear()
        self.fdsn_station_list.addItems(
            SERVICE_MANAGER.available_services(SERVICE_MANAGER.FDSNSTATION))
        self.fdsn_station_list.setCurrentRow(0)

        self.refreshOgcWidgets()

    def _save_configuration(self):
        """
        Triggers saving the current service configuration
        """
        service_type = self.get_current_service_type()
        name, ok = QInputDialog.getText(
            self, self.tr('Save Service Configuration'),
            self.tr('Save the current service configuration as'))
        if not name or not ok:
            return

        filter_widget = self.get_service_filter_widget(service_type)
        SERVICE_MANAGER.save_service(service_type, name,
                                     filter_widget.to_service_definition())
        self.set_current_service(service_type, name)

    def _save_settings(self):
        """
        Saves all settings currently defined in the dialog
        """
        s = QgsSettings()
        if self.service_tab_widget.currentIndex(
        ) != self.service_tab_widget.count() - 1:
            s.setValue('/plugins/qquake/last_tab',
                       self.service_tab_widget.currentIndex())
        s.setValue('/plugins/qquake/fdsn_event_last_event_service',
                   self.fdsn_event_list.currentItem().text())
        s.setValue('/plugins/qquake/macro_last_event_service',
                   self.fdsn_macro_list.currentItem().text())

        s.setValue('/plugins/qquake/fdsnevent_last_tab',
                   self.fdsn_tab_widget.currentIndex())
        s.setValue('/plugins/qquake/macro_last_tab',
                   self.macro_tab_widget.currentIndex())
        s.setValue('/plugins/qquake/station_last_tab',
                   self.fdsnstation_tab_widget.currentIndex())

        self.fdsn_event_filter.save_settings('fdsn_event')
        self.fdsn_by_id_filter.save_settings('fdsn_event')
        self.fdsn_by_url_widget.save_settings('fdsn_event')
        self.macro_filter.save_settings('macro')
        self.macro_by_id_filter.save_settings('macro')
        self.macro_by_url_widget.save_settings('macro')
        self.station_filter.save_settings('stations')
        self.station_by_id_filter.save_settings('stations')
        self.station_by_url_widget.save_settings('stations')

    def _restore_settings(self):
        """
        Restores dialog settings
        """
        s = QgsSettings()

        last_tab = s.value('/plugins/qquake/last_tab')
        if last_tab is not None:
            self.service_tab_widget.setCurrentIndex(int(last_tab))

        last_service = s.value('/plugins/qquake/fdsn_event_last_event_service')
        if last_service is not None:
            try:
                self.fdsn_event_list.setCurrentItem(
                    self.fdsn_event_list.findItems(last_service,
                                                   Qt.MatchContains)[0])
            except IndexError:
                pass

        last_service = s.value('/plugins/qquake/macro_last_event_service')
        if last_service is not None:
            self.fdsn_macro_list.setCurrentItem(
                self.fdsn_macro_list.findItems(last_service,
                                               Qt.MatchContains)[0])

        self.fdsn_event_filter.restore_settings('fdsn_event')
        self.fdsn_by_id_filter.restore_settings('fdsn_event')
        self.fdsn_by_url_widget.restore_settings('fdsn_event')
        self.macro_filter.restore_settings('macro')
        self.macro_by_id_filter.restore_settings('macro')
        self.macro_by_url_widget.restore_settings('fdsn_event')
        self.station_filter.restore_settings('stations')
        self.station_by_id_filter.restore_settings('stations')
        self.station_by_url_widget.restore_settings('stations')

        self.fdsn_tab_widget.setCurrentIndex(
            s.value('/plugins/qquake/fdsnevent_last_tab', 0, int))
        self.macro_tab_widget.setCurrentIndex(
            s.value('/plugins/qquake/macro_last_tab', 0, int))
        self.fdsnstation_tab_widget.setCurrentIndex(
            s.value('/plugins/qquake/station_last_tab', 0, int))

    def get_current_service_id(self, service_type: str) -> Optional[str]:
        """
        Returns the current selected service id
        """
        if service_type == SERVICE_MANAGER.FDSNEVENT:
            service_id = self.fdsn_event_list.currentItem().text(
            ) if self.fdsn_event_list.currentItem() else None
        elif service_type == SERVICE_MANAGER.MACROSEISMIC:
            service_id = self.fdsn_macro_list.currentItem().text(
            ) if self.fdsn_macro_list.currentItem() else None
        elif service_type == SERVICE_MANAGER.FDSNSTATION:
            service_id = self.fdsn_station_list.currentItem().text(
            ) if self.fdsn_station_list.currentItem() else None
        elif service_type in (SERVICE_MANAGER.WMS, SERVICE_MANAGER.WFS):
            service_id = self.ogc_list.selectionModel().selectedIndexes(
            )[0].data() if self.ogc_list.selectionModel().selectedIndexes(
            ) else None
        else:
            service_id = None

        return service_id

    def get_current_service_type(self) -> Optional[str]:
        """
        Returns the current service type
        """
        if self.service_tab_widget.currentIndex() == 0:
            service_type = SERVICE_MANAGER.FDSNEVENT
        elif self.service_tab_widget.currentIndex() == 1:
            service_type = SERVICE_MANAGER.MACROSEISMIC
        elif self.service_tab_widget.currentIndex() == 2:
            service_type = SERVICE_MANAGER.FDSNSTATION
        elif self.service_tab_widget.currentIndex() == 3:
            return self.ogc_combo.currentData()
        else:
            service_type = None
        return service_type

    def get_service_filter_widget(
        self,  # pylint:disable=too-many-branches
        service_type: str
    ) -> Optional[
            Union[FilterParameterWidget, FilterByIdWidget, FetchByUrlWidget,
                  FilterStationByIdWidget, OgcServiceWidget]]:
        """
        Returns the service filter widget for a specific service type
        """
        widget = None
        if service_type == SERVICE_MANAGER.FDSNEVENT:
            if self.fdsn_tab_widget.currentIndex() in (0, 3):
                widget = self.fdsn_event_filter
            elif self.fdsn_tab_widget.currentIndex() == 1:
                widget = self.fdsn_by_id_filter
            elif self.fdsn_tab_widget.currentIndex() == 2:
                widget = self.fdsn_by_url_widget
        elif service_type == SERVICE_MANAGER.MACROSEISMIC:
            if self.macro_tab_widget.currentIndex() in (0, 3):
                widget = self.macro_filter
            elif self.macro_tab_widget.currentIndex() == 1:
                widget = self.macro_by_id_filter
            elif self.macro_tab_widget.currentIndex() == 2:
                widget = self.macro_by_url_widget
        elif service_type == SERVICE_MANAGER.FDSNSTATION:
            if self.fdsnstation_tab_widget.currentIndex() in (0, 3):
                widget = self.station_filter
            elif self.fdsnstation_tab_widget.currentIndex() == 1:
                widget = self.station_by_id_filter
            elif self.fdsnstation_tab_widget.currentIndex() == 2:
                widget = self.station_by_url_widget
        elif service_type in (SERVICE_MANAGER.WMS, SERVICE_MANAGER.WFS):
            widget = self.ogc_service_widget
        return widget

    def get_fetcher(self, service_type: Optional[str] = None):
        """
        Returns a quake fetcher corresponding to the current dialog settings
        """

        if service_type is None:
            service_type = self.get_current_service_type()

        service = self.get_current_service_id(service_type)
        if not service:
            return None

        filter_widget = self.get_service_filter_widget(service_type)

        service_config = SERVICE_MANAGER.service_details(service_type, service)

        if isinstance(filter_widget, FilterParameterWidget):
            fetcher = Fetcher(
                service_type=service_type,
                event_service=service,
                event_start_date=filter_widget.start_date(),
                event_end_date=filter_widget.end_date(),
                event_min_magnitude=filter_widget.min_magnitude(),
                event_max_magnitude=filter_widget.max_magnitude(),
                limit_extent_rect=filter_widget.extent_rect(),
                min_latitude=filter_widget.min_latitude(),
                max_latitude=filter_widget.max_latitude(),
                min_longitude=filter_widget.min_longitude(),
                max_longitude=filter_widget.max_longitude(),
                limit_extent_circle=filter_widget.limit_extent_circle(),
                circle_latitude=filter_widget.circle_latitude(),
                circle_longitude=filter_widget.circle_longitude(),
                circle_min_radius=filter_widget.circle_min_radius(),
                circle_max_radius=filter_widget.circle_max_radius(),
                circle_radius_unit=filter_widget.circle_radius_unit(),
                earthquake_number_mdps_greater=filter_widget.
                earthquake_number_mdps_greater(),
                earthquake_max_intensity_greater=filter_widget.
                earthquake_max_intensity_greater(),
                output_fields=filter_widget.output_fields,
                output_type=filter_widget.output_type(),
                convert_negative_depths=filter_widget.convert_negative_depths(
                ),
                depth_unit=filter_widget.depth_unit(),
                event_type=filter_widget.event_type(),
                updated_after=filter_widget.updated_after())
        elif isinstance(filter_widget, FilterByIdWidget):
            if not service_config['settings'].get('queryeventid'):
                fetcher = None
            else:
                fetcher = Fetcher(
                    service_type=service_type,
                    event_service=service,
                    event_ids=filter_widget.ids(),
                    contributor_id=filter_widget.contributor_id(),
                    output_fields=filter_widget.output_fields,
                    output_type=filter_widget.output_type(),
                    convert_negative_depths=filter_widget.
                    convert_negative_depths(),
                    depth_unit=filter_widget.depth_unit())
        elif isinstance(filter_widget, FetchByUrlWidget):
            fetcher = Fetcher(service_type=service_type,
                              event_service=service,
                              url=filter_widget.url(),
                              output_fields=filter_widget.output_fields,
                              output_type=filter_widget.output_type(),
                              convert_negative_depths=filter_widget.
                              convert_negative_depths(),
                              depth_unit=filter_widget.depth_unit())
        elif isinstance(filter_widget, FilterStationByIdWidget):
            fetcher = Fetcher(service_type=service_type,
                              event_service=service,
                              network_codes=filter_widget.network_codes(),
                              station_codes=filter_widget.station_codes(),
                              locations=filter_widget.locations(),
                              output_fields=filter_widget.output_fields,
                              output_type=filter_widget.output_type(),
                              convert_negative_depths=filter_widget.
                              convert_negative_depths(),
                              depth_unit=filter_widget.depth_unit())
        return fetcher

    def _refresh_url(self, service_type: Optional[str] = None):
        """
        Updates the service URL
        """
        if not service_type:
            service_type = self.get_current_service_type()
            if service_type is None:
                self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
                return

            if service_type not in (SERVICE_MANAGER.FDSNEVENT,
                                    SERVICE_MANAGER.MACROSEISMIC,
                                    SERVICE_MANAGER.FDSNSTATION):
                self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
                return

        fetcher = self.get_fetcher(service_type)
        if not fetcher:
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
            return

        self._valid_changed()

        if service_type == SERVICE_MANAGER.FDSNEVENT:
            self.fdsn_event_url_text_browser.setText(
                '<a href="{0}">{0}</a>'.format(fetcher.generate_url()))
        elif service_type == SERVICE_MANAGER.MACROSEISMIC:
            self.fdsn_macro_url_text_browser.setText(
                '<a href="{0}">{0}</a>'.format(fetcher.generate_url()))
        elif service_type == SERVICE_MANAGER.FDSNSTATION:
            self.fdsn_station_url_text_browser.setText(
                '<a href="{0}">{0}</a>'.format(fetcher.generate_url()))

    def _valid_changed(self):
        """
        Called when dialog entry validation should occur
        """
        service_type = self.get_current_service_type()
        if service_type not in (SERVICE_MANAGER.FDSNEVENT,
                                SERVICE_MANAGER.MACROSEISMIC,
                                SERVICE_MANAGER.FDSNSTATION):
            self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
            return

        filter_widget = self.get_service_filter_widget(service_type)
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(
            filter_widget.is_valid())

    def _update_service_widgets(
            self,  # pylint: disable=too-many-locals,too-many-branches
            service_type,
            service_id,
            filter_widget,
            filter_by_id_widget,
            fetch_by_url_widget,
            info_widget,
            remove_service_button,
            edit_service_button,
            rename_service_button,
            tab_widget):
        """
        Updates all widgets to reflect the current service details
        """
        service_config = SERVICE_MANAGER.service_details(
            service_type, service_id)

        date_start = QDateTime.fromString(service_config['datestart'],
                                          Qt.ISODate)
        default_date_start = QDateTime.fromString(
            service_config['default']['datestart'],
            Qt.ISODate) if service_config['default'].get('datestart') else None

        # if the dateend is not set in the config.json set the date to NOW
        date_end = QDateTime.fromString(
            service_config['dateend'],
            Qt.ISODate) if 'dateend' in service_config and service_config[
                'dateend'] else None

        default_date_end = QDateTime.fromString(
            service_config['default']['dateend'],
            Qt.ISODate) if service_config['default'].get('dateend') else None

        filter_widget.set_date_range_limits(date_start, date_end)
        filter_widget.set_current_date_range(default_date_start,
                                             default_date_end)

        if service_config['default'].get('boundingboxpredefined'):
            filter_widget.set_predefined_bounding_box(
                service_config['default'].get('boundingboxpredefined'))
        if service_config['default'].get('minimumlatitude'):
            filter_widget.set_min_latitude(
                service_config['default'].get('minimumlatitude'))
        if service_config['default'].get('maximumlatitude'):
            filter_widget.set_max_latitude(
                service_config['default'].get('maximumlatitude'))
        if service_config['default'].get('minimumlongitude'):
            filter_widget.set_min_longitude(
                service_config['default'].get('minimumlongitude'))
        if service_config['default'].get('maximumlongitude'):
            filter_widget.set_max_longitude(
                service_config['default'].get('maximumlongitude'))
        if service_config['default'].get('circlelatitude'):
            filter_widget.set_circle_latitude(
                service_config['default'].get('circlelatitude'))
        if service_config['default'].get('circlelongitude'):
            filter_widget.set_circle_longitude(
                service_config['default'].get('circlelongitude'))
        if service_config['default'].get('minimumcircleradius'):
            filter_widget.set_min_circle_radius(
                service_config['default'].get('minimumcircleradius'))
        if service_config['default'].get('maximumcircleradius'):
            filter_widget.set_max_circle_radius(
                service_config['default'].get('maximumcircleradius'))
        if service_config['default'].get('minimummagnitude'):
            filter_widget.set_min_magnitude(
                service_config['default'].get('minimummagnitude'))
        if service_config['default'].get('maximummagnitude'):
            filter_widget.set_max_magnitude(
                service_config['default'].get('maximummagnitude'))
        if service_config['default'].get('macromaxintensitygreater'):
            filter_widget.set_max_intensity_greater(
                service_config['default'].get('macromaxintensitygreater'))
        if service_config['default'].get('macromdpsgreaterthan'):
            filter_widget.set_mdps_greater_than(
                service_config['default'].get('macromdpsgreaterthan'))
        if service_config['default'].get('eventtype'):
            filter_widget.set_event_type(
                service_config['default'].get('eventtype'))
        updated_after = QDateTime.fromString(
            service_config['default']['updatedafter'], Qt.ISODate
        ) if service_config['default'].get('updatedafter') else None
        if updated_after:
            filter_widget.set_updated_after(updated_after)

        filter_widget.set_extent_limit(
            service_config.get('boundingbox', [-180, -90, 180, 90]))

        if service_type in [
                SERVICE_MANAGER.FDSNEVENT, SERVICE_MANAGER.MACROSEISMIC
        ]:
            tab_widget.widget(1).setEnabled(service_config['settings'].get(
                'queryeventid', False))

        info_widget.set_service(service_type=service_type,
                                service_id=service_id)

        filter_widget.set_service_id(service_id)
        filter_by_id_widget.set_service_id(service_id)
        if fetch_by_url_widget is not None:
            fetch_by_url_widget.set_service_id(service_id)

        remove_service_button.setEnabled(not service_config['read_only'])
        edit_service_button.setEnabled(not service_config['read_only'])
        rename_service_button.setEnabled(not service_config['read_only'])

    def _refresh_fdsnevent_widgets(self):
        """
        Refreshing the FDSN-Event UI depending on the WS chosen
        """
        if not self.fdsn_event_list.currentItem():
            return

        service_id = self.fdsn_event_list.currentItem().text()
        self._update_service_widgets(
            service_type=SERVICE_MANAGER.FDSNEVENT,
            service_id=service_id,
            filter_widget=self.fdsn_event_filter,
            filter_by_id_widget=self.fdsn_by_id_filter,
            fetch_by_url_widget=self.fdsn_by_url_widget,
            info_widget=self.earthquake_service_info_widget,
            remove_service_button=self.button_fdsn_remove_service,
            edit_service_button=self.button_fdsn_edit_service,
            rename_service_button=self.button_fdsn_rename_service,
            tab_widget=self.fdsn_tab_widget)

    def refreshFdsnMacroseismicWidgets(self):
        """
        Refreshing the FDSN-Macroseismic UI depending on the WS chosen
        """
        if not self.fdsn_macro_list.currentItem():
            return

        service_id = self.fdsn_macro_list.currentItem().text()
        self._update_service_widgets(
            service_type=SERVICE_MANAGER.MACROSEISMIC,
            service_id=service_id,
            filter_widget=self.macro_filter,
            filter_by_id_widget=self.macro_by_id_filter,
            fetch_by_url_widget=self.macro_by_url_widget,
            info_widget=self.macro_service_info_widget,
            remove_service_button=self.button_macro_remove_service,
            edit_service_button=self.button_macro_edit_service,
            rename_service_button=self.button_macro_rename_service,
            tab_widget=self.macro_tab_widget)

    def refreshFdsnStationWidgets(self):
        """
        Refreshing the FDSN-Macroseismic UI depending on the WS chosen
        """
        if not self.fdsn_station_list.currentItem():
            return

        service_id = self.fdsn_station_list.currentItem().text()
        self._update_service_widgets(
            service_type=SERVICE_MANAGER.FDSNSTATION,
            service_id=service_id,
            filter_by_id_widget=self.station_by_id_filter,
            fetch_by_url_widget=self.station_by_url_widget,
            filter_widget=self.station_filter,
            info_widget=self.station_service_info_widget,
            remove_service_button=self.button_station_remove_service,
            edit_service_button=self.button_station_edit_service,
            rename_service_button=self.button_station_rename_service,
            tab_widget=self.fdsnstation_tab_widget)

    def refreshOgcWidgets(self):
        """
        read the ogc_combo and fill it with the services
        """
        self.ogc_list_model.clear()
        ogc_selection = self.ogc_combo.currentData()

        services = SERVICE_MANAGER.available_services(ogc_selection)

        group_items = {}

        for service in services:
            service_config = SERVICE_MANAGER.service_details(
                ogc_selection, service)
            group = service_config.get('group')
            if not group or group in group_items:
                continue

            group_item = QStandardItem(group)
            group_item.setFlags(Qt.ItemIsEnabled)
            self.ogc_list_model.appendRow([group_item])
            group_items[group] = group_item

        first_item = None
        for service in services:
            item = QStandardItem(service)
            item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
            item.setData(service, role=Qt.UserRole)
            if not first_item:
                first_item = item

            service_config = SERVICE_MANAGER.service_details(
                ogc_selection, service)
            group = service_config.get('group')
            if group:
                parent = group_items[group]
                parent.appendRow([item])
            else:
                self.ogc_list_model.appendRow([item])

        self.ogc_list.expandAll()
        first_item_index = self.ogc_list_model.indexFromItem(first_item)
        self.ogc_list.selectionModel().select(
            first_item_index, QItemSelectionModel.ClearAndSelect)

        service_config = SERVICE_MANAGER.service_details(
            ogc_selection, self.get_current_service_id(ogc_selection))
        self.button_ogc_edit_service.setEnabled(
            not service_config['read_only'])
        self.button_ogc_rename_service.setEnabled(
            not service_config['read_only'])
        self.button_ogc_remove_service.setEnabled(
            not service_config['read_only'])

    def _ogc_service_changed(self, _, __):
        """
        Triggered when the current OGC service changes
        """
        if not self.ogc_list.selectionModel().selectedIndexes():
            return

        current_service = self.ogc_list.selectionModel().selectedIndexes(
        )[0].data(Qt.UserRole)
        if not current_service:
            return

        self.ogc_service_widget.set_service(
            service_type=self.ogc_combo.currentData(),
            service_id=current_service)

        self.ogc_service_info_widget.set_service(
            service_type=self.ogc_combo.currentData(),
            service_id=current_service)

        service_config = SERVICE_MANAGER.service_details(
            self.ogc_combo.currentData(), current_service)
        self.button_ogc_edit_service.setEnabled(
            not service_config['read_only'])
        self.button_ogc_rename_service.setEnabled(
            not service_config['read_only'])
        self.button_ogc_remove_service.setEnabled(
            not service_config['read_only'])

    def _remove_service(self):
        """
        Removes the current service
        """
        service_type = self.get_current_service_type()
        service_id = self.get_current_service_id(service_type)
        if QMessageBox.question(
                self, self.tr('Remove Service'),
                self.tr('Are you sure you want to remove "{}"?'.format(
                    service_id))) != QMessageBox.Yes:
            return

        SERVICE_MANAGER.remove_service(service_type, service_id)

    def _edit_service(self):
        """
        Edits the current service
        """
        service_type = self.get_current_service_type()
        service_id = self.get_current_service_id(service_type)

        config_dialog = ServiceConfigurationDialog(self.iface, service_type,
                                                   service_id, self)
        if config_dialog.exec_():
            self.set_current_service(service_type, service_id)

    def _rename_service(self):
        """
        Renames the current service
        """
        service_type = self.get_current_service_type()
        service_id = self.get_current_service_id(service_type)

        dlg = QgsNewNameDialog(
            service_id,
            service_id, [],
            existing=SERVICE_MANAGER.available_services(service_type))
        dlg.setHintString(self.tr('Rename service configuration to'))
        dlg.setWindowTitle(self.tr('Rename Service Configuration'))
        dlg.setOverwriteEnabled(False)
        dlg.setConflictingNameWarning(
            self.tr('A configuration with this name already exists'))
        if not dlg.exec_():
            return

        new_name = dlg.name()
        SERVICE_MANAGER.rename_service(service_type, service_id, new_name)
        self.set_current_service(service_type, new_name)

    def set_current_service(self, service_type: str, service_id: str):
        """
        Sets the current service
        """
        if service_type == SERVICE_MANAGER.FDSNEVENT:
            self.fdsn_event_list.setCurrentItem(
                self.fdsn_event_list.findItems(service_id,
                                               Qt.MatchContains)[0])
        elif service_type == SERVICE_MANAGER.MACROSEISMIC:
            self.fdsn_macro_list.setCurrentItem(
                self.fdsn_macro_list.findItems(service_id,
                                               Qt.MatchContains)[0])
        elif service_type == SERVICE_MANAGER.FDSNSTATION:
            self.fdsn_station_list.setCurrentItem(
                self.fdsn_station_list.findItems(service_id,
                                                 Qt.MatchContains)[0])
        elif service_type in (SERVICE_MANAGER.WMS, SERVICE_MANAGER.WFS):
            self.ogc_combo.setCurrentIndex(
                self.ogc_combo.findData(service_type))

            indexes = self.ogc_list_model.match(
                self.ogc_list_model.index(0, 0),
                Qt.UserRole,
                service_id,
                flags=Qt.MatchExactly | Qt.MatchRecursive)
            if len(indexes) > 0:
                self.ogc_list.selectionModel().select(
                    indexes[0], QItemSelectionModel.ClearAndSelect)

    def _create_configuration(self):
        """
        Creates a new service configuration
        """
        service_type = self.get_current_service_type()
        dlg = QgsNewNameDialog(
            '',
            '', [],
            existing=SERVICE_MANAGER.available_services(service_type))
        dlg.setHintString(self.tr('Create a new service configuration named'))
        dlg.setWindowTitle(self.tr('New Service Configuration'))
        dlg.setOverwriteEnabled(False)
        dlg.setConflictingNameWarning(
            self.tr('A configuration with this name already exists'))
        if not dlg.exec_():
            return

        name = dlg.name()
        config_dialog = ServiceConfigurationDialog(self.iface, service_type,
                                                   name, self)
        if config_dialog.exec_():
            self.set_current_service(service_type, name)

    def _export_service(self):
        """
        Triggers exporting a service configuration
        """
        service_type = self.get_current_service_type()
        service_id = self.get_current_service_id(service_type)
        file, _ = QFileDialog.getSaveFileName(
            self, self.tr('Export Service'),
            QDir.homePath() + '/{}.json'.format(service_id),
            'JSON Files (*.json)')
        if not file:
            return

        file = QgsFileUtils.ensureFileNameHasExtension(file, ['json'])

        if SERVICE_MANAGER.export_service(service_type, service_id, file):
            self.message_bar.pushMessage(self.tr("Service exported"),
                                         Qgis.Success, 5)
        else:
            self.message_bar.pushMessage(
                self.tr("An error occurred while exporting service"),
                Qgis.Critical, 5)

    def _import_configuration(self):
        """
        Triggers importing a configuration
        """
        file, _ = QFileDialog.getOpenFileName(self, self.tr('Import Service'),
                                              QDir.homePath(),
                                              'JSON Files (*.json)')
        if not file:
            return

        res, err = SERVICE_MANAGER.import_service(file)
        if res:
            self.message_bar.pushMessage(self.tr("Service imported"),
                                         Qgis.Success, 5)
        else:
            self.message_bar.pushMessage(err, Qgis.Critical, 5)

    def _getEventList(self):
        """
        read the event URL and convert the response in a list
        """
        if self.get_current_service_type() in (SERVICE_MANAGER.WMS,
                                               SERVICE_MANAGER.WFS):
            self.ogc_service_widget.add_selected_layers()
            return

        if self.fetcher:
            # TODO - cancel current request
            return

        self.fetcher = self.get_fetcher()

        def on_started():
            self.progressBar.setValue(0)
            self.progressBar.setRange(0, 0)

        def on_progress(progress: float):
            self.progressBar.setRange(0, 100)
            self.progressBar.setValue(progress)

        self.fetcher.started.connect(on_started)
        self.fetcher.progress.connect(on_progress)
        self.fetcher.finished.connect(self._fetcher_finished)
        self.fetcher.message.connect(self._fetcher_message)
        self.button_box.button(QDialogButtonBox.Ok).setText(
            self.tr('Fetching'))
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)

        self.fetcher.fetch_data()

    def _fetcher_message(self, message, level):
        """
        Handles message feedback from a fetcher
        """
        self.message_bar.clearWidgets()
        self.message_bar.pushMessage(message, level, 0)

    def _fetcher_finished(self, res):  # pylint: disable=too-many-branches
        """
        Triggered when a fetcher is finished
        """
        self.progressBar.setRange(0, 100)
        self.progressBar.reset()
        self.button_box.button(QDialogButtonBox.Ok).setText(
            self.tr('Fetch Data'))
        self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)

        if not res:
            self.fetcher.deleteLater()
            self.fetcher = None
            return

        found_results = False

        layers = []
        if self.fetcher.service_type in (SERVICE_MANAGER.FDSNEVENT,
                                         SERVICE_MANAGER.MACROSEISMIC):
            layer = self.fetcher.create_event_layer()
            if layer:
                layers.append(layer)
            if self.fetcher.service_type == SERVICE_MANAGER.MACROSEISMIC:
                layer = self.fetcher.create_mdp_layer()
                if layer:
                    layers.append(layer)

            if layers:
                events_count = layers[0].featureCount()
                found_results = bool(events_count)

                service_limit = self.fetcher.service_config['settings'].get(
                    'querylimitmaxentries', None)
                self.message_bar.clearWidgets()
                if service_limit is not None and events_count >= service_limit:
                    self.message_bar.pushMessage(
                        self.tr("Query exceeded the service's result limit"),
                        Qgis.Critical, 0)
                elif events_count > 500:
                    self.message_bar.pushMessage(
                        self.tr(
                            "Query returned a large number of results ({})".
                            format(events_count)), Qgis.Warning, 0)
                elif events_count == 0:
                    self.message_bar.pushMessage(
                        self.
                        tr("Query returned no results - possibly parameters are invalid for this service"
                           ), Qgis.Critical, 0)
                else:
                    self.message_bar.pushMessage(
                        self.tr("Query returned {} records").format(
                            events_count), Qgis.Success, 0)
        elif self.fetcher.service_type == SERVICE_MANAGER.FDSNSTATION:
            layers.append(self.fetcher.create_stations_layer())
            stations_count = layers[0].featureCount()
            found_results = bool(stations_count)

            if stations_count == 0:
                self.message_bar.pushMessage(
                    self.
                    tr("Query returned no results - possibly parameters are invalid for this service"
                       ), Qgis.Critical, 0)
            else:
                self.message_bar.pushMessage(
                    self.tr("Query returned {} stations").format(
                        stations_count), Qgis.Info, 0)
        else:
            assert False

        self.fetcher.deleteLater()
        self.fetcher = None

        if found_results:
            QgsProject.instance().addMapLayers(layers)
示例#38
0
class DialogImportData(QDialog, DIALOG_UI):
    open_dlg_import_schema = pyqtSignal(dict)  # dict with key-value params
    BUTTON_NAME_IMPORT_DATA = QCoreApplication.translate(
        "DialogImportData", "Import data")
    BUTTON_NAME_GO_TO_CREATE_STRUCTURE = QCoreApplication.translate(
        "DialogImportData", "Go to Create Structure...")

    def __init__(self,
                 iface,
                 conn_manager,
                 context,
                 link_to_import_schema=True,
                 parent=None):
        QDialog.__init__(self, parent)
        self.setupUi(self)

        QgsGui.instance().enableAutoGeometryRestore(self)
        self.iface = iface
        self.conn_manager = conn_manager
        self.db_source = context.get_db_sources()[0]
        self.link_to_import_schema = link_to_import_schema
        self.db = self.conn_manager.get_db_connector_from_source(
            self.db_source)
        self.base_configuration = BaseConfiguration()
        self.logger = Logger()
        self.app = AppInterface()
        self.__ladmcol_models = LADMColModelRegistry()

        self.java_dependency = JavaDependency()
        self.java_dependency.download_dependency_completed.connect(
            self.download_java_complete)
        self.java_dependency.download_dependency_progress_changed.connect(
            self.download_java_progress_change)

        self.ilicache = IliCache(self.base_configuration)
        self.ilicache.refresh()

        self._dbs_supported = ConfigDBsSupported()
        self._running_tool = False

        # There may be 1 case where we need to emit a db_connection_changed from the Import Data dialog:
        #   1) Connection Settings was opened and the DB conn was changed.
        self._db_was_changed = False  # To postpone calling refresh gui until we close this dialog instead of settings

        # Similarly, we could call a refresh on layers and relations cache in 1 case:
        #   1) If the ID dialog was called for the COLLECTED source: opening Connection Settings and changing the DB
        #      connection.
        self._schedule_layers_and_relations_refresh = False

        # We need bar definition above calling clear_messages
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.layout().addWidget(self.bar, 0, 0, Qt.AlignTop)

        self.xtf_file_browse_button.clicked.connect(
            make_file_selector(
                self.xtf_file_line_edit,
                title=QCoreApplication.translate(
                    "DialogImportData", "Open Transfer or Catalog File"),
                file_filter=QCoreApplication.translate(
                    "DialogImportData",
                    'Transfer File (*.xtf *.itf);;Catalogue File (*.xml *.xls *.xlsx)'
                )))

        self.validators = Validators()
        self.xtf_file_line_edit.setPlaceholderText(
            QCoreApplication.translate("DialogImportData",
                                       "[Name of the XTF to be imported]"))
        fileValidator = FileValidator(pattern=['*.xtf', '*.itf', '*.xml'])
        self.xtf_file_line_edit.setValidator(fileValidator)
        self.xtf_file_line_edit.textChanged.connect(self.update_import_models)
        self.xtf_file_line_edit.textChanged.emit(
            self.xtf_file_line_edit.text())

        # db
        self.connection_setting_button.clicked.connect(self.show_settings)
        self.connection_setting_button.setText(
            QCoreApplication.translate("DialogImportData",
                                       "Connection Settings"))

        # LOG
        self.log_config.setTitle(
            QCoreApplication.translate("DialogImportData", "Show log"))

        self.buttonBox.accepted.disconnect()
        self.buttonBox.clicked.connect(self.accepted_import_data)
        self.buttonBox.clear()
        self.buttonBox.addButton(QDialogButtonBox.Cancel)
        self._accept_button = self.buttonBox.addButton(
            self.BUTTON_NAME_IMPORT_DATA, QDialogButtonBox.AcceptRole)
        self.buttonBox.addButton(QDialogButtonBox.Help)
        self.buttonBox.helpRequested.connect(self.show_help)

        self.update_connection_info()
        self.restore_configuration()

    def accepted_import_data(self, button):
        if self.buttonBox.buttonRole(button) == QDialogButtonBox.AcceptRole:
            if button.text() == self.BUTTON_NAME_IMPORT_DATA:
                self.accepted()
            elif button.text() == self.BUTTON_NAME_GO_TO_CREATE_STRUCTURE:
                self.close()  # Close import data dialog
                self.open_dlg_import_schema.emit({
                    'selected_models':
                    self.get_ili_models()
                })  # Emit signal to open import schema dialog

    def reject(self):
        if self._running_tool:
            QMessageBox.information(
                self, QCoreApplication.translate("DialogImportData",
                                                 "Warning"),
                QCoreApplication.translate(
                    "DialogImportData",
                    "The Import Data tool is still running. Please wait until it finishes."
                ))
        else:
            self.close_dialog()

    def close_dialog(self):
        """
        We use this method to be safe when emitting the db_connection_changed, otherwise we could trigger slots that
        unload the plugin, destroying dialogs and thus, leading to crashes.
        """
        if self._schedule_layers_and_relations_refresh:
            self.conn_manager.db_connection_changed.connect(
                self.app.core.cache_layers_and_relations)

        if self._db_was_changed:
            # If the db was changed, it implies it complies with ladm_col, hence the second parameter
            self.conn_manager.db_connection_changed.emit(
                self.db, True, self.db_source)

        if self._schedule_layers_and_relations_refresh:
            self.conn_manager.db_connection_changed.disconnect(
                self.app.core.cache_layers_and_relations)

        self.logger.info(__name__, "Dialog closed.")
        self.done(QDialog.Accepted)

    def update_connection_info(self):
        db_description = self.db.get_description_conn_string()
        if db_description:
            self.db_connect_label.setText(db_description)
            self.db_connect_label.setToolTip(self.db.get_display_conn_string())
            self._accept_button.setEnabled(True)
        else:
            self.db_connect_label.setText(
                QCoreApplication.translate("DialogImportData",
                                           "The database is not defined!"))
            self.db_connect_label.setToolTip('')
            self._accept_button.setEnabled(False)

    def update_import_models(self):
        self.clear_messages()
        error_msg = None

        if not self.xtf_file_line_edit.text().strip():
            color = '#ffd356'  # Light orange
            self.import_models_qmodel = QStandardItemModel()
            self.import_models_list_view.setModel(self.import_models_qmodel)
        else:
            if os.path.isfile(self.xtf_file_line_edit.text().strip()):
                color = '#fff'  # White

                self.import_models_qmodel = QStandardItemModel()
                model_names = get_models_from_xtf(
                    self.xtf_file_line_edit.text().strip())

                for model in self.__ladmcol_models.supported_models():
                    if not model.hidden() and model.full_name() in model_names:
                        item = QStandardItem(model.full_alias())
                        item.setData(model.full_name(), Qt.UserRole)
                        item.setCheckable(False)
                        item.setEditable(False)
                        self.import_models_qmodel.appendRow(item)

                if self.import_models_qmodel.rowCount() > 0:
                    self.import_models_list_view.setModel(
                        self.import_models_qmodel)
                else:
                    error_msg = QCoreApplication.translate(
                        "DialogImportData",
                        "No models were found in the XTF. Is it a valid file?")
                    color = '#ffd356'  # Light orange
                    self.import_models_qmodel = QStandardItemModel()
                    self.import_models_list_view.setModel(
                        self.import_models_qmodel)
            else:
                error_msg = QCoreApplication.translate(
                    "DialogImportData", "Please set a valid XTF file")
                color = '#ffd356'  # Light orange
                self.import_models_qmodel = QStandardItemModel()
                self.import_models_list_view.setModel(
                    self.import_models_qmodel)
        self.xtf_file_line_edit.setStyleSheet(
            'QLineEdit {{ background-color: {} }}'.format(color))

        if error_msg:
            self.txtStdout.setText(error_msg)
            self.show_message(error_msg, Qgis.Warning)
            self.import_models_list_view.setFocus()
            return

    def get_ili_models(self):
        ili_models = list()
        for index in range(self.import_models_qmodel.rowCount()):
            item = self.import_models_qmodel.item(index)
            ili_models.append(item.data(Qt.UserRole))
        return ili_models

    def show_settings(self):
        # We only need those tabs related to Model Baker/ili2db operations
        dlg = SettingsDialog(self.conn_manager, parent=self)
        dlg.setWindowTitle(
            QCoreApplication.translate("DialogImportData",
                                       "Target DB Connection Settings"))
        dlg.show_tip(
            QCoreApplication.translate(
                "DialogImportData",
                "Configure where do you want the XTF data to be imported."))
        dlg.set_db_source(self.db_source)
        dlg.set_tab_pages_list(
            [SETTINGS_CONNECTION_TAB_INDEX, SETTINGS_MODELS_TAB_INDEX])

        # Connect signals (DBUtils, Core)
        dlg.db_connection_changed.connect(self.db_connection_changed)
        if self.db_source == COLLECTED_DB_SOURCE:
            self._schedule_layers_and_relations_refresh = True

        dlg.set_action_type(EnumDbActionType.IMPORT)

        if dlg.exec_():
            self.db = dlg.get_db_connection()
            self.update_connection_info()

    def db_connection_changed(self, db, ladm_col_db, db_source):
        self._db_was_changed = True
        self.clear_messages()

    def accepted(self):
        self._running_tool = True
        self.txtStdout.clear()
        self.progress_bar.setValue(0)
        self.bar.clearWidgets()

        if not os.path.isfile(self.xtf_file_line_edit.text().strip()):
            self._running_tool = False
            error_msg = QCoreApplication.translate(
                "DialogImportData",
                "Please set a valid XTF file before importing data. XTF file does not exist."
            )
            self.txtStdout.setText(error_msg)
            self.show_message(error_msg, Qgis.Warning)
            self.xtf_file_line_edit.setFocus()
            return

        java_home_set = self.java_dependency.set_java_home()
        if not java_home_set:
            message_java = QCoreApplication.translate(
                "DialogImportData",
                """Configuring Java {}...""").format(JAVA_REQUIRED_VERSION)
            self.txtStdout.setTextColor(QColor('#000000'))
            self.txtStdout.clear()
            self.txtStdout.setText(message_java)
            self.java_dependency.get_java_on_demand()
            self.disable()
            return

        configuration = self.update_configuration()

        if configuration.disable_validation:  # If data validation at import is disabled, we ask for confirmation
            self.msg = QMessageBox()
            self.msg.setIcon(QMessageBox.Question)
            self.msg.setText(
                QCoreApplication.translate(
                    "DialogImportData",
                    "Are you sure you want to import your data without validation?"
                ))
            self.msg.setWindowTitle(
                QCoreApplication.translate("DialogImportData",
                                           "Import XTF without validation?"))
            self.msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            res = self.msg.exec_()
            if res == QMessageBox.No:
                self._running_tool = False
                return

        if not self.xtf_file_line_edit.validator().validate(
                configuration.xtffile, 0)[0] == QValidator.Acceptable:
            self._running_tool = False
            error_msg = QCoreApplication.translate(
                "DialogImportData",
                "Please set a valid XTF before importing data.")
            self.txtStdout.setText(error_msg)
            self.show_message(error_msg, Qgis.Warning)
            self.xtf_file_line_edit.setFocus()
            return

        if not self.get_ili_models():
            self._running_tool = False
            error_msg = QCoreApplication.translate(
                "DialogImportData",
                "The selected XTF file does not have information according to the LADM-COL model to import."
            )
            self.txtStdout.setText(error_msg)
            self.show_message(error_msg, Qgis.Warning)
            self.import_models_list_view.setFocus()
            return

        # Get list of models present in the XTF file, in the DB and in the list of required models (by the plugin)
        ili_models = set([ili_model for ili_model in self.get_ili_models()])

        supported_models_in_ili = set([
            m.full_name() for m in self.__ladmcol_models.supported_models()
        ]).intersection(ili_models)

        if not supported_models_in_ili:
            self._running_tool = False
            error_msg = QCoreApplication.translate("DialogImportData",
                                                   "The selected XTF file does not have data from any LADM-COL model supported by the LADM-COL Assistant. " \
                                                   "Therefore, you cannot import it! These are the models supported:\n\n * {}").format(" \n * ".join([m.full_alias() for m in self.__ladmcol_models.supported_models()]))
            self.txtStdout.setText(error_msg)
            self.show_message(error_msg, Qgis.Warning)
            self.import_models_list_view.setFocus()
            return

        db_models = set(self.db.get_models())
        suggested_models = sorted(ili_models.difference(db_models))

        if not ili_models.issubset(db_models):
            self._running_tool = False
            error_msg = QCoreApplication.translate("DialogImportData",
                                                   "IMPORT ERROR: The XTF file to import does not have the same models as the target database schema. " \
                                                   "Please create a schema that also includes the following missing modules:\n\n * {}").format(
                " \n * ".join(suggested_models))
            self.txtStdout.clear()
            self.txtStdout.setTextColor(QColor('#000000'))
            self.txtStdout.setText(error_msg)
            self.show_message(error_msg, Qgis.Warning)
            self.xtf_file_line_edit.setFocus()

            # button is removed to define order in GUI
            for button in self.buttonBox.buttons():
                if button.text() == self.BUTTON_NAME_IMPORT_DATA:
                    self.buttonBox.removeButton(button)

            # Check if button was previously added
            self.remove_create_structure_button()

            if self.link_to_import_schema:
                self.buttonBox.addButton(
                    self.BUTTON_NAME_GO_TO_CREATE_STRUCTURE,
                    QDialogButtonBox.AcceptRole).setStyleSheet(
                        "color: #aa2222;")
            self.buttonBox.addButton(self.BUTTON_NAME_IMPORT_DATA,
                                     QDialogButtonBox.AcceptRole)

            return

        with OverrideCursor(Qt.WaitCursor):
            self.progress_bar.show()

            self.disable()
            self.txtStdout.setTextColor(QColor('#000000'))
            self.txtStdout.clear()

            dataImporter = iliimporter.Importer(dataImport=True)

            db_factory = self._dbs_supported.get_db_factory(self.db.engine)

            dataImporter.tool = db_factory.get_model_baker_db_ili_mode()
            dataImporter.configuration = configuration

            self.save_configuration(configuration)

            dataImporter.stdout.connect(self.print_info)
            dataImporter.stderr.connect(self.on_stderr)
            dataImporter.process_started.connect(self.on_process_started)
            dataImporter.process_finished.connect(self.on_process_finished)

            self.progress_bar.setValue(25)

            try:
                if dataImporter.run() != iliimporter.Importer.SUCCESS:
                    self._running_tool = False
                    self.show_message(
                        QCoreApplication.translate(
                            "DialogImportData",
                            "An error occurred when importing the data. For more information see the log..."
                        ), Qgis.Warning)
                    return
            except JavaNotFoundError:
                self._running_tool = False
                error_msg_java = QCoreApplication.translate(
                    "DialogImportData",
                    "Java {} could not be found. You can configure the JAVA_HOME environment variable manually, restart QGIS and try again."
                ).format(JAVA_REQUIRED_VERSION)
                self.txtStdout.setTextColor(QColor('#000000'))
                self.txtStdout.clear()
                self.txtStdout.setText(error_msg_java)
                self.show_message(error_msg_java, Qgis.Warning)
                return

            self._running_tool = False
            self.buttonBox.clear()
            self.buttonBox.setEnabled(True)
            self.buttonBox.addButton(QDialogButtonBox.Close)
            self.progress_bar.setValue(100)
            self.show_message(
                QCoreApplication.translate(
                    "DialogImportData",
                    "Import of the data was successfully completed"),
                Qgis.Success)

    def download_java_complete(self):
        self.accepted()

    def download_java_progress_change(self, progress):
        self.progress_bar.setValue(progress / 2)
        if (progress % 20) == 0:
            self.txtStdout.append('...')

    def remove_create_structure_button(self):
        for button in self.buttonBox.buttons():
            if button.text() == self.BUTTON_NAME_GO_TO_CREATE_STRUCTURE:
                self.buttonBox.removeButton(button)

    def save_configuration(self, configuration):
        settings = QSettings()
        settings.setValue(
            'Asistente-LADM-COL/QgisModelBaker/ili2pg/xtffile_import',
            configuration.xtffile)
        settings.setValue('Asistente-LADM-COL/QgisModelBaker/show_log',
                          not self.log_config.isCollapsed())

    def restore_configuration(self):
        settings = QSettings()
        self.xtf_file_line_edit.setText(
            settings.value(
                'Asistente-LADM-COL/QgisModelBaker/ili2pg/xtffile_import'))

        # Show log
        value_show_log = settings.value(
            'Asistente-LADM-COL/QgisModelBaker/show_log', False, type=bool)
        self.log_config.setCollapsed(not value_show_log)

        # set model repository
        # if there is no option  by default use online model repository
        self.use_local_models = settings.value(
            'Asistente-LADM-COL/models/custom_model_directories_is_checked',
            DEFAULT_USE_CUSTOM_MODELS,
            type=bool)
        if self.use_local_models:
            self.custom_model_directories = settings.value(
                'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR)

    def update_configuration(self):
        """
        Get the configuration that is updated with the user configuration changes on the dialog.
        :return: Configuration
        """
        db_factory = self._dbs_supported.get_db_factory(self.db.engine)

        configuration = ImportDataConfiguration()
        db_factory.set_ili2db_configuration_params(self.db.dict_conn_params,
                                                   configuration)

        configuration.xtffile = self.xtf_file_line_edit.text().strip()
        configuration.delete_data = False

        configuration.srs_auth = QSettings().value(
            'Asistente-LADM-COL/QgisModelBaker/srs_auth', DEFAULT_SRS_AUTH,
            str)
        configuration.srs_code = QSettings().value(
            'Asistente-LADM-COL/QgisModelBaker/srs_code',
            int(DEFAULT_SRS_CODE), int)
        configuration.inheritance = ILI2DBNames.DEFAULT_INHERITANCE
        configuration.create_basket_col = ILI2DBNames.CREATE_BASKET_COL
        configuration.create_import_tid = ILI2DBNames.CREATE_IMPORT_TID
        configuration.stroke_arcs = ILI2DBNames.STROKE_ARCS
        configuration.with_importtid = True

        full_java_exe_path = JavaDependency.get_full_java_exe_path()
        if full_java_exe_path:
            self.base_configuration.java_path = full_java_exe_path

        # User could have changed the default values
        self.use_local_models = QSettings().value(
            'Asistente-LADM-COL/models/custom_model_directories_is_checked',
            DEFAULT_USE_CUSTOM_MODELS,
            type=bool)
        self.custom_model_directories = QSettings().value(
            'Asistente-LADM-COL/models/custom_models', DEFAULT_MODELS_DIR)

        # Check custom model directories
        if self.use_local_models:
            if not self.custom_model_directories:
                self.base_configuration.custom_model_directories_enabled = False
            else:
                self.base_configuration.custom_model_directories = self.custom_model_directories
                self.base_configuration.custom_model_directories_enabled = True

        configuration.base_configuration = self.base_configuration
        if self.get_ili_models():
            configuration.ilimodels = ';'.join(self.get_ili_models())

        configuration.disable_validation = not QSettings().value(
            'Asistente-LADM-COL/models/validate_data_importing_exporting',
            True, bool)

        return configuration

    def print_info(self, text, text_color='#000000', clear=False):
        self.txtStdout.setTextColor(QColor(text_color))
        self.txtStdout.append(text)
        QCoreApplication.processEvents()

    def on_stderr(self, text):
        color_log_text(text, self.txtStdout)
        self.advance_progress_bar_by_text(text)

    def on_process_started(self, command):
        self.disable()
        self.txtStdout.setTextColor(QColor('#000000'))
        self.txtStdout.clear()
        self.txtStdout.setText(command)
        QCoreApplication.processEvents()

    def on_process_finished(self, exit_code, result):
        color = '#004905' if exit_code == 0 else '#aa2222'
        self.txtStdout.setTextColor(QColor(color))
        self.txtStdout.append('Finished ({})'.format(exit_code))
        if result == iliimporter.Importer.SUCCESS:
            self.buttonBox.clear()
            self.buttonBox.setEnabled(True)
            self.buttonBox.addButton(QDialogButtonBox.Close)
        else:
            self.show_message(
                QCoreApplication.translate("DialogImportData",
                                           "Error when importing data"),
                Qgis.Warning)

            # Open log
            if self.log_config.isCollapsed():
                self.log_config.setCollapsed(False)

    def advance_progress_bar_by_text(self, text):
        if text.strip() == 'Info: compile models...':
            self.progress_bar.setValue(50)
            QCoreApplication.processEvents()
        elif text.strip() == 'Info: create table structure...':
            self.progress_bar.setValue(55)
            QCoreApplication.processEvents()
        elif text.strip() == 'Info: first validation pass...':
            self.progress_bar.setValue(60)
            QCoreApplication.processEvents()
        elif text.strip() == 'Info: second validation pass...':
            self.progress_bar.setValue(80)
            QCoreApplication.processEvents()

    def clear_messages(self):
        self.bar.clearWidgets(
        )  # Remove previous messages before showing a new one
        self.txtStdout.clear()  # Clear previous log messages
        self.progress_bar.setValue(0)  # Initialize progress bar

    def show_help(self):
        show_plugin_help("import_data")

    def disable(self):
        self.source_config.setEnabled(False)
        self.target_config.setEnabled(False)
        self.buttonBox.setEnabled(False)

    def enable(self):
        self.source_config.setEnabled(True)
        self.target_config.setEnabled(True)
        self.buttonBox.setEnabled(True)

    def show_message(self, message, level):
        if level == Qgis.Warning:
            self.enable()

        self.bar.clearWidgets(
        )  # Remove previous messages before showing a new one
        self.bar.pushMessage("Asistente LADM-COL", message, level, duration=0)