Esempio n. 1
0
    def update_jobs_table(self):
        if self.jobs:
            table_model = JobsTableModel(self.jobs, self)
            proxy_model = QSortFilterProxyModel()
            proxy_model.setSourceModel(table_model)
            self.jobs_view.setModel(proxy_model)
            # Add "Details" buttons in cell
            for row in range(0, len(self.jobs)):
                btn = QtWidgets.QPushButton(self.tr("Details"))
                btn.clicked.connect(self.btn_details)
                btn.setMinimumSize(QSize(75, 0))
                btn.setMaximumSize(QSize(150, 16777215))
                self.jobs_view.setIndexWidget(proxy_model.index(row, 5), btn)

            #self.jobs_view.widget(proxy_model.index(row, 2)).setTextAlignment(Qt.AlignCenter)

            # self.jobs_view.setMinimumSize(QSize(0, 100))
            # self.jobs_view.setColumnWidth(1, 400)
            # self.jobs_view.setColumnWidth(2, 200)
            # self.jobs_view.setColumnWidth(3, 200)
            # self.jobs_view.setColumnWidth(4, 200)
            # self.jobs_view.setColumnWidth(5, 200)

            self.jobs_view.selectionModel().selectionChanged.connect(
                self.selection_changed)
Esempio n. 2
0
class BigList(Ui_BigList, QWidget):
    itemselected = pyqtSignal(QModelIndex)
    closewidget = pyqtSignal()
    savewidget = pyqtSignal()

    def __init__(self, parent=None, centeronparent=False, showsave=True):
        super(BigList, self).__init__(parent)
        self.setupUi(self)
        self.centeronparent = centeronparent
        self.listView.clicked.connect(self.selected)
        self.saveButton.pressed.connect(self.savewidget.emit)
        self.closebutton.pressed.connect(self.closewidget.emit)
        self._index = None
        self.search.textEdited.connect(self.set_filter)
        self.filtermodel = QSortFilterProxyModel()
        self.filtermodel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.listView.setModel(self.filtermodel)
        self.listView.setWordWrap(True)

        self.saveButton.setVisible(showsave)

        utils.install_touch_scroll(self.listView)

    def set_filter(self, text):
        self.filtermodel.setFilterRegExp(text + ".*")

    def selected(self, index):
        self._index = index
        self._index = self.filtermodel.mapToSource(index)
        self.itemselected.emit(self._index)

    def setmodel(self, model):
        self.filtermodel.setSourceModel(model)

    def setlabel(self, fieldname):
        self.fieldnameLabel.setText(fieldname)

    def currentindex(self):
        return self._index

    def setcurrentindex(self, index):
        if index is None:
            index = QModelIndex()
        if isinstance(index, int):
            index = self.listView.model().index(index, 0)
        self.listView.setCurrentIndex(index)

    def show(self):
        super(BigList, self).show()

        if self.centeronparent:
            width = self.parent().width()
            height = self.parent().height()
            self.move(width / 4, 0)
            self.resize(QSize(width / 2, height))
Esempio n. 3
0
    def setup_class_table(self, classes):
        default_codes = sorted(
            [c['Initial_Code'] for c in self.default_classes])
        input_codes = sorted([c['Initial_Code'] for c in classes])
        new_codes = [c for c in input_codes if c not in default_codes]
        missing_codes = [c for c in default_codes if c not in input_codes]
        if len(new_codes) > 0:
            QtWidgets.QMessageBox.warning(
                None, self.tr("Warning"),
                self.
                tr(u"Some of the class codes ({}) in the definition file do not appear in the chosen data file."
                   .format(', '.join([str(c) for c in new_codes]), None)))
        if len(missing_codes) > 0:
            QtWidgets.QMessageBox.warning(
                None, self.tr("Warning"),
                self.
                tr(u"Some of the class codes ({}) in the data file do not appear in the chosen definition file."
                   .format(', '.join([str(c) for c in missing_codes]), None)))

        # Setup a new classes list with the new class codes for all classes
        # included in default calsses, and and any other class codes that are
        # missing added from the default class list
        classes = [c for c in classes if c['Initial_Code'] in default_codes]
        classes.extend([
            c for c in self.default_classes
            if c['Initial_Code'] not in input_codes
        ])

        table_model = AggTableModel(classes, parent=self)
        proxy_model = QSortFilterProxyModel()
        proxy_model.setSourceModel(table_model)
        self.remap_view.setModel(proxy_model)

        # Add selector in cell
        for row in range(0, len(classes)):
            lc_classes = QtWidgets.QComboBox()
            lc_classes.currentIndexChanged.connect(self.lc_class_combo_changed)
            # Add the classes in order of their codes
            lc_classes.addItems(
                sorted(list(self.final_classes.keys()),
                       key=lambda k: self.final_classes[k]))
            ind = lc_classes.findText(classes[row]['Final_Label'])
            if ind != -1:
                lc_classes.setCurrentIndex(ind)
            self.remap_view.setIndexWidget(
                proxy_model.index(row,
                                  self.remap_view.model().columnCount() - 1),
                lc_classes)

        self.remap_view.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.remap_view.setColumnWidth(1, 450)
        self.remap_view.horizontalHeader().setStretchLastSection(True)
        return True
class ExtendedComboBox(QComboBox):
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())
        self.completer = QCompleter(self.pFilterModel, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.completer.popup().setStyleSheet("min-height: 150px")
        self.completer.popup().setAlternatingRowColors(True)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited[str].connect(self.pFilterModel.setFilterFixedString)
Esempio n. 5
0
class ExtendedComboBox(QComboBox):
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())
        self.completer = QCompleter(self.pFilterModel, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.completer.popup().setStyleSheet('min-height: 150px')
        self.completer.popup().setAlternatingRowColors(True)
        self.setCompleter(self.completer)
        self.lineEdit().textEdited[unicode].connect(
            self.pFilterModel.setFilterFixedString)
Esempio n. 6
0
    def update_data_table(self):
        table_model = DataTableModel(self.datasets, self)
        proxy_model = QSortFilterProxyModel()
        proxy_model.setSourceModel(table_model)
        self.data_view.setModel(proxy_model)

        # Add "Notes" buttons in cell
        for row in range(0, len(self.datasets)):
            btn = QtWidgets.QPushButton(self.tr("Details"))
            btn.clicked.connect(self.btn_details)
            self.data_view.setIndexWidget(proxy_model.index(row, 7), btn)

        self.data_view.horizontalHeader().setResizeMode(
            QtWidgets.QHeaderView.ResizeToContents)

        self.data_view.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
def set_model_by_list(string_list, widget, proxy_model):
    """ Set the model according to the list """

    model = QStringListModel()
    model.setStringList(string_list)
    proxy_model.setSourceModel(model)
    proxy_model.setFilterKeyColumn(0)
    proxy_model_aux = QSortFilterProxyModel()
    proxy_model_aux.setSourceModel(model)
    proxy_model_aux.setFilterKeyColumn(0)
    widget.setModel(proxy_model_aux)
    widget.setModelColumn(0)
    completer = QCompleter()
    completer.setModel(proxy_model)
    completer.setCompletionColumn(0)
    completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
    widget.setCompleter(completer)
Esempio n. 8
0
    def config(self, token_model):

        space_model = XYZSpaceModel(self)

        proxy_model = QSortFilterProxyModel()
        proxy_model.setSourceModel(space_model)
        self.tableView_space.setModel(proxy_model)
        self.tableView_space.setSelectionMode(
            self.tableView_space.SingleSelection)
        self.tableView_space.setSelectionBehavior(
            self.tableView_space.SelectRows)
        self.tableView_space.setSortingEnabled(True)

        ############# connect gui
        self.tableView_space.pressed.connect(self.cb_table_row_selected)

        self.btn_use.clicked.connect(self._get_space_model().reset)
        TokenUX.config(self, token_model)
Esempio n. 9
0
class ExtendedComboBox(QComboBox):
    """Extended class of QComboBox so we can perform a filtering of items.
    """
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # add a filter model to filter matching items
        self.pFilterModel = QSortFilterProxyModel(self)
        self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.pFilterModel.setSourceModel(self.model())

        # add a completer, which uses the filter model
        self.completer = QCompleter(self.pFilterModel, self)
        # always show all (filtered) completions
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # connect signals
        self.lineEdit().textEdited[str].connect(
            self.pFilterModel.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)

    # on selection of an item from the completer,
    # select the corresponding item from combobox
    def on_completer_activated(self, text):
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)

    # on model change, update the models of the filter and completer as well
    def setModel(self, model):
        super(ExtendedComboBox, self).setModel(model)
        self.pFilterModel.setSourceModel(model)
        self.completer.setModel(self.pFilterModel)

    # on model column change, update the model column of
    # the filter and completer as well
    def setModelColumn(self, column):
        self.completer.setCompletionColumn(column)
        self.pFilterModel.setFilterKeyColumn(column)
        super(ExtendedComboBox, self).setModelColumn(column)
Esempio n. 10
0
class FilteredComboBox(QComboBox):
    """Custom QComboBox with filtering option."""
    def __init__(self, parent=None):
        super(FilteredComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLength)
        self.setEditable(True)
        self.filter_proxy_model = QSortFilterProxyModel(self)
        self.filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter_proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.filter_proxy_model.setSourceModel(self.model())
        self.completer = QCompleter(self.filter_proxy_model, self)
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)
        self.setMinimumSize(150, 25)
        self.setFont(QFont("Segoe UI", 10))
        self.setStyleSheet("QComboBox {background-color: white;}")
        self.setMaxVisibleItems(10)
        self.completer.activated.connect(self.on_completer_activated)
        self.lineEdit().textEdited.connect(
            self.filter_proxy_model.setFilterFixedString)

    def on_completer_activated(self, text):
        """Set active combobox item when a completer item is picked."""
        if not text:
            return
        idx = self.findText(text)
        self.setCurrentIndex(idx)
        self.activated[str].emit(self.itemText(idx))

    def setModel(self, model):
        """Set completer model after the combobox model."""
        super(FilteredComboBox, self).setModel(model)
        self.filter_proxy_model.setSourceModel(model)
        self.completer.setModel(self.filter_proxy_model)

    def setModelColumn(self, column_idx):
        """Set the correct column for completer and combobox model using column index."""
        self.completer.setCompletionColumn(column_idx)
        self.filter_proxy_model.setFilterKeyColumn(column_idx)
        super(FilteredComboBox, self).setModelColumn(column_idx)
Esempio n. 11
0
    def searchModel(self, columnIndex, columnValue):
        '''
        Searches for 'columnValue' in the column whose index is specified by 'columnIndex' in all
        rows contained in the model.
        '''
        if isinstance(columnValue, QVariant):
            columnValue = str(columnValue.toString())

        if not isinstance(columnValue, str):
            columnValue = str(columnValue)

        columnValue = columnValue.strip()

        proxy = QSortFilterProxyModel(self)
        proxy.setSourceModel(self._tableModel)
        proxy.setFilterKeyColumn(columnIndex)
        proxy.setFilterFixedString(columnValue)
        # Will return model index containing the primary key.
        matchingIndex = proxy.mapToSource(proxy.index(0, 0))

        return matchingIndex
Esempio n. 12
0
    def __init__(
            self, table_data, headers, parent=None, *args
    ):
        """
        Creates two QTableViews one of which is a frozen table while the
        other one can scroll behind it.
        :param table_data: The data that goes into the tables
        :type table_data: List
        :param headers: The header data of the tables.
        :type headers: List
        :param parent: The parent of the QTableView
        :type parent: QWidget
        :param args:
        :type args:
        """
        QTableView.__init__(self, parent)
        # set the table model
        self.table_model = BaseSTDMTableModel(
            table_data, headers, parent
        )
        # set the proxy model
        proxy_model = QSortFilterProxyModel(self)
        proxy_model.setSourceModel(self.table_model)
        # Assign a data model for TableView
        self.setModel(self.table_model)
        # frozen_table_view - first column
        self.frozen_table_view = QTableView(self)
        # Set the model for the widget, fixed column
        self.frozen_table_view.setModel(self.table_model)
        # Hide row headers
        self.frozen_table_view.verticalHeader().hide()
        # Widget does not accept focus
        self.frozen_table_view.setFocusPolicy(
            Qt.StrongFocus | Qt.TabFocus | Qt.ClickFocus
        )
        # The user can not resize columns
        self.frozen_table_view.horizontalHeader(). \
            setSectionResizeMode(QHeaderView.Fixed)
        self.frozen_table_view.setObjectName('frozen_table')
        self.setSelectionMode(QAbstractItemView.NoSelection)
        # Remove the scroll bar
        self.frozen_table_view.setHorizontalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff
        )
        self.frozen_table_view.setVerticalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff
        )
        # Puts more widgets to the foreground
        self.viewport().stackUnder(self.frozen_table_view)
        # # Log in to edit mode - even with one click
        # Set the properties of the column headings
        hh = self.horizontalHeader()
        # Text alignment centered
        hh.setDefaultAlignment(Qt.AlignCenter)

        self.set_column_width()
        # Set properties header lines
        vh = self.verticalHeader()
        vh.setDefaultSectionSize(25)  # height lines
        # text alignment centered
        vh.setDefaultAlignment(Qt.AlignCenter)
        vh.setVisible(True)
        # Height of rows - as in the main widget
        self.frozen_table_view.verticalHeader(). \
            setDefaultSectionSize(
            vh.defaultSectionSize()
        )
        # Show frozen table view
        self.frozen_table_view.show()
        # Set the size of him like the main

        self.setHorizontalScrollMode(
            QAbstractItemView.ScrollPerPixel
        )
        self.setVerticalScrollMode(
            QAbstractItemView.ScrollPerPixel
        )
        self.frozen_table_view.setVerticalScrollMode(
            QAbstractItemView.ScrollPerPixel
        )
        ## select the first column (STR Type)
        self.frozen_table_view.selectColumn(0)

        self.frozen_table_view.setEditTriggers(
            QAbstractItemView.AllEditTriggers
        )
        self.set_size()
        self.signals()
Esempio n. 13
0
class NafiDockWidget(QtWidgets.QDockWidget, Ui_NafiDockWidgetBase):
    closingPlugin = pyqtSignal()

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

        self.setupUi(self)

        # set up QTreeView
        self.treeView.setHeaderHidden(True)
        self.treeView.setSortingEnabled(True)
        self.treeView.setFocusPolicy(Qt.NoFocus)
        self.treeView.pressed.connect(self.treeViewPressed)

        # set up search signal
        self.lineEdit.textChanged.connect(self.searchTextChanged)
        self.searchText = ""

        # set up clear search
        self.clearSearchButton.clicked.connect(self.clearSearch)

        # set up About … dialog
        self.aboutButton.clicked.connect(self.showAboutDialog)

        # set up Download NAFI data … link button
        self.dataButton.clicked.connect(
            lambda: webbrowser.open(getNafiDataUrl()))

        # set up base model
        self.treeViewModel = NafiTreeViewModel(getNafiUrl())

        # set up proxy model for filtering
        self.proxyModel = QSortFilterProxyModel(self.treeView)
        self.proxyModel.setSourceModel(self.treeViewModel)
        self.proxyModel.setRecursiveFilteringEnabled(True)
        self.treeView.setModel(self.proxyModel)

        self.reader = NafiCapabilitiesReader()
        self.reader.capabilitiesDownloaded.connect(
            lambda xml: self.initModel(xml))

        # restore the view from source whenever this dock widget is made visible again
        self.visibilityChanged.connect(
            lambda visible: visible and self.loadNafiWms())

        # initialise proxied tree view model from WMS contents
        # self.loadNafiWms()

    def loadNafiWms(self):
        """Load the NAFI WMS and additional layers."""
        self.wmsUrl = getNafiUrl()
        self.reader.downloadCapabilities(self.wmsUrl)

    def initModel(self, wmsXml):
        """Initialise a QStandardItemModel from the NAFI WMS."""
        googSat = GoogleXyzItem()
        googHyb = GoogleXyzItem("y")
        googStr = GoogleXyzItem("m")
        # ibraWms = IbraWmsItem()
        ozTopoWmts = OzTopoWmtsItem()
        self.treeViewModel.loadWms(
            self.wmsUrl,
            wmsXml,
            additionalItems=[googSat, googHyb, googStr, ozTopoWmts])

        # set default sort and expansion
        self.proxyModel.sort(0, Qt.AscendingOrder)
        self.expandTopLevel()

    def expandTopLevel(self):
        # expand the top level items
        for row in range(self.proxyModel.rowCount()):
            self.treeView.expand(self.proxyModel.index(row, 0))

    def treeViewPressed(self, index):
        """Load a NAFI WMS layer given an index in the tree view."""
        assert isinstance(
            index, QModelIndex), "Supplied parameter is not a QModelIndex"

        realIndex = self.proxyModel.mapToSource(index)
        modelNode = self.treeViewModel.itemFromIndex(realIndex)

        # if we've got a layer and not a layer group, add to map
        if modelNode is not None:
            if isinstance(
                    modelNode,
                (GoogleXyzItem, IbraWmsItem, OzTopoWmtsItem, WmsItem)):
                modelNode.addLayer()

    def searchTextChanged(self, text):
        """Process a change in the search filter text."""
        # user adding characters and has exceeded 3 or more, or is removing characters
        if len(text) >= 3 or len(self.searchText) > len(text):
            regex = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
            self.proxyModel.setFilterRegExp(regex)
            self.treeView.expandAll()

        # update last search text state
        self.searchText = text

    def clearSearch(self):
        """Clear search data."""
        self.lineEdit.setText(None)
        self.treeView.collapseAll()

    def sizeHint(self):
        return QtCore.QSize(150, 400)

    def showAboutDialog(self):
        """Show an About … dialog."""
        aboutDialog = NafiAboutDialog()
        aboutDialog.exec_()

    def closeEvent(self, event):
        """Handle plug-in close."""
        self.closingPlugin.emit()
        event.accept()
class RuimtelijkePlannen(object):
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface and the mapCanvas
        self.iface = iface
        self.mapcanvas = iface.mapCanvas()
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        if not QSettings().value('locale/userLocale'):
            locale = QSettings().value('locale/globalLocale')[0:2]
        else:
            locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'RuimtelijkePlannen_{}.qm'.format(locale))

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

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

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Ruimtelijke Plannen')
        self.toolbar = self.iface.addToolBar(u'RuimtelijkePlannen')
        self.toolbar.setObjectName(u'RuimtelijkePlannen')

        self.nam = networkaccessmanager.NetworkAccessManager()
        self.project = QgsProject.instance()

        # initialize styles folder
        self.settings = QSettings()
        self.available_styles_folder = os.path.join(self.plugin_dir, 'styles')
        self.map_style = self.settings.value("RuimtelijkePlannen/map_style",
                                             "print")
        self.map_style_folder = os.path.join(self.available_styles_folder,
                                             self.map_style)
        if not os.path.isdir(self.map_style_folder):
            self.map_style = "print"
            self.map_style_folder = os.path.join(self.available_styles_folder,
                                                 self.map_style)

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

        We implement this ourselves since we do not inherit QObject.

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

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

        return QCoreApplication.translate('RuimtelijkePlannen', message)

    def add_action(self,
                   dialog,
                   icon_path,
                   text,
                   callback,
                   enabled_flag=True,
                   add_to_menu=True,
                   add_to_toolbar=True,
                   status_tip=None,
                   whats_this=None,
                   parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        if dialog:
            self.dlg = dialog

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToWebMenu(self.menu, action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        self.dlg = RuimtelijkePlannenDialog()
        self.settings_dlg = RuimtelijkePlannenSettingsDialog()

        self.add_action(dialog=None,
                        icon_path=':/plugins/RuimtelijkePlannen/help.png',
                        text=self.tr(u'Help'),
                        callback=self.open_help,
                        parent=self.iface.mainWindow(),
                        add_to_toolbar=False)

        self.add_action(dialog=None,
                        icon_path=':/plugins/RuimtelijkePlannen/settings.png',
                        text=self.tr(u'Settings'),
                        callback=self.run_settings,
                        parent=self.iface.mainWindow(),
                        add_to_toolbar=False)

        # add a button to click in map and find bestemmingsplannen
        self.action = self.add_action(
            dialog=None,
            icon_path=':/plugins/RuimtelijkePlannen/icon.png',
            text=self.tr(u'Click map query RuimtelijkePlannen'),
            callback=self.activate_tool,
            add_to_menu=True,
            status_tip=self.tr(u'Click map query RuimtelijkePlannen'),
            parent=self.iface.mainWindow())
        self.action.setCheckable(True)
        # add it to the same group as the pan/zoom tools
        self.iface.actionPan().actionGroup().addAction(self.action)
        self.xytool = GetPointTool(self.mapcanvas, self.getRPplannenByPoint)

        self.toolbarSearch = QLineEdit()
        self.toolbarSearch.setMaximumWidth(200)
        self.toolbarSearch.setAlignment(QtCore.Qt.AlignLeft)
        self.toolbarSearch.setPlaceholderText("NL.IMRO.")
        self.toolbar.addWidget(self.toolbarSearch)
        self.toolbarSearch.returnPressed.connect(self.addRPplanFromToolbar)

        self.proxyModel = QSortFilterProxyModel()
        self.sourceModel = QStandardItemModel()
        self.proxyModel.setSourceModel(self.sourceModel)

        self.dlg.treeView_results.setModel(self.proxyModel)
        self.dlg.treeView_results.setEditTriggers(
            QAbstractItemView.NoEditTriggers)
        self.dlg.treeView_results.setSortingEnabled(True)
        self.dlg.treeView_results.doubleClicked.connect(self.loadRPplan)

        # have an info icon at hand for keuzehulp
        self.infoIcon = QIcon(':/plugins/RuimtelijkePlannen/info.png')

        # have the right crs at hand
        self.rp_crs = QgsCoordinateReferenceSystem(28992)

        ## urls to RuimtelijkePlannen
        ## this one is the traditional one
        # self.rp_search_url = "https://www.ruimtelijkeplannen.nl/web-roo/rest/search"
        # self.rp_search_id_resource = "/plan/id/"
        # self.rp_search_xy_resource = "/plannen/xy/"
        ## this one is new and has more metadata with the "keuzehulp"!
        self.rp_search_url = "https://www.ruimtelijkeplannen.nl/plannenservice"
        self.rp_search_id_resource = "/plannen/identificatie/"
        self.rp_search_xy_resource = "/plannen/xy/"

        self.rp_wfs_url = "https://afnemers.ruimtelijkeplannen.nl/afnemers2012/services"

        # the following lists of plantypes comes from:
        # https://www.ruimtelijkeplannen.nl/viewer/planoverzicht
        self.rp_supported_planTypes = [\
            'aanwijzingsbesluit',
            'beheersverordening',
            'bestemmingsplan',
            'exploitatieplan',
            'gemeentelijk plan; bestemmingsplan artikel 10',
            'gemeentelijk plan; uitwerkingsplan artikel 11',
            'gemeentelijk plan; voorbereidingsbesluit',
            'gemeentelijk plan; wijzigingsplan artikel 11',
            'gemeentelijke visie; overig',
            'gerechtelijke uitspraak',
            'inpassingsplan',
            'omgevingsvergunning',
            'projectbesluit',
            'reactieve aanwijzing',
            'tijdelijke ontheffing buitenplans',
            'uitwerkingsplan',
            'voorbereidingsbesluit',
            'wijzigingsplan'
            ]
        self.rp_not_supported_plantypes = [\
            # these are the plan types which can have multiple maps

            'amvb',
            'provinciale verordening',
            'regeling',
            'structuurvisie'
            ]

        # layer action on RuimtelijkePlannen layers to show links to text
        self.rp_layer_action = QgsAction(QgsAction.GenericPython,
                                         'Open text link(s) in browser ',
                                         layer_action, "", False, "",
                                         {'Feature', 'Canvas'})

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginWebMenu(self.tr(u'&Ruimtelijke Plannen'),
                                           action)
            self.iface.removeToolBarIcon(action)
        del self.toolbar

    def open_help(self):
        '''
        Method to open the help pages
        '''

        QDesktopServices().openUrl(
            QUrl.fromLocalFile(
                os.path.join("file://", self.plugin_dir, 'help/build/html',
                             'index.html')))

    def run_settings(self):
        '''
        method showing the settings dialog and act on the results
        '''

        # we do this on opening this setting, so the user can easily add
        # new styles wthout reloading the plugin.
        available_styles = next(os.walk(self.available_styles_folder))[1]
        self.settings_dlg.styleComboBox.clear()
        self.settings_dlg.styleComboBox.addItems(available_styles)

        index = self.settings_dlg.styleComboBox.findText(self.map_style)
        self.settings_dlg.styleComboBox.setCurrentIndex(index)

        self.settings_dlg.show()
        result = self.settings_dlg.exec_()
        if result:
            map_style_folder = os.path.join(
                self.available_styles_folder,
                self.settings_dlg.styleComboBox.currentText())
            if os.path.isdir(map_style_folder):
                self.map_style = self.settings_dlg.styleComboBox.currentText()
                self.map_style_folder = os.path.join(
                    self.available_styles_folder, self.map_style)
                self.settings.setValue("RuimtelijkePlannen/map_style",
                                       self.map_style)
            else:
                self.iface.messageBar().pushMessage(
                    'Warning',
                    self.
                    tr(u"Selected style folder not found. See message log for details."
                       ),
                    level=Qgis.Warning)
                QgsMessageLog.logMessage(u'Style folder not found: ' + \
                    os.path.join(self.available_styles_folder, self.map_style),
                    'RuimtelijkePlannen')

    def activate_tool(self):
        self.mapcanvas.setMapTool(self.xytool)

    def addRPplanFromToolbar(self):
        '''slot for toolbarSearch'''
        self.addFromIdn(self.toolbarSearch.text())

    def addFromIdn(self, search_string):
        '''adds plan from idn'''
        self.toolbarSearch.clear()
        url = self.rp_search_url + self.rp_search_id_resource + search_string
        QgsMessageLog.logMessage(u'Query: ' + str(url), 'RuimtelijkePlannen')
        QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        (response, content) = self.nam.request(url)
        self.rp = json.loads(content.decode("utf-8"))

        QApplication.restoreOverrideCursor()
        if "ErrorType" in self.rp \
        or ('aantal' in self.rp and self.rp['aantal'] == 0):
            self.iface.messageBar().pushMessage("Error",
                                                self.tr(u'Plan not found.'),
                                                level=Qgis.Critical)
            return
        if 'resultaat' in self.rp:
            # we are using the keuzeHulp
            self.rp = self.rp['plannen'][0]
        if not self.rp["typePlan"] in self.rp_supported_planTypes:
            self.iface.messageBar().pushMessage(
                "Error",
                self.tr(u'Plan type not supported.'),
                level=Qgis.Critical)
        else:
            self.addRPplan_WFS(plangebied=search_string,
                               plantype=self.rp["typePlan"])

    def getWfsLayer(self, service, typename, wfs_filter):
        params = {
            'service': 'WFS',
            'version': '1.1.0',
            'request': 'GetFeature',
            'typename': typename,
            'filter': wfs_filter,
            'srsname': 'EPSG:28992',
        }
        if not service[-1] == '?':
            service += '?'
        uri = service + urllib.parse.unquote(urllib.parse.urlencode(params))
        layername = typename
        vlayer = QgsVectorLayer(uri, layername, "WFS")
        return vlayer

    def addRPplan_WFS(self, plangebied, plantype):
        '''adds a plan as a WFS layer'''

        QgsMessageLog.logMessage(u'Adding plan with IDN "%s" and plantype "%s"'\
            % (plangebied,plantype), 'RuimtelijkePlannen')

        # add a layergroup to insert the layers in
        bpGroup = QgsProject.instance().layerTreeRoot().insertGroup(
            0, plangebied)

        service = self.rp_wfs_url
        wfs_filter = '"plangebied"=\'' + plangebied + '\''
        plan = rp_plan(plantype)
        for layer in plan.layers:
            vlayer = self.getWfsLayer(service, layer['name'], wfs_filter)
            if vlayer.isValid():
                if 'qml' in layer:
                    layerQml = os.path.join(self.map_style_folder,
                                            layer['qml'])
                    if os.path.exists(layerQml):
                        vlayer.loadNamedStyle(layerQml)
                    else:
                        self.iface.messageBar().pushMessage(
                            'Warning',
                            self.
                            tr(u"Style not found. See message log for details."
                               ),
                            level=Qgis.Warning)
                        QgsMessageLog.logMessage(u'Style file not found: ' + \
                            str(layerQml), 'RuimtelijkePlannen')
                if layer['text_action']:
                    vlayer.actions().addAction(self.rp_layer_action)
                self.project.addMapLayer(vlayer, False)
                bpGroup.insertChildNode(-1, QgsLayerTreeLayer(vlayer))
            else:
                self.iface.messageBar().pushMessage(
                    'Warning',
                    self.tr(u"Invalid layer: ") + layer['name'],
                    level=Qgis.Warning)

        vlayer.selectAll()
        canvas = self.iface.mapCanvas()
        canvas.zoomToSelected(vlayer)
        vlayer.removeSelection()

    def loadRPplan(self, index):
        '''slot for row in search results widget'''
        self.dlg.hide()
        self.addRPplan_WFS(plangebied=index.sibling(index.row(), 1).data(),
                           plantype=index.sibling(index.row(), 3).data())

    def addSourceRow(self, nr, plan, keuze_hulp=None):
        '''adds plan to search results widget'''
        if plan["typePlan"] in self.rp_supported_planTypes:
            nr = QStandardItem(str(nr + 1))
            planId = QStandardItem(plan["identificatie"])
            if keuze_hulp:
                planStatus = QStandardItem(self.infoIcon, plan["planStatus"])
                f = planStatus.font()
                f.setUnderline(True)
                planStatus.setFont(f)
                planStatus.setToolTip(
                    '%s: %s' %
                    (keuze_hulp["positieTekst"], keuze_hulp["keuzeHulpTekst"]))
            else:
                planStatus = QStandardItem(plan["planStatus"])
            planNaam = QStandardItem(plan["naam"])
            planType = QStandardItem(plan["typePlan"])
            #planGebiedType = QStandardItem(plan["planGebiedType"])
            # not yet(?) in use by this plugin
            self.sourceModel.appendRow(
                [nr, planId, planStatus, planType, planNaam])

    def addSourceRowFromKeuzeHulp(self, nr, plan_en_keuze):
        '''adds plan to search results widget'''
        keuze_hulp = plan_en_keuze['keuzeHulp']
        plan = plan_en_keuze['planDto']

        self.addSourceRow(nr, plan, keuze_hulp)

    def getRPplannenByPoint(self, event):
        '''Queries ruimtelijkeplannen by point and shows results on widget.'''

        xform = QgsCoordinateTransform(
            self.mapcanvas.mapSettings().destinationCrs(), self.rp_crs,
            QgsProject.instance())
        xy = xform.transform(
            QgsPointXY(
                self.mapcanvas.getCoordinateTransform().toMapCoordinates(
                    event.pos().x(),
                    event.pos().y())))

        self.sourceModel.clear()
        url = self.rp_search_url + self.rp_search_xy_resource + str(
            xy.x()) + "/" + str(xy.y())
        QgsMessageLog.logMessage(u'Query: ' + str(url), 'RuimtelijkePlannen')

        QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        (response, content) = self.nam.request(url)
        self.rp = json.loads(content.decode("utf-8"))

        if "ErrorType" in self.rp:
            self.iface.messageBar().pushMessage("Error",
                                                self.tr(u'No Plans found.') +
                                                self.rp["ErrorDescription"],
                                                level=Qgis.Critical)
            QApplication.restoreOverrideCursor()
            return

        if 'plannen' in self.rp:
            for nr, plan in enumerate(self.rp["plannen"]):
                self.addSourceRow(nr, plan)
        else:
            for nr, plan_en_keuze in enumerate(self.rp["keuzeHulpPlannen"]):
                self.addSourceRowFromKeuzeHulp(nr, plan_en_keuze)

        if not self.sourceModel.rowCount():
            QApplication.restoreOverrideCursor()
            return

        self.sourceModel.setHeaderData(0, QtCore.Qt.Horizontal, "Nr")
        self.sourceModel.setHeaderData(1, QtCore.Qt.Horizontal,
                                       "Identification")
        self.sourceModel.horizontalHeaderItem(1).setTextAlignment(
            QtCore.Qt.AlignLeft)
        self.sourceModel.setHeaderData(2, QtCore.Qt.Horizontal, "Status")
        self.sourceModel.setHeaderData(3, QtCore.Qt.Horizontal, "Type")
        self.sourceModel.setHeaderData(4, QtCore.Qt.Horizontal, "Name")
        self.dlg.treeView_results.setColumnHidden(0, True)
        self.dlg.treeView_results.resizeColumnsToContents()
        self.dlg.treeView_results.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)
        self.dlg.treeView_results.setSelectionMode(1)
        self.dlg.treeView_results.selectRow(0)
        # sort on order of the keuzehulp, instead of status.
        #self.dlg.treeView_results.sortByColumn(2, QtCore.Qt.AscendingOrder)
        self.dlg.treeView_results.sortByColumn(0, QtCore.Qt.AscendingOrder)
        QApplication.restoreOverrideCursor()
        self.dlg.show()
Esempio n. 15
0
class STRViewEntityWidget(WIDGET2, BASE2, EntitySearchItem):
    """
    A widget that represents options for searching through an entity.
    """
    asyncStarted = pyqtSignal()
    asyncFinished = pyqtSignal()

    def __init__(self, config, formatter=None, parent=None):
        QWidget.__init__(self, parent)
        EntitySearchItem.__init__(self, formatter)
        self.setupUi(self)

        self.tbSTRViewEntity.setTabIcon(0, GuiUtils.get_icon('filter.png'))
        self.tbSTRViewEntity.setTabIcon(1,
                                        GuiUtils.get_icon('period_blue.png'))

        self.config = config
        self.setConfigOptions()
        self.curr_profile = current_profile()
        self.social_tenure = self.curr_profile.social_tenure
        self.str_model = entity_model(self.social_tenure)
        # Model for storing display and actual mapping values
        self._completer_model = None
        self._proxy_completer_model = None

        # Hook up signals
        self.cboFilterCol.currentIndexChanged.connect(
            self._on_column_index_changed)
        self.init_validity_dates()
        self.validity_from_date.dateChanged.connect(self.set_minimum_to_date)
        self.validity.setDisabled(True)
        self.init_validity_checkbox()

    def init_validity_checkbox(self):
        self.check_box_list = []
        self.validity_checkbox = QCheckBox()

        self.check_box_list.append(self.validity_checkbox)
        self.tbSTRViewEntity.tabBar().setTabButton(
            self.tbSTRViewEntity.tabBar().count() - 1, QTabBar.LeftSide,
            self.validity_checkbox)
        self.validity_checkbox.stateChanged.connect(
            self.toggle_validity_period)

    def toggle_validity_period(self, state):
        if state == Qt.Checked:
            self.validity.setDisabled(False)
        else:
            self.validity.setDisabled(True)

    def set_minimum_to_date(self):
        """
        Set the minimum to date based on the
        change in value of from date.
        :return:
        :rtype:
        """
        self.validity_to_date.setMinimumDate(self.validity_from_date.date())

    def init_validity_dates(self):
        """
        Initialize the dates by setting the current date.
        :return:
        :rtype:
        """
        self.validity_from_date.setDate(date.today())
        self.validity_to_date.setDate(date.today())

    def setConfigOptions(self):
        """
        Apply configuration options.
        """
        # Set filter columns and remove id column
        for col_name, display_name in self.config.filterColumns.items():
            if col_name != "id":
                self.cboFilterCol.addItem(display_name, col_name)

    def loadAsync(self):
        """
        Asynchronously loads an entity's attribute values.
        """
        self.asyncStarted.emit()

        # Create model worker
        workerThread = QThread(self)
        modelWorker = ModelWorker()
        modelWorker.moveToThread(workerThread)

        # Connect signals
        modelWorker.error.connect(self.errorHandler)
        workerThread.started.connect(lambda: modelWorker.fetch(
            self.config.STRModel, self.currentFieldName()))
        modelWorker.retrieved.connect(self._asyncFinished)
        modelWorker.retrieved.connect(workerThread.quit)
        workerThread.finished.connect(modelWorker.deleteLater)
        workerThread.finished.connect(workerThread.deleteLater)

        # Start thread
        workerThread.start()

    def validate(self):
        """
        Validate entity search widget
        """
        is_valid = True
        message = ""

        if self.txtFilterPattern.text() == "":
            message = QApplication.translate("ViewSTR",
                                             "Search word cannot be empty.")
            is_valid = False

        return is_valid, message

    def executeSearch(self):
        """
        Base class override.
        Search for matching items for the specified entity and column.
        """
        model_root_node = None

        prog_dialog = QProgressDialog(self)
        prog_dialog.setFixedWidth(380)
        prog_dialog.setWindowTitle(
            QApplication.translate("STRViewEntityWidget",
                                   "Searching for STR..."))
        prog_dialog.show()
        prog_dialog.setRange(0, 10)
        search_term = self._searchTerm()

        prog_dialog.setValue(2)
        # Try to get the corresponding search term value from the completer model
        if not self._completer_model is None:
            reg_exp = QRegExp("^%s$" % (search_term), Qt.CaseInsensitive,
                              QRegExp.RegExp2)
            self._proxy_completer_model.setFilterRegExp(reg_exp)

            if self._proxy_completer_model.rowCount() > 0:
                # Get corresponding actual value from the first matching item
                value_model_idx = self._proxy_completer_model.index(0, 1)
                source_model_idx = self._proxy_completer_model.mapToSource(
                    value_model_idx)
                prog_dialog.setValue(4)
                search_term = self._completer_model.data(
                    source_model_idx, Qt.DisplayRole)

        modelInstance = self.config.STRModel()

        modelQueryObj = modelInstance.queryObject()

        queryObjProperty = getattr(self.config.STRModel,
                                   self.currentFieldName())

        entity_name = modelQueryObj._primary_entity._label_name

        entity = self.curr_profile.entity_by_name(entity_name)

        prog_dialog.setValue(6)
        # Get property type so that the filter can
        # be applied according to the appropriate type
        propType = queryObjProperty.property.columns[0].type
        results = []
        try:
            if not isinstance(propType, String):

                col_name = self.currentFieldName()
                col = entity.columns[self.currentFieldName()]

                if col.TYPE_INFO == 'LOOKUP':
                    lookup_entity = lookup_parent_entity(
                        self.curr_profile, col_name)
                    lkp_model = entity_model(lookup_entity)
                    lkp_obj = lkp_model()
                    value_obj = getattr(lkp_model, 'value')

                    result = lkp_obj.queryObject().filter(
                        func.lower(value_obj) == func.lower(
                            search_term)).first()
                    if result is None:
                        result = lkp_obj.queryObject().filter(
                            func.lower(value_obj).like(search_term +
                                                       '%')).first()

                    if not result is None:
                        results = modelQueryObj.filter(
                            queryObjProperty == result.id).all()

                    else:
                        results = []

            else:
                results = modelQueryObj.filter(
                    func.lower(queryObjProperty) == func.lower(
                        search_term)).all()

            if self.validity.isEnabled():
                valid_str_ids = self.str_validity_period_filter(results)
            else:
                valid_str_ids = None

            prog_dialog.setValue(7)
        except exc.StatementError:
            return model_root_node, [], search_term

        # if self.formatter is not None:
        # self.formatter.setData(results)
        # model_root_node = self.formatter.root(valid_str_ids)
        prog_dialog.setValue(10)
        prog_dialog.hide()

        return results, search_term

    def str_validity_period_filter(self, results):
        """
        Filter the entity results using validity period in STR table.
        :param results: Entity result
        :type results: SQLAlchemy result proxy
        :return: Valid list of STR ids
        :rtype: List
        """
        self.str_model_obj = self.str_model()
        valid_str_ids = []
        for result in results:
            from_date = self.validity_from_date.date().toPyDate()
            to_date = self.validity_to_date.date().toPyDate()
            entity_id = '{}_id'.format(result.__table__.name[3:])
            str_column_obj = getattr(self.str_model, entity_id)
            str_result = self.str_model_obj.queryObject().filter(
                self.str_model.validity_start >= from_date).filter(
                    self.str_model.validity_end <= to_date).filter(
                        str_column_obj == result.id).all()

            for res in str_result:
                valid_str_ids.append(res.id)

        return valid_str_ids

    def reset(self):
        """
        Clear search input parameters.
        """
        self.txtFilterPattern.clear()
        if self.cboFilterCol.count() > 0:
            self.cboFilterCol.setCurrentIndex(0)

    def currentFieldName(self):
        """
        Returns the name of the database field
        from the current item in the combo box.
        """
        curr_index = self.cboFilterCol.currentIndex()
        field_name = self.cboFilterCol.itemData(curr_index)

        if field_name is None:
            return
        else:
            return field_name

    def _searchTerm(self):
        """
        Returns the search term specified by the user.
        """
        return self.txtFilterPattern.text()

    def _asyncFinished(self, model_values):
        """
        Slot raised when worker has finished retrieving items.
        """
        # Create QCompleter and add values to it.
        self._update_completer(model_values)
        self.asyncFinished.emit()

    def _update_completer(self, values):
        # Get the items in a tuple and put them in a list

        # Store display and actual values in a
        # model for easier mapping and
        # retrieval when carrying out searches

        model_attr_mapping = []

        # Check if there are formaters specified
        # for the current field name
        for mv in values:
            f_model_values = []

            m_val = mv[0]

            if m_val is not None:
                col_label = self.currentFieldName()
                if col_label in self.config.LookupFormatters:
                    formatter = self.config.LookupFormatters[col_label]
                    if formatter.column.TYPE_INFO == 'LOOKUP':
                        m_val = formatter.code_value(m_val)[0]
                    else:
                        m_val = formatter.format_column_value(m_val)
            f_model_values.extend([m_val, m_val])

            model_attr_mapping.append(f_model_values)

        self._completer_model = BaseSTDMTableModel(model_attr_mapping,
                                                   ["", ""], self)

        # We will use the QSortFilterProxyModel for filtering purposes
        self._proxy_completer_model = QSortFilterProxyModel()
        self._proxy_completer_model.setDynamicSortFilter(True)
        self._proxy_completer_model.setSourceModel(self._completer_model)
        self._proxy_completer_model.setSortCaseSensitivity(Qt.CaseInsensitive)
        self._proxy_completer_model.setFilterKeyColumn(0)

        # Configure completer
        mod_completer = QCompleter(self._completer_model, self)
        mod_completer.setCaseSensitivity(Qt.CaseInsensitive)
        mod_completer.setCompletionMode(QCompleter.PopupCompletion)
        mod_completer.setCompletionColumn(0)
        mod_completer.setCompletionRole(Qt.DisplayRole)

        self.txtFilterPattern.setCompleter(mod_completer)

    def _on_column_index_changed(self, int):
        """
        Slot raised when the user selects a different filter column.
        """
        self.txtFilterPattern.clear()
        self.loadAsync()
Esempio n. 16
0
class DlgDownload(DlgCalculateBase, Ui_DlgDownload):
    def __init__(self, parent=None):
        """Constructor."""
        super(DlgDownload, self).__init__(parent)

        # Allow the download tool to support data downloads of any size (in 
        # terms of area)
        self._max_area = 1e10

        self.settings = QSettings()

        self.setupUi(self)

        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'data', 'gee_datasets.json')) as f:
            data_dict = json.load(f)

        self.datasets = []
        for cat in list(data_dict.keys()):
            for title in list(data_dict[cat].keys()):
                item = data_dict[cat][title]
                item.update({'category': cat, 'title': title})
                min_x = item.get('Min Longitude', None)
                max_x = item.get('Max Longitude', None)
                min_y = item.get('Min Latitude', None)
                max_y = item.get('Max Latitude', None)
                if not None in (min_x, max_x, min_y, max_y):
                    extent_lat = '{} - {}'.format(min_y, max_y)
                    extent_lon = '{} - {}'.format(min_x, max_x)
                    item.update({'extent_lat': extent_lat,
                                 'extent_lon': extent_lon})
                self.datasets.append(item)

        self.update_data_table()

        self.data_view.selectionModel().selectionChanged.connect(self.selection_changed)

        self.data_view.viewport().installEventFilter(tool_tipper(self.data_view))

    def selection_changed(self):
        if self.data_view.selectedIndexes():
            # Note there can only be one row selected at a time by default
            row = list(set(index.row() for index in self.data_view.selectedIndexes()))[0]
            first_year = self.datasets[row]['Start year']
            last_year = self.datasets[row]['End year']
            if (first_year == 'NA') or (last_year == 'NA'):
                self.first_year.setEnabled(False)
                self.last_year.setEnabled(False)
            else:
                self.first_year.setEnabled(True)
                self.last_year.setEnabled(True)
                first_year = QDate(first_year, 12, 31)
                last_year = QDate(last_year, 12, 31)
                self.first_year.setMinimumDate(first_year)
                self.first_year.setMaximumDate(last_year)
                self.last_year.setMinimumDate(first_year)
                self.last_year.setMaximumDate(last_year)

    def tab_changed(self):
        super(DlgDownload, self).tab_changed()
        if (self.TabBox.currentIndex() == (self.TabBox.count() - 1)) \
                and not self.data_view.selectedIndexes():
            # Only enable download if a dataset is selected
            self.button_calculate.setEnabled(False)

    def firstShow(self):
        super(DlgDownload, self).firstShow()
        # Don't show the time selector for now
        self.TabBox.removeTab(1)

    def showEvent(self, event):
        super(DlgDownload, self).showEvent(event)

        # Don't local/cloud selector for this dialog
        self.options_tab.toggle_show_where_to_run(False)

    def update_data_table(self):
        table_model = DataTableModel(self.datasets, self)
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(table_model)
        self.data_view.setModel(self.proxy_model)

        # Add "Notes" buttons in cell
        for row in range(0, len(self.datasets)):
            btn = QtWidgets.QPushButton(self.tr("Details"))
            btn.clicked.connect(self.btn_details)
            self.data_view.setIndexWidget(self.proxy_model.index(row, 8), btn)

        self.data_view.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        self.data_view.horizontalHeader().setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        self.data_view.horizontalHeader().setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        self.data_view.horizontalHeader().setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
        self.data_view.horizontalHeader().setSectionResizeMode(4, QtWidgets.QHeaderView.ResizeToContents)
        self.data_view.horizontalHeader().setSectionResizeMode(5, QtWidgets.QHeaderView.ResizeToContents)
        self.data_view.horizontalHeader().setSectionResizeMode(6, QtWidgets.QHeaderView.ResizeToContents)
        self.data_view.horizontalHeader().setSectionResizeMode(7, QtWidgets.QHeaderView.ResizeToContents)
        self.data_view.horizontalHeader().setSectionResizeMode(8, QtWidgets.QHeaderView.ResizeToContents)

        self.data_view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)

    def btn_details(self):
        button = self.sender()
        index = self.data_view.indexAt(button.pos())
        #TODO: Code the details view

    def btn_calculate(self):
        # Note that the super class has several tests in it - if they fail it
        # returns False, which would mean this function should stop execution
        # as well.
        ret = super(DlgDownload, self).btn_calculate()
        if not ret:
            return

        rows = list(set(index.row() for index in self.data_view.selectedIndexes()))
        # Construct unique dataset names as the concatenation of the category 
        # and the title
        selected_names = [self.proxy_model.index(row, 0).data() + self.proxy_model.index(row, 1).data()for row in rows]
        selected_datasets = [d for d in self.datasets if d['category'] + d['title'] in selected_names]

        self.close()

        crosses_180th, geojsons = self.gee_bounding_box
        for dataset in selected_datasets:
            payload = {'geojsons': json.dumps(geojsons),
                       'crs': self.aoi.get_crs_dst_wkt(),
                       'year_start': self.first_year.date().year(),
                       'year_end': self.last_year.date().year(),
                       'crosses_180th': crosses_180th,
                       'asset': dataset['GEE Dataset'],
                       'name': dataset['title'],
                       'temporal_resolution': dataset['Temporal resolution'],
                       'task_name': self.options_tab.task_name.text(),
                       'task_notes': self.options_tab.task_notes.toPlainText()}

            resp = run_script(get_script_slug('download-data'), payload)

            if resp:
                mb.pushMessage(self.tr("Success"),
                               self.tr("Download request submitted to Google Earth Engine."),
                               level=0, duration=5)
            else:
                mb.pushMessage(self.tr("Error"),
                               self.tr("Unable to submit download request to Google Earth Engine."),
                               level=0, duration=5)
Esempio n. 17
0
 def makeProxyModel(self, model):
     proxyModel = QSortFilterProxyModel()
     proxyModel.setDynamicSortFilter(True)
     proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive)
     proxyModel.setSourceModel(model)
     return proxyModel
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)
Esempio n. 19
0
class ExtendedCombobox(QComboBox):
    """
    Overwrite combobox to provide text filtering of
    combobox list.
    """

    def __init__(self, parent):
        """
        Initialise  ExtendedCombobox

        :param parent: Parent of combobox
        :type parent: PyQt5.QtWidgets.QWidget
        """

        super().__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)
        self.completer = QCompleter(self)

        # always show all completions
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.p_filter_model = QSortFilterProxyModel(self)
        self.p_filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setPopup(self.view())
        self.setCompleter(self.completer)
        self.lineEdit().textEdited.connect(self.p_filter_model.setFilterFixedString)
        self.completer.activated.connect(self.setTextIfCompleterIsClicked)

    def setModel(self, model):  # pylint:disable=invalid-name
        """
        Set the model to use the Filter model

        :param model: The model to be used by the combobox
        :type model: PyQt5.QtGui.QStandardItemModel
        """

        super().setModel(model)
        self.p_filter_model.setSourceModel(model)
        self.completer.setModel(self.p_filter_model)

    def setModelColumn(self, column):  # pylint:disable=invalid-name
        """
        :param model: The model to be used by the combobox
        :type model: PyQt5.QtGui.QStandardItemModel
        """

        self.completer.setCompletionColumn(column)
        self.p_filter_model.setFilterKeyColumn(column)
        super().setModelColumn(column)

    def view(self):
        """
        A QListView of items stored in the model

        :return: items stored in the model
        :rtype: PyQt5.QtWidgets.QListView
        """

        return self.completer.popup()

    def index(self):
        """
        Index of the current item in the combobox.

        :return: index of the current item
        :rtype: int
        """

        return self.currentIndex()

    def setTextIfCompleterIsClicked(self, text):  # pylint:disable=invalid-name
        """
        :param text: The current text of the qlineedit
        :type text: str

        If the combobx lineedit is clicked, set the lineedits
        current item as the combobox's current item
        """

        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)
Esempio n. 20
0
class DlgJobs(QtWidgets.QDialog, Ui_DlgJobs):
    # When a connection to the api starts, emit true. When it ends, emit False
    connectionEvent = pyqtSignal(bool)

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

        self.setupUi(self)

        self.connection_in_progress = False

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

        self.refresh.clicked.connect(self.btn_refresh)
        self.download.clicked.connect(self.btn_download)

        self.connectionEvent.connect(self.connection_event_changed)

        # Only enable download button if a job is selected
        self.download.setEnabled(False)

        self.jobs_view.viewport().installEventFilter(
            tool_tipper(self.jobs_view))

    def showEvent(self, event):
        super(DlgJobs, self).showEvent(event)

        #######################################################################
        #######################################################################
        # Hack to download multiple countries at once for workshop preparation
        #######################################################################
        #######################################################################
        # from qgis.PyQt.QtCore import QTimer, Qt
        # from qgis.PyQt.QtWidgets import QMessageBox, QApplication
        # from qgis.PyQt.QtTest import QTest
        # from time import sleep
        #
        # self.btn_refresh()
        #
        # search_string = '_TE_Land_Productivity'
        #
        # # Ensure any message boxes that open are closed within 1 second
        # def close_msg_boxes():
        #     for w in QApplication.topLevelWidgets():
        #         if isinstance(w, QMessageBox):
        #             print('Closing message box')
        #             QTest.keyClick(w, Qt.Key_Enter)
        # timer = QTimer()
        # timer.timeout.connect(close_msg_boxes)
        # timer.start(1000)
        # jobs = [job for job in self.jobs if job['status'] == 'FINISHED' and \
        #                                     job['results']['type'] == 'CloudResults' and \
        #                                     re.search(search_string, job['task_name'])]
        # for job in jobs:
        #     name = job['task_name']
        #     country = name.replace(search_string, '')
        #     out_file = os.path.join(u'H:/Data/Trends.Earth/USB Stick Data/Trends.Earth_Data', country, u'{}.json'.format(name))
        #     #out_file = os.path.join(u'C:/Users/azvol/Desktop/TE_Indicators_For_USB', country, u'{}.json'.format(name))
        #     if not os.path.exists(out_file):
        #         if not os.path.exists(os.path.dirname(out_file)):
        #             os.makedirs(os.path.dirname(out_file))
        #         log(u'Downloading {} to {}'.format(name, out_file))
        #         download_cloud_results(job,
        #                                os.path.splitext(out_file)[0],
        #                                self.tr,
        #                                add_to_map=False)
        #         sleep(2)
        #######################################################################
        #######################################################################
        # End hack
        #######################################################################
        #######################################################################

        try:
            jobs_cache = json.loads(QSettings().value("LDMP/jobs_cache", '{}'))
        except TypeError:
            # For backward compatibility need to handle case of jobs caches
            # that were stored inappropriately in past version of Trends.Earth
            jobs_cache = {}
        if jobs_cache is not {}:
            self.jobs = jobs_cache
            self.update_jobs_table()

    def connection_event_changed(self, flag):
        if flag:
            self.connection_in_progress = True
            self.download.setEnabled(False)
            self.refresh.setEnabled(False)
        else:
            self.connection_in_progress = False
            # Enable the download button if there is a selection
            self.selection_changed()
            self.refresh.setEnabled(True)

    def selection_changed(self):
        if self.connection_in_progress:
            return
        elif not self.jobs_view.selectedIndexes():
            self.download.setEnabled(False)
        else:
            rows = set(
                list(index.row()
                     for index in self.jobs_view.selectedIndexes()))
            job_ids = [self.proxy_model.index(row, 4).data() for row in rows]
            statuses = [
                job.get('status', None) for job in self.jobs
                if job.get('id', None) in job_ids
            ]

            if len(statuses) > 0:
                for status in statuses:
                    # Don't set button to enabled if any of the tasks aren't
                    # yet finished, or if any are invalid
                    if status != 'FINISHED':
                        self.download.setEnabled(False)
                        return
                self.download.setEnabled(True)

    def btn_refresh(self):
        self.connectionEvent.emit(True)
        email = get_user_email()
        if email:
            start_date = datetime.datetime.now() + datetime.timedelta(-14)
            jobs = get_execution(date=start_date.strftime('%Y-%m-%d'))
            if jobs:
                self.jobs = jobs
                # Add script names and descriptions to jobs list
                for job in self.jobs:
                    # self.jobs will have prettified data for usage in table,
                    # so save a backup of the original data under key 'raw'
                    job['raw'] = job.copy()
                    script = job.get('script_id', None)
                    if script:
                        job['script_name'] = job['script']['name']
                        # Clean up the script name so the version tag doesn't
                        # look so odd
                        job['script_name'] = re.sub(r'([0-9]+(_[0-9]+)+)$',
                                                    r'(v\g<1>)',
                                                    job['script_name'])
                        job['script_name'] = job['script_name'].replace(
                            '_', '.')
                        job['script_description'] = job['script'][
                            'description']
                    else:
                        # Handle case of scripts that have been removed or that are
                        # no longer supported
                        job['script_name'] = self.tr('Script not found')
                        job['script_description'] = self.tr('Script not found')

                # Pretty print dates and pull the metadata sent as input params
                for job in self.jobs:
                    job['start_date'] = datetime.datetime.strftime(
                        job['start_date'], '%Y/%m/%d (%H:%M)')
                    job['end_date'] = datetime.datetime.strftime(
                        job['end_date'], '%Y/%m/%d (%H:%M)')
                    job['task_name'] = job['params'].get('task_name', '')
                    job['task_notes'] = job['params'].get('task_notes', '')
                    job['params'] = job['params']

                # Cache jobs for later reuse
                QSettings().setValue(
                    "LDMP/jobs_cache",
                    json.dumps(self.jobs, default=json_serial))

                self.update_jobs_table()
                self.connectionEvent.emit(False)
                return True

        self.connectionEvent.emit(False)
        return False

    def update_jobs_table(self):
        if self.jobs:
            table_model = JobsTableModel(self.jobs, self)
            self.proxy_model = QSortFilterProxyModel()
            self.proxy_model.setSourceModel(table_model)
            self.jobs_view.setModel(self.proxy_model)
            # Add "Details" buttons in cell
            for row in range(0, len(self.jobs)):
                btn = QtWidgets.QPushButton(self.tr("Details"))
                btn.clicked.connect(self.btn_details)
                self.jobs_view.setIndexWidget(self.proxy_model.index(row, 6),
                                              btn)

            self.jobs_view.horizontalHeader().setSectionResizeMode(
                0, QtWidgets.QHeaderView.Stretch)
            self.jobs_view.horizontalHeader().setSectionResizeMode(
                1, QtWidgets.QHeaderView.Stretch)
            self.jobs_view.horizontalHeader().setSectionResizeMode(
                2, QtWidgets.QHeaderView.ResizeToContents)
            self.jobs_view.horizontalHeader().setSectionResizeMode(
                3, QtWidgets.QHeaderView.ResizeToContents)
            self.jobs_view.horizontalHeader().setSectionResizeMode(
                4, QtWidgets.QHeaderView.Fixed)
            self.jobs_view.horizontalHeader().setSectionResizeMode(
                5, QtWidgets.QHeaderView.ResizeToContents)
            self.jobs_view.horizontalHeader().setSectionResizeMode(
                6, QtWidgets.QHeaderView.ResizeToContents)

            self.jobs_view.selectionModel().selectionChanged.connect(
                self.selection_changed)

    def btn_details(self):
        button = self.sender()
        index = self.jobs_view.indexAt(button.pos())

        details_dlg = DlgJobsDetails(self)

        job = self.jobs[index.row()]

        details_dlg.task_name.setText(job.get('task_name', ''))
        details_dlg.task_status.setText(job.get('status', ''))
        details_dlg.comments.setText(job.get('task_notes', ''))
        details_dlg.input.setText(
            json.dumps(job.get('params', ''), indent=4, sort_keys=True))
        details_dlg.output.setText(
            json.dumps(job.get('results', ''), indent=4, sort_keys=True))

        details_dlg.show()
        details_dlg.exec_()

    def btn_download(self):
        # Use set below in case multiple cells within the same row are selected
        rows = set(
            list(index.row() for index in self.jobs_view.selectedIndexes()))
        job_ids = [self.proxy_model.index(row, 4).data() for row in rows]
        jobs = [job for job in self.jobs if job['id'] in job_ids]

        filenames = []
        for job in jobs:
            # Check if we need a download filename - some tasks don't need to
            # save data, but if any of the chosen tasks do, then we need to
            # choose a folder. Right now only TimeSeriesTable doesn't need a
            # filename.
            if job['results'].get('type') != 'TimeSeriesTable':
                f = None
                while not f:
                    # Setup a string to use in filename window
                    if job['task_name']:
                        job_info = u'{} ({})'.format(job['script_name'],
                                                     job['task_name'])
                    else:
                        job_info = job['script_name']
                    f, _ = QtWidgets.QFileDialog.getSaveFileName(
                        self,
                        self.tr(
                            u'Choose a filename. Downloading results of: {}'.
                            format(job_info)),
                        QSettings().value("LDMP/output_dir", None),
                        self.tr('Base filename (*.json)'))

                    # Strip the extension so that it is a basename
                    f = os.path.splitext(f)[0]

                    if f:
                        if os.access(os.path.dirname(f), os.W_OK):
                            QSettings().setValue("LDMP/output_dir",
                                                 os.path.dirname(f))
                            log(u"Downloading results to {} with basename {}".
                                format(os.path.dirname(f),
                                       os.path.basename(f)))
                        else:
                            QtWidgets.QMessageBox.critical(
                                None, self.tr("Error"),
                                self.
                                tr(u"Cannot write to {}. Choose a different base filename."
                                   .format(f)))
                    else:
                        return False

                filenames.append(f)
            else:
                filenames.append(None)

        self.close()

        for row, f in zip(rows, filenames):
            job = self.jobs[row]
            log(u"Processing job {}.".format(job.get('id', None)))
            result_type = job['results'].get('type')
            if result_type == 'CloudResults':
                download_cloud_results(job, f, self.tr)
            elif result_type == 'TimeSeriesTable':
                download_timeseries(job, self.tr)
            else:
                raise ValueError(
                    "Unrecognized result type in download results: {}".format(
                        result_type))
Esempio n. 21
0
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
        runIcon = QIcon(os.path.join(self.plugin_dir, 'icon_add_service.svg'))
        self.run_action = QAction(runIcon, \
            "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
        eraserIcon = QIcon(
            os.path.join(self.plugin_dir, 'icon_remove_cross.svg'))
        self.clean_action = QAction(eraserIcon, \
            "Cleanup", self.eraseAddress())
        self.toolbar.addAction(self.clean_action)
        self.clean_action.triggered.connect(self.eraseAddress)
        self.clean_action.setEnabled(False)

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

        # about
        self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/icon_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("&Pdok Services Plugin", self.run_action)
        self.iface.removePluginMenu("&Pdok Services Plugin", self.aboutAction)
        del self.toolbarSearch
        del self.run_action
        del self.aboutAction

    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)
        self.clean_action.setEnabled(True)

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

    def info(self, msg=""):
        QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin',
                                 Qgis.Info)
Esempio n. 22
0
class SPAQLunicornDialog(QtWidgets.QDialog, FORM_CLASS):
    ## The triple store configuration file
    triplestoreconf = None
    ## Prefix map
    prefixes = None

    enrichtab = None

    interlinktab = None

    conceptList = None

    completerClassList = None

    columnvars = {}

    def __init__(self,
                 triplestoreconf={},
                 prefixes=[],
                 addVocabConf={},
                 autocomplete={},
                 prefixstore={
                     "normal": {},
                     "reversed": {}
                 },
                 savedQueriesJSON={},
                 maindlg=None,
                 parent=None):
        """Constructor."""
        super(SPAQLunicornDialog, self).__init__(parent)
        self.setupUi(self)
        self.prefixes = prefixes
        self.maindlg = maindlg
        self.savedQueriesJSON = savedQueriesJSON
        self.enrichtab = EnrichmentTab(self)
        self.interlinktab = InterlinkingTab(self)
        self.addVocabConf = addVocabConf
        self.autocomplete = autocomplete
        self.prefixstore = prefixstore
        self.triplestoreconf = triplestoreconf
        self.searchTripleStoreDialog = TripleStoreDialog(
            self.triplestoreconf, self.prefixes, self.prefixstore,
            self.comboBox)
        self.geoClassList.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.geoClassList.setAlternatingRowColors(True)
        self.geoClassList.setViewMode(QListView.ListMode)
        self.geoClassList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.geoClassList.customContextMenuRequested.connect(self.onContext)
        self.geoClassListModel = QStandardItemModel()
        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.sort(0)
        self.proxyModel.setSourceModel(self.geoClassListModel)
        self.geoClassList.setModel(self.proxyModel)
        self.geoClassListModel.clear()
        self.queryLimit.setValidator(QRegExpValidator(QRegExp("[0-9]*")))
        self.filterConcepts.textChanged.connect(self.setFilterFromText)
        self.inp_sparql2 = ToolTipPlainText(self.tab, self.triplestoreconf,
                                            self.comboBox, self.columnvars,
                                            self.prefixes, self.autocomplete)
        self.inp_sparql2.move(10, 130)
        self.inp_sparql2.setMinimumSize(780, 401)
        self.inp_sparql2.document().defaultFont().setPointSize(16)
        self.inp_sparql2.setPlainText(
            "SELECT ?item ?lat ?lon WHERE {\n ?item ?b ?c .\n ?item <http://www.wikidata.org/prop:P123> ?def .\n}"
        )
        self.inp_sparql2.columnvars = {}
        self.inp_sparql2.textChanged.connect(self.validateSPARQL)
        self.sparqlhighlight = SPARQLHighlighter(self.inp_sparql2)
        self.areaconcepts.hide()
        self.areas.hide()
        self.label_8.hide()
        self.label_9.hide()
        self.savedQueries.hide()
        self.loadQuery.hide()
        self.saveQueryButton.hide()
        self.saveQueryName.hide()
        self.savedQueryLabel.hide()
        self.saveQueryName_2.hide()
        self.enrichTableResult.hide()
        self.queryTemplates.currentIndexChanged.connect(self.viewselectaction)
        self.bboxButton.clicked.connect(self.getPointFromCanvas)
        self.interlinkTable.cellClicked.connect(
            self.createInterlinkSearchDialog)
        self.enrichTable.cellClicked.connect(self.createEnrichSearchDialog)
        self.chooseLayerInterlink.clear()
        self.searchClass.clicked.connect(self.createInterlinkSearchDialog)
        urlregex = QRegExp(
            "http[s]?://(?:[a-zA-Z#]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+"
        )
        urlvalidator = QRegExpValidator(urlregex, self)
        self.interlinkNameSpace.setValidator(urlvalidator)
        self.interlinkNameSpace.textChanged.connect(self.check_state3)
        self.interlinkNameSpace.textChanged.emit(
            self.interlinkNameSpace.text())
        self.addEnrichedLayerButton.clicked.connect(
            self.enrichtab.addEnrichedLayer)
        self.startEnrichment.clicked.connect(self.enrichtab.enrichLayerProcess)
        self.exportInterlink.clicked.connect(
            self.enrichtab.exportEnrichedLayer)
        self.loadQuery.clicked.connect(self.loadQueryFunc)
        self.saveQueryButton.clicked.connect(self.saveQueryFunc)
        self.exportMappingButton.clicked.connect(
            self.interlinktab.exportMapping)
        self.importMappingButton.clicked.connect(self.interlinktab.loadMapping)
        self.loadLayerInterlink.clicked.connect(self.loadLayerForInterlink)
        self.loadLayerEnrich.clicked.connect(self.loadLayerForEnrichment)
        self.addEnrichedLayerRowButton.clicked.connect(self.addEnrichRow)
        self.geoClassList.selectionModel().selectionChanged.connect(
            self.viewselectaction)
        self.loadFileButton.clicked.connect(self.buildLoadGraphDialog)
        self.refreshLayersInterlink.clicked.connect(self.loadUnicornLayers)
        self.btn_loadunicornlayers.clicked.connect(self.loadUnicornLayers)
        self.whattoenrich.clicked.connect(self.createWhatToEnrich)
        self.quickAddTripleStore.clicked.connect(self.buildQuickAddTripleStore)
        self.loadTripleStoreButton.clicked.connect(
            self.buildCustomTripleStoreDialog)
        self.loadUnicornLayers()

    def loadQueryFunc(self):
        if self.triplestoreconf[self.comboBox.currentIndex(
        )]["endpoint"] in self.savedQueriesJSON:
            self.inp_sparql2.setPlainText(self.savedQueriesJSON[
                self.triplestoreconf[self.comboBox.currentIndex()]
                ["endpoint"]][self.savedQueries.currentIndex()]["query"])

    def saveQueryFunc(self):
        queryName = self.saveQueryName.text()
        if queryName != None and queryName != "":
            __location__ = os.path.realpath(
                os.path.join(os.getcwd(), os.path.dirname(__file__)))
            self.savedQueriesJSON[self.triplestoreconf[
                self.comboBox.currentIndex()]["endpoint"]].append({
                    "label":
                    queryName,
                    "query":
                    self.inp_sparql2.toPlainText()
                })
            self.savedQueries.addItem(queryName)
            f = open(os.path.join(__location__, 'savedqueries.json'), "w")
            f.write(json.dumps(self.savedQueriesJSON))
            f.close()

    def onContext(self):
        menu = QMenu("Menu", self.geoClassList)
        action = QAction("Open in Webbrowser")
        menu.addAction(action)
        action.triggered.connect(self.openURL)

    def openURL(self):
        curindex = self.proxyModel.mapToSource(
            self.geoClassList.selectionModel().currentIndex())
        concept = self.geoClassListModel.itemFromIndex(curindex).data(1)
        url = QUrl(concept)
        QDesktopServices.openUrl(url)

    def setFilterFromText(self):
        self.proxyModel.setFilterRegExp(self.filterConcepts.text())

    ##
    #  @brief Creates a What To Enrich dialog with parameters given.
    #
    #  @param self The object pointer
    def buildLoadGraphDialog(self):
        self.searchTripleStoreDialog = LoadGraphDialog(self.triplestoreconf,
                                                       self.maindlg, self)
        self.searchTripleStoreDialog.setWindowTitle("Load Graph")
        self.searchTripleStoreDialog.exec_()

    ##
    #  @brief Creates a What To Enrich dialog with parameters given.
    #
    #  @param self The object pointer
    def buildQuickAddTripleStore(self):
        self.searchTripleStoreDialog = TripleStoreQuickAddDialog(
            self.triplestoreconf, self.prefixes, self.prefixstore,
            self.comboBox)
        self.searchTripleStoreDialog.setMinimumSize(580, 186)
        self.searchTripleStoreDialog.setWindowTitle(
            "Configure Own Triple Store")
        self.searchTripleStoreDialog.exec_()

    ##
    #  @brief Creates a What To Enrich dialog with parameters given.
    #
    #  @param self The object pointer
    def buildCustomTripleStoreDialog(self):
        self.searchTripleStoreDialog = TripleStoreDialog(
            self.triplestoreconf, self.prefixes, self.prefixstore,
            self.comboBox)
        self.searchTripleStoreDialog.setMinimumSize(700, 500)
        self.searchTripleStoreDialog.setWindowTitle(
            "Configure Own Triple Store")
        self.searchTripleStoreDialog.exec_()

    ##
    #  @brief Creates a What To Enrich dialog with parameters given.
    #
    #  @param self The object pointer
    def createWhatToEnrich(self):
        if self.enrichTable.rowCount() == 0:
            return
        layers = QgsProject.instance().layerTreeRoot().children()
        selectedLayerIndex = self.chooseLayerEnrich.currentIndex()
        layer = layers[selectedLayerIndex].layer()
        self.searchTripleStoreDialog = EnrichmentDialog(
            self.triplestoreconf, self.prefixes, self.enrichTable, layer, None,
            None)
        self.searchTripleStoreDialog.setMinimumSize(700, 500)
        self.searchTripleStoreDialog.setWindowTitle("Enrichment Search")
        self.searchTripleStoreDialog.exec_()

    def check_state3(self):
        self.searchTripleStoreDialog.check_state(self.interlinkNameSpace)

    def createEnrichSearchDialog(self, row=-1, column=-1):
        if column == 1:
            self.buildSearchDialog(row, column, False, self.enrichTable, False,
                                   False, None, self.addVocabConf)
        if column == 6:
            self.buildSearchDialog(row, column, False, self.enrichTable, False,
                                   False, None, self.addVocabConf)

    def createEnrichSearchDialogProp(self, row=-1, column=-1):
        self.buildSearchDialog(row, column, False, self.findIDPropertyEdit,
                               True, False, None, self.addVocabConf)

    ##
    #  @brief Creates a search dialog with parameters for interlinking.
    #
    #  @param self The object pointer
    #  @param row The row of the table for which to map the search result
    #  @param column The column of the table for which to map the search result
    def createInterlinkSearchDialog(self, row=-1, column=-1):
        if column > 3 and column < 7:
            self.buildSearchDialog(row, column, True, self.interlinkTable,
                                   True, False, None, self.addVocabConf)
        elif column >= 7:
            layers = QgsProject.instance().layerTreeRoot().children()
            selectedLayerIndex = self.chooseLayerInterlink.currentIndex()
            layer = layers[selectedLayerIndex].layer()
            self.buildValueMappingDialog(row, column, True,
                                         self.interlinkTable, layer)
        elif column == -1:
            self.buildSearchDialog(row, column, -1,
                                   self.interlinkOwlClassInput, False, False,
                                   None, self.addVocabConf)

    ##
    #  @brief Shows the configuration table after creating an enrichment result.
    #
    #  @param  self The object pointer
    #
    def showConfigTable(self):
        self.enrichTableResult.hide()
        self.enrichTable.show()
        self.startEnrichment.setText("Start Enrichment")
        self.startEnrichment.clicked.disconnect()
        self.startEnrichment.clicked.connect(self.enrichtab.enrichLayerProcess)

    ##
    #  @brief Executes a GUI event when a new SPARQL endpoint is selected.
    #  Usually loads the list of concepts related to the SPARQL endpoint
    #  @param  send The sender of the request
    #
    def viewselectaction(self):
        endpointIndex = self.comboBox.currentIndex()
        if endpointIndex == 0:
            self.justloadingfromfile = False
            return
        concept = ""
        curindex = self.proxyModel.mapToSource(
            self.geoClassList.selectionModel().currentIndex())
        if self.geoClassList.selectionModel().currentIndex(
        ) != None and self.geoClassListModel.itemFromIndex(
                curindex) != None and re.match(
                    r'.*Q[0-9]+.*',
                    self.geoClassListModel.itemFromIndex(curindex).text()
                ) and not self.geoClassListModel.itemFromIndex(
                    curindex).text().startswith("http"):
            self.inp_label.setText(
                self.geoClassListModel.itemFromIndex(curindex).text().split(
                    "(")[0].lower().replace(" ", "_"))
            concept = "Q" + self.geoClassListModel.itemFromIndex(
                curindex).text().split("Q")[1].replace(")", "")
        elif self.geoClassListModel.itemFromIndex(curindex) != None:
            concept = self.geoClassListModel.itemFromIndex(curindex).data(1)
        if "querytemplate" in self.triplestoreconf[endpointIndex]:
            if "wd:Q%%concept%% ." in self.triplestoreconf[endpointIndex][
                    "querytemplate"][
                        self.queryTemplates.currentIndex()]["query"]:
                querytext = ""
                if concept != None and concept.startswith("http"):
                    querytext = self.triplestoreconf[endpointIndex][
                        "querytemplate"][self.queryTemplates.currentIndex(
                        )]["query"].replace(
                            "wd:Q%%concept%% .",
                            "wd:" + concept[concept.rfind('/') + 1:] + " .")
                elif concept != None:
                    querytext = self.triplestoreconf[endpointIndex][
                        "querytemplate"][self.queryTemplates.currentIndex(
                        )]["query"].replace("wd:Q%%concept%% .",
                                            "wd:" + concept + " .")
            else:
                querytext = self.triplestoreconf[endpointIndex][
                    "querytemplate"][
                        self.queryTemplates.currentIndex()]["query"].replace(
                            "%%concept%%", concept)
            if self.queryLimit.text().isnumeric(
            ) and querytext.rfind("LIMIT") != -1:
                querytext = querytext[0:querytext.rfind(
                    "LIMIT")] + "LIMIT " + self.queryLimit.text()
            elif self.queryLimit.text().isnumeric() and querytext.rfind(
                    "LIMIT") == -1:
                querytext = querytext + " LIMIT " + self.queryLimit.text()
            self.inp_sparql2.setPlainText(querytext)
            self.inp_sparql2.columnvars = {}
        if self.geoClassList.selectionModel().currentIndex(
        ) != None and self.geoClassListModel.itemFromIndex(
                curindex
        ) != None and "#" in self.geoClassListModel.itemFromIndex(
                curindex).text():
            self.inp_label.setText(
                self.geoClassListModel.itemFromIndex(curindex).text()
                [self.geoClassListModel.itemFromIndex(curindex).text().
                 rfind('#') + 1:].lower().replace(" ", "_"))
        elif self.geoClassList.selectionModel().currentIndex(
        ) != None and self.geoClassListModel.itemFromIndex(curindex) != None:
            self.inp_label.setText(
                self.geoClassListModel.itemFromIndex(curindex).text()
                [self.geoClassListModel.itemFromIndex(curindex).text().
                 rfind('/') + 1:].lower().replace(" ", "_"))

    def itemModelToMap(self, model):
        resdict = {}
        for row in range(model.rowCount()):
            index = model.index(row, 0, self)
            resdict[model.itemFromIndex(index).text()] = model.itemFromIndex(
                index).data(1)
        return resdict

    ##
    #  @brief Deletes a row from the table in the enrichment dialog.
    #
    #  @param  send The sender of the request
    #
    def deleteEnrichRow(send):
        w = send.sender().parent()
        row = self.enrichTable.indexAt(w.pos()).row()
        self.enrichTable.removeRow(row)
        self.enrichTable.setCurrentCell(0, 0)

    ##
    #  @brief Adds a new row to the table in the enrichment dialog.
    #
    #  @param  self The object pointer
    #
    def addEnrichRow(self):
        layers = QgsProject.instance().layerTreeRoot().children()
        selectedLayerIndex = self.chooseLayerEnrich.currentIndex()
        layer = layers[selectedLayerIndex].layer()
        self.enrichTableResult.hide()
        fieldnames = [field.name() for field in layer.fields()]
        item = QTableWidgetItem("new_column")
        #item.setFlags(QtCore.Qt.ItemIsEnabled)
        row = self.enrichTable.rowCount()
        self.enrichTable.insertRow(row)
        self.enrichTable.setItem(row, 0, item)
        cbox = QComboBox()
        cbox.addItem("Get Remote")
        cbox.addItem("No Enrichment")
        cbox.addItem("Exclude")
        self.enrichTable.setCellWidget(row, 3, cbox)
        cbox = QComboBox()
        cbox.addItem("Enrich Value")
        cbox.addItem("Enrich URI")
        cbox.addItem("Enrich Both")
        self.enrichTable.setCellWidget(row, 4, cbox)
        cbox = QComboBox()
        for fieldd in fieldnames:
            cbox.addItem(fieldd)
        self.enrichTable.setCellWidget(row, 5, cbox)
        itemm = QTableWidgetItem("http://www.w3.org/2000/01/rdf-schema#label")
        self.enrichTable.setItem(row, 6, itemm)
        itemm = QTableWidgetItem("")
        self.enrichTable.setItem(row, 7, itemm)
        itemm = QTableWidgetItem("")
        self.enrichTable.setItem(row, 8, itemm)

    ## Validates the SPARQL query in the input field and outputs errors in a label.
    #  @param self The object pointer.
    def validateSPARQL(self):
        if self.prefixes != None and self.comboBox != None and self.comboBox.currentIndex(
        ) != None and self.prefixes[self.comboBox.currentIndex(
        )] != None and self.inp_sparql2.toPlainText(
        ) != None and self.inp_sparql2.toPlainText() != "":
            try:
                if self.prefixes[self.comboBox.currentIndex()] != "":
                    prepareQuery(
                        "".join(self.prefixes[self.comboBox.currentIndex()]) +
                        "\n" + self.inp_sparql2.toPlainText())
                self.errorLabel.setText("Valid Query")
                self.errorline = -1
                self.sparqlhighlight.errorhighlightline = self.errorline
                self.sparqlhighlight.currentline = 0
                self.inp_sparql2.errorline = None
            except Exception as e:
                match = re.search(r'line:([0-9]+),', str(e))
                match2 = re.search(r'col:([0-9]+),', str(e))
                start = int(match.group(1)) - len(self.triplestoreconf[
                    self.comboBox.currentIndex()]["prefixes"]) - 1
                self.errorLabel.setText(
                    re.sub("line:([0-9]+),", "line: " + str(start) + ",",
                           str(e)))
                self.inp_sparql2.errorline = start - 1
                if "line" in str(e):
                    ex = str(e)
                    start = ex.find('line:') + 5
                    end = ex.find(',', start)
                    start2 = ex.find('col:') + 4
                    end2 = ex.find(')', start2)
                    self.errorline = ex[start:end]
                    self.sparqlhighlight.errorhighlightcol = ex[start2:end2]
                    self.sparqlhighlight.errorhighlightline = self.errorline
                    self.sparqlhighlight.currentline = 0

    ##
    #  @brief Builds the search dialog to search for a concept or class.
    #  @param  self The object pointer
    #  @param  row the row to insert the result
    #  @param  column the column to insert the result
    #  @param  interlinkOrEnrich indicates if the dialog is meant for interlinking or enrichment
    #  @param  table the GUI element to display the result
    def buildSearchDialog(self,
                          row,
                          column,
                          interlinkOrEnrich,
                          table,
                          propOrClass,
                          bothOptions=False,
                          currentprefixes=None,
                          addVocabConf=None):
        self.currentcol = column
        self.currentrow = row
        self.interlinkdialog = SearchDialog(column, row, self.triplestoreconf,
                                            self.prefixes, interlinkOrEnrich,
                                            table, propOrClass, bothOptions,
                                            currentprefixes, addVocabConf)
        self.interlinkdialog.setMinimumSize(650, 400)
        self.interlinkdialog.setWindowTitle("Search Interlink Concept")
        self.interlinkdialog.exec_()

    ##
    #  @brief Builds a boundingbox dialog allows to pick a bounding box for a SPARQL query.
    #
    #  @param self The object pointer
    def getPointFromCanvas(self):
        self.d = BBOXDialog(self.inp_sparql2, self.triplestoreconf,
                            self.comboBox.currentIndex())
        self.d.setWindowTitle("Choose BoundingBox")
        self.d.exec_()

    ##
    #  @brief Builds a value mapping dialog window for ther interlinking dialog.
    #
    #  @param self The object pointer
    #  @param row The row of the table for which to map the value
    #  @param column The column of the table for which to map the value
    #  @param table The table in which to save the value mapping result
    #  @param layer The layer which is concerned by the enrichment oder interlinking
    def buildValueMappingDialog(self, row, column, interlinkOrEnrich, table,
                                layer):
        self.currentcol = column
        self.currentrow = row
        valuemap = None
        if table.item(row, column) != None and table.item(row,
                                                          column).text() != "":
            valuemap = table.item(row, column).data(1)
        self.interlinkdialog = ValueMappingDialog(column, row,
                                                  self.triplestoreconf,
                                                  interlinkOrEnrich, table,
                                                  table.item(row, 3).text(),
                                                  layer, valuemap)
        self.interlinkdialog.setMinimumSize(650, 400)
        self.interlinkdialog.setWindowTitle("Get Value Mappings for column " +
                                            table.item(row, 3).text())
        self.interlinkdialog.exec_()

    ##
    #  @brief Loads a QGIS layer for interlinking into the interlinking dialog.
    #
    #  @param self The object pointer
    def loadLayerForInterlink(self):
        layers = QgsProject.instance().layerTreeRoot().children()
        selectedLayerIndex = self.chooseLayerInterlink.currentIndex()
        if len(layers) == 0:
            return
        layer = layers[selectedLayerIndex].layer()
        fieldnames = [field.name() for field in layer.fields()]
        while self.interlinkTable.rowCount() > 0:
            self.interlinkTable.removeRow(0)
        row = 0
        self.interlinkTable.setHorizontalHeaderLabels([
            "Export?", "IDColumn?", "GeoColumn?", "Column", "ColumnProperty",
            "PropertyType", "ColumnConcept", "ValueConcepts"
        ])
        self.interlinkTable.setColumnCount(8)
        for field in fieldnames:
            item = QTableWidgetItem(field)
            item.setFlags(QtCore.Qt.ItemIsEnabled)
            item2 = QTableWidgetItem()
            item2.setCheckState(True)
            item3 = QTableWidgetItem()
            item3.setCheckState(False)
            item4 = QTableWidgetItem()
            item4.setCheckState(False)
            self.interlinkTable.insertRow(row)
            self.interlinkTable.setItem(row, 3, item)
            self.interlinkTable.setItem(row, 0, item2)
            self.interlinkTable.setItem(row, 1, item3)
            self.interlinkTable.setItem(row, 2, item4)
            cbox = QComboBox()
            cbox.addItem("Automatic")
            cbox.addItem("AnnotationProperty")
            cbox.addItem("DataProperty")
            cbox.addItem("ObjectProperty")
            cbox.addItem("SubClass")
            self.interlinkTable.setCellWidget(row, 5, cbox)
            currentRowCount = self.interlinkTable.rowCount()
            row += 1

    ##
    #  @brief Loads a QGIS layer for enrichment into the enrichment dialog.
    #
    #  @param self The object pointer
    def loadLayerForEnrichment(self):
        layers = QgsProject.instance().layerTreeRoot().children()
        selectedLayerIndex = self.chooseLayerEnrich.currentIndex()
        if len(layers) == 0:
            return
        layer = layers[selectedLayerIndex].layer()
        self.enrichTableResult.hide()
        while self.enrichTableResult.rowCount() > 0:
            self.enrichTableResult.removeRow(0)
        self.enrichTable.show()
        self.addEnrichedLayerRowButton.setEnabled(True)
        fieldnames = [field.name() for field in layer.fields()]
        while self.enrichTable.rowCount() > 0:
            self.enrichTable.removeRow(0)
        row = 0
        self.enrichTable.setColumnCount(9)
        self.enrichTable.setHorizontalHeaderLabels([
            "Column", "EnrichmentConcept", "TripleStore", "Strategy",
            "content", "ID Column", "ID Property", "ID Domain", "Language"
        ])
        for field in fieldnames:
            item = QTableWidgetItem(field)
            item.setFlags(QtCore.Qt.ItemIsEnabled)
            currentRowCount = self.enrichTable.rowCount()
            self.enrichTable.insertRow(row)
            self.enrichTable.setItem(row, 0, item)
            cbox = QComboBox()
            cbox.addItem("No Enrichment")
            cbox.addItem("Keep Local")
            cbox.addItem("Keep Remote")
            cbox.addItem("Replace Local")
            cbox.addItem("Merge")
            cbox.addItem("Ask User")
            cbox.addItem("Exclude")
            self.enrichTable.setCellWidget(row, 3, cbox)
            cbox = QComboBox()
            cbox.addItem("Enrich Value")
            cbox.addItem("Enrich URI")
            cbox.addItem("Enrich Both")
            self.enrichTable.setCellWidget(row, 4, cbox)
            cbox = QComboBox()
            for fieldd in fieldnames:
                cbox.addItem(fieldd)
            self.enrichTable.setCellWidget(row, 5, cbox)
            itemm = QTableWidgetItem(
                "http://www.w3.org/2000/01/rdf-schema#label")
            self.enrichTable.setItem(row, 6, itemm)
            itemm = QTableWidgetItem("")
            self.enrichTable.setItem(row, 7, itemm)
            itemm = QTableWidgetItem("")
            self.enrichTable.setItem(row, 8, itemm)
            celllayout = QHBoxLayout()
            upbutton = QPushButton("Up")
            removebutton = QPushButton("Remove", self)
            removebutton.clicked.connect(self.deleteEnrichRow)
            downbutton = QPushButton("Down")
            celllayout.addWidget(upbutton)
            celllayout.addWidget(downbutton)
            celllayout.addWidget(removebutton)
            w = QWidget()
            w.setLayout(celllayout)
            optitem = QTableWidgetItem()
            #self.enrichTable.setCellWidget(row,4,w)
            #self.enrichTable.setItem(row,3,cbox)
            row += 1
        self.originalRowCount = row

    ## Fetch the currently loaded layers.
    #  @param self The object pointer.
    def loadUnicornLayers(self):
        layers = QgsProject.instance().layerTreeRoot().children()
        # Populate the comboBox with names of all the loaded unicorn layers
        self.loadedLayers.clear()
        self.chooseLayerInterlink.clear()
        self.chooseLayerEnrich.clear()
        for layer in layers:
            ucl = layer.name()
            #if type(layer) == QgsMapLayer.VectorLayer:
            self.loadedLayers.addItem(layer.name())
            self.chooseLayerInterlink.addItem(layer.name())
            self.chooseLayerEnrich.addItem(layer.name())
class geopunt4QgisDataCatalog(QDialog):
    def __init__(self, iface):
        QDialog.__init__(self, None)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.iface = iface

        # initialize locale
        locale = QSettings().value("locale/userLocale", "en")
        if not locale: locale = 'en'
        else: locale = locale[0:2]
        localePath = os.path.join(os.path.dirname(__file__), 'i18n', 'geopunt4qgis_{}.qm'.format(locale))
        if os.path.exists(localePath):
            self.translator = QTranslator()
            self.translator.load(localePath)
            QCoreApplication.installTranslator(self.translator)

        self._initGui()

    def _initGui(self):
        """setup the user interface"""
        self.ui = Ui_geopunt4QgisDataCatalogDlg()
        self.ui.setupUi(self)

        # get settings
        self.s = QSettings()
        self.loadSettings()

        self.gh = geometryHelper(self.iface)

        # setup a message bar
        self.bar = QgsMessageBar()
        self.bar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.ui.verticalLayout.addWidget(self.bar)

        self.ui.buttonBox.addButton(QPushButton("Sluiten"), QDialogButtonBox.RejectRole)
        for btn in self.ui.buttonBox.buttons():
            btn.setAutoDefault(0)

        # vars
        self.firstShow = True
        self.wms = None
        self.wfs = None
        self.dl = None
        self.zoek = ''
        self.bronnen = None

        self.model = QStandardItemModel(self)
        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.model)
        self.ui.resultView.setModel(self.proxyModel)

        self.completer = QCompleter(self)
        self.completerModel = QStringListModel(self)
        self.ui.zoekTxt.setCompleter(self.completer)
        self.completer.setModel(self.completerModel)

        # eventhandlers
        self.ui.zoekBtn.clicked.connect(self.onZoekClicked)
        self.ui.addWMSbtn.clicked.connect(self.addWMS)
        self.ui.addWFSbtn.clicked.connect(self.addWFS)
        self.ui.DLbtn.clicked.connect(lambda: self.openUrl(self.dl))
        self.ui.resultView.clicked.connect(self.resultViewClicked)
        self.ui.modelFilterCbx.currentIndexChanged.connect(self.modelFilterCbxIndexChanged)
        self.ui.filterWgt.setHidden(1)
        self.ui.buttonBox.helpRequested.connect(self.openHelp)
        self.finished.connect(self.clean)

    def loadSettings(self):
        self.timeout = int(self.s.value("geopunt4qgis/timeout", 15))
        if settings().proxyUrl:
            self.proxy = settings().proxyUrl
        else:
            self.proxy = ""

        self.md = MDReader(self.timeout, self.proxy)

    def openHelp(self):
        webbrowser.open_new_tab("http://www.geopunt.be/voor-experts/geopunt-plug-ins/functionaliteiten/catalogus")

    def _setModel(self, records):
        self.model.clear()
        records = sorted(records, key=lambda k: k['title']) 

        for rec in records:
            title = QStandardItem(rec['title'])  # 0
            wms = QStandardItem(rec['wms'])  # 1
            downloadLink = QStandardItem(rec['download'])  # 2
            id = QStandardItem(rec['uuid'])  # 3
            abstract = QStandardItem(rec['abstract'])  # 4
            wfs = QStandardItem(rec['wfs'])  # 5
            self.model.appendRow([title, wms, downloadLink, id, abstract, wfs])

    # overwrite
    def show(self):
        QDialog.show(self)
        self.setWindowModality(0)
        metadataUrl = "https://metadata.geopunt.be"
        inet = internet_on(proxyUrl=self.proxy, timeout=self.timeout, testSite= metadataUrl)
        if not inet:
            msg = "Kan geen verbing maken met de metadata van Geopunt: {} \nMogelijke is deze site niet bereikbaar, dan zal deze tool ook niet werken.\nProbeer later opnieuw. Indien dit probleem zich blijft voordoen contacteer informatie Vlaanderen.".format(metadataUrl)
            QMessageBox.warning(self.iface.mainWindow(),  "Waarschuwing: kan geen verbinding maken", msg)
            self.bar.pushMessage( QCoreApplication.translate("geopunt4QgisPoidialog","Waarschuwing"),  msg, level=Qgis.Warning, duration=3)  
            return 
        
        if self.firstShow:
            self.ui.GDIThemaCbx.addItems([''] + self.md.list_GDI_theme())
            self.ui.organisatiesCbx.addItems([''] + self.md.list_organisations())
            keywords = sorted(self.md.list_suggestionKeyword())
            self.completerModel.setStringList(keywords)
            self.bronnen = self.md.list_bronnen()
            self.ui.bronCbx.addItems([''] + [n[1] for n in self.bronnen])
            self.ui.typeCbx.addItems([''] + [n[0] for n in self.md.dataTypes])

            self.ui.INSPIREannexCbx.addItems([''] + self.md.inspireannex)
            self.ui.INSPIREserviceCbx.addItems([''] + self.md.inspireServiceTypes)
            self.ui.INSPIREthemaCbx.addItems([''] + self.md.list_inspire_theme())
            self.firstShow = False


    # eventhandlers
    def resultViewClicked(self):
        if self.ui.resultView.selectedIndexes():
            row = self.ui.resultView.selectedIndexes()[0].row()

            title = self.proxyModel.data(self.proxyModel.index(row, 0))
            self.wms = self.proxyModel.data(self.proxyModel.index(row, 1))
            self.dl = self.proxyModel.data(self.proxyModel.index(row, 2))
            self.wfs = self.proxyModel.data(self.proxyModel.index(row, 5))
            uuid = self.proxyModel.data(self.proxyModel.index(row, 3))
            abstract = self.proxyModel.data(self.proxyModel.index(row, 4))

            self.ui.descriptionText.setText(
                """<h3>%s</h3><div>%s</div><br/><div>
             <a href='https://metadata.geopunt.be/zoekdienst/apps/tabsearch/index.html?uuid=%s'>
             Ga naar fiche</a></div>""" % (title, abstract, uuid))

            if self.wms:
                self.ui.addWMSbtn.setEnabled(1)
            else:
                self.ui.addWMSbtn.setEnabled(0)

            if self.wfs:
                self.ui.addWFSbtn.setEnabled(1)
            else:
                self.ui.addWFSbtn.setEnabled(0)

            if self.dl:
                self.ui.DLbtn.setEnabled(1)
            else:
                self.ui.DLbtn.setEnabled(0)

    def onZoekClicked(self):
        self.zoek = self.ui.zoekTxt.currentText()
        self.search()

    def modelFilterCbxIndexChanged(self):
        value = self.ui.modelFilterCbx.currentIndex()
        if value == 1:
            self.filterModel(1)
        elif value == 2:
            self.filterModel(5)
        elif value == 3:
            self.filterModel(2)
        else:
            self.filterModel()

    def filterModel(self, col=None):
        if col != None:
            self.proxyModel.setFilterKeyColumn(col)
            expr = QRegExp("?*", Qt.CaseInsensitive, QRegExp.Wildcard)
            self.proxyModel.setFilterRegExp(expr)
        else:
            self.proxyModel.setFilterRegExp(None)

    def search(self):
        try:
            if self.ui.filterBox.isChecked():
                themekey = self.ui.GDIThemaCbx.currentText()
                orgName = self.ui.organisatiesCbx.currentText()
                dataTypes = [n[1] for n in self.md.dataTypes if n[0] == self.ui.typeCbx.currentText()]
                if dataTypes != []:
                    dataType = dataTypes[0]
                else:
                    dataType = ''
                siteIds = [n[0] for n in self.bronnen if n[1] == self.ui.bronCbx.currentText()]
                if siteIds != []:
                    siteId = siteIds[0]
                else:
                    siteId = ''
                inspiretheme = self.ui.INSPIREthemaCbx.currentText()
                inspireannex = self.ui.INSPIREannexCbx.currentText()
                inspireServiceType = self.ui.INSPIREserviceCbx.currentText()
                searchResult = MDdata(self.md.searchAll(
                    self.zoek, themekey, orgName, dataType, siteId, inspiretheme, inspireannex, inspireServiceType))
            else:
                searchResult = MDdata(self.md.searchAll(self.zoek))
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=3)
            return

        self.ui.countLbl.setText("Aantal gevonden: %s" % searchResult.count)
        self.ui.descriptionText.setText('')
        self._setModel(searchResult.records)
        if searchResult.count == 0:
            self.bar.pushMessage(
                QCoreApplication.translate("geopunt4QgisPoidialog", "Waarschuwing "),
                QCoreApplication.translate("geopunt4QgisPoidialog",
                                                  "Er werden geen resultaten gevonde voor deze zoekopdracht"),
                duration=5)

    def openUrl(self, url):
        if url: webbrowser.open_new_tab(url.encode("utf-8"))

    def addWMS(self):
        if self.wms == None: return

        crs = self.gh.getGetMapCrs(self.iface).authid()
        if crs != 'EPSG:31370' or crs != 'EPSG:3857' or crs != 'EPSG:3043':
            crs = 'EPSG:31370'
        try:
            lyrs = getWmsLayerNames(self.wms, self.proxy)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return
        if len(lyrs) == 0:
            self.bar.pushMessage("WMS",
                                 QCoreApplication.translate("geopunt4QgisDataCatalog",
                                                                   "Kan geen lagen vinden in: %s" % self.wms),
                                 level=Qgis.Warning, duration=10)
            return
        elif len(lyrs) == 1:
            layerTitle = lyrs[0][1]
        else:
            layerTitle, accept = QInputDialog.getItem(self, "WMS toevoegen",
                                                            "Kies een laag om toe te voegen", [n[1] for n in lyrs],
                                                            editable=0)
            if not accept: return

        layerName = [n[0] for n in lyrs if n[1] == layerTitle][0]
        style = [n[2] for n in lyrs if n[1] == layerTitle][0]
        if not style: style = ""
        
        url = self.wms.split('?')[0]

        if crs != 'EPSG:31370' or crs != 'EPSG:3857':
            crs = 'EPSG:31370'
        wmsUrl = "contextualWMSLegend=0&dpiMode=7&url=%s&layers=%s&format=image/png&styles=%s&crs=%s" % (
                                                                         url, layerName, style, crs)

        try:
            rlayer = QgsRasterLayer(wmsUrl, layerTitle, 'wms')
            if rlayer.isValid():
                QgsProject.instance().addMapLayer(rlayer)
            else:
                self.bar.pushMessage("Error",
                                     QCoreApplication.translate("geopunt4QgisDataCatalog", "Kan WMS niet laden"),
                                     level=Qgis.Critical, duration=10)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return

    def addWFS(self):
        if self.wfs == None: return
        try:
            lyrs = getWFSLayerNames(self.wfs, self.proxy)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return
        if len(lyrs) == 0:
            self.bar.pushMessage("WFS",
                 QCoreApplication.translate("geopunt4QgisDataCatalog",
                 "Kan geen lagen vinden in: %s" % self.wfs), level=Qgis.Warning, duration=10)
            return
        elif len(lyrs) == 1:
            layerTitle = lyrs[0][1]
        else:
            layerTitle, accept = QInputDialog.getItem(self, "WFS toevoegen",
                                                            "Kies een laag om toe te voegen", [n[1] for n in lyrs],
                                                            editable=0)
            if not accept: return

        layerName = [n[0] for n in lyrs if n[1] == layerTitle][0]
        crs = [n[2] for n in lyrs if n[1] == layerTitle][0]
        url = self.wfs.split('?')[0]

        wfsUri = makeWFSuri(url, layerName, crs )

        try:
          vlayer = QgsVectorLayer(wfsUri, layerTitle, "WFS")
          QgsProject.instance().addMapLayer(vlayer)
        except:
            self.bar.pushMessage("Error", str(sys.exc_info()[1]), level=Qgis.Critical, duration=10)
            return

    def clean(self):
        self.model.clear()
        self.wms = None
        self.wfs = None
        self.dl = None
        self.ui.zoekTxt.setCurrentIndex(0)
        self.ui.descriptionText.setText('')
        self.ui.countLbl.setText("")
        self.ui.msgLbl.setText("")
        self.ui.DLbtn.setEnabled(0)
        self.ui.addWFSbtn.setEnabled(0)
        self.ui.addWMSbtn.setEnabled(0)
        self.ui.modelFilterCbx.setCurrentIndex(0)
    def refresh_model(self, source_model, db_connector=None, silent=False):

        filtered_source_model = QSortFilterProxyModel()
        filtered_source_model.setSourceModel(source_model)
        filtered_source_model.setFilterRole(int(SourceModel.Roles.TYPE))
        self.print_info.emit(self.tr("Refresh available models:"))
        self.clear()
        previously_checked_models = self._checked_models
        self._checked_models = {}

        # models from db
        db_modelnames = self._db_modelnames(db_connector)

        # models from the repos
        filtered_source_model.setFilterFixedString("model")
        for r in range(0, filtered_source_model.rowCount()):
            filtered_source_model_index = filtered_source_model.index(
                r, SourceModel.Columns.SOURCE)
            modelname = filtered_source_model_index.data(
                int(SourceModel.Roles.NAME))
            if modelname:
                enabled = modelname not in db_modelnames
                self.add_source(
                    modelname,
                    filtered_source_model_index.data(
                        int(SourceModel.Roles.TYPE)),
                    filtered_source_model_index.data(
                        int(SourceModel.Roles.PATH)),
                    filtered_source_model_index.data(
                        int(SourceModel.Roles.ORIGIN_INFO)),
                    previously_checked_models.get(
                        (
                            modelname,
                            filtered_source_model_index.data(
                                int(SourceModel.Roles.PATH)),
                        ),
                        Qt.Checked,
                    ) if enabled and modelname not in self.checked_models()
                    else Qt.Unchecked,
                    enabled,
                )
                if not silent:
                    self.print_info.emit(
                        self.tr("- Append (repository) model {}{}").format(
                            modelname,
                            " (inactive because it already exists in the database)"
                            if not enabled else "",
                        ))

        # models from the files
        filtered_source_model.setFilterFixedString("ili")
        for r in range(0, filtered_source_model.rowCount()):
            filtered_source_model_index = filtered_source_model.index(
                r, SourceModel.Columns.SOURCE)
            ili_file_path = filtered_source_model_index.data(
                int(SourceModel.Roles.PATH))
            self.ilicache = IliCache(None, ili_file_path)
            models = self.ilicache.process_ili_file(ili_file_path)
            for model in models:
                if model["name"]:
                    enabled = model["name"] not in db_modelnames
                    self.add_source(
                        model["name"],
                        filtered_source_model_index.data(
                            int(SourceModel.Roles.TYPE)),
                        filtered_source_model_index.data(
                            int(SourceModel.Roles.PATH)),
                        filtered_source_model_index.data(
                            int(SourceModel.Roles.ORIGIN_INFO)),
                        previously_checked_models.get(
                            (
                                model["name"],
                                filtered_source_model_index.data(
                                    int(SourceModel.Roles.PATH)),
                            ),
                            Qt.Checked if model is models[-1] and enabled
                            and model["name"] not in self.checked_models() else
                            Qt.Unchecked,
                        ),
                        enabled,
                    )
                    if not silent:
                        self.print_info.emit(
                            self.tr("- Append (file) model {}{} from {}").
                            format(
                                model["name"],
                                " (inactive because it already exists in the database)"
                                if not enabled else "",
                                ili_file_path,
                            ))

        # models from the transfer files
        filtered_source_model.setFilterRegExp("|".join(TransferExtensions))
        for r in range(0, filtered_source_model.rowCount()):
            filtered_source_model_index = filtered_source_model.index(
                r, SourceModel.Columns.SOURCE)
            xtf_file_path = filtered_source_model_index.data(
                int(SourceModel.Roles.PATH))
            models = self._transfer_file_models(xtf_file_path)
            for model in models:
                if model["name"]:
                    enabled = model["name"] not in db_modelnames
                    self.add_source(
                        model["name"],
                        filtered_source_model_index.data(
                            int(SourceModel.Roles.TYPE)),
                        filtered_source_model_index.data(
                            int(SourceModel.Roles.PATH)),
                        filtered_source_model_index.data(
                            int(SourceModel.Roles.ORIGIN_INFO)),
                        previously_checked_models.get(
                            (
                                model["name"],
                                filtered_source_model_index.data(
                                    int(SourceModel.Roles.PATH)),
                            ),
                            Qt.Checked if enabled
                            and model["name"] not in self.checked_models() else
                            Qt.Unchecked,
                        ),
                        enabled,
                    )
                    if not silent:
                        self.print_info.emit(
                            self.tr("- Append (xtf file) model {}{} from {}").
                            format(
                                model["name"],
                                " (inactive because it already exists in the database)"
                                if not enabled else "",
                                xtf_file_path,
                            ))

        return self.rowCount()
Esempio n. 25
0
    def setup_class_table(self, classes=[]):
        # Load the codes each class will be recoded to.
        # 
        # The "classes" parameter will include any mappings derived from a 
        # class definition file, or, in the case or reading in user land cover 
        # files, classes from the file itself.
        # 
        # The default codes stored in self.default_classes are derived either 
        # from the data/land_cover_classes_ESA_to_IPCC.json file when this class is 
        # instantiated from the LCSetupWidget, or from the values within a 
        # custom user data file when this class is instantiated from the 
        # DlgDataIOImportLC class.
        if len(classes) > 0:
            input_codes = sorted([c['Initial_Code'] for c in classes])
            default_codes = sorted([c['Initial_Code'] for c in self.default_classes])
            new_codes = [c for c in input_codes if c not in default_codes]
            missing_codes = [c for c in default_codes if c not in input_codes]
            if len(new_codes) > 0:
                QtWidgets.QMessageBox.warning(None,
                                              self.tr("Warning"),
                                              self.tr(u"Some of the class codes ({}) in the definition file do not appear in the chosen data file.".format(', '.join([str(c) for c in new_codes]))))
            if len(missing_codes) > 0:
                QtWidgets.QMessageBox.warning(None,
                                              self.tr("Warning"),
                                              self.tr(u"Some of the class codes ({}) in the data file do not appear in the chosen definition file.".format(', '.join([str(c) for c in missing_codes]))))

            # Setup a new classes list with the new class codes for all classes 
            # included in default classes, and any other class codes that are 
            # missing added from the default class list
            classes = [c for c in classes if c['Initial_Code'] in default_codes]
            classes.extend([c for c in self.default_classes if c['Initial_Code'] not in input_codes])
        else:
            classes = self.default_classes

        table_model = LCAggTableModel(classes, parent=self)
        proxy_model = QSortFilterProxyModel()
        proxy_model.setSourceModel(table_model)
        self.remap_view.setModel(proxy_model)

        # Add selector in cell
        for row in range(0, len(classes)):
            lc_class_combo = LCClassComboBox()


            # Now Set the default final codes for each row. Note that the 
            # QComboBox entries are potentially translated, so need to link the 
            # translated names back to a particular code.
            
            # Get the input code for this row and the final label it should map 
            # to by default
            input_code = table_model.index(row, 0).data()
            final_label = [c['Final_Label'] for c in classes if c['Initial_Code'] == input_code][0]

            # Figure out which label translation this Final_Label (in English) 
            # is equivalent to
            label_to_label_tr = {final_classes[key]['label']: key for key in final_classes.keys()}
            final_label_tr = label_to_label_tr[final_label]

            # Now find the index in the combo box of this translated final 
            # label
            ind = lc_class_combo.findText(final_label_tr)
            if ind != -1:
                lc_class_combo.setCurrentIndex(ind)
            self.remap_view.setIndexWidget(proxy_model.index(row, 2), lc_class_combo)

        self.remap_view.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        self.remap_view.horizontalHeader().setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        self.remap_view.horizontalHeader().setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
        
        self.remap_view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)

        return True
class ThreeDiResultSelectionWidget(QWidget, FORM_CLASS):
    """Dialog for selecting model (spatialite and result files netCDFs)

    TODO: actually, it is two dialogs in one: a selector of results and a
    separate downloader of results. They are not really connected. So
    splitting them makes the code simpler. And, more importantly, it makes the
    UI clearer.

    """

    closingDialog = pyqtSignal()

    def __init__(
        self,
        parent=None,
        iface=None,
        ts_datasources=None,
        downloadable_results=None,
        tool=None,
    ):
        """Constructor

        :parent: Qt parent Widget
        :iface: QGiS interface
        :ts_datasources: TimeseriesDatasourceModel instance
        :downloadable_results: DownloadableResultModel instance
        :tool: the tool class which instantiated this widget. Is used
             here for storing volatile information
        """
        super().__init__(parent)

        self.tool = tool
        self.iface = iface
        self.setupUi(self)

        # login administration
        self.login_dialog = LoginDialog()
        # NOTE: autoDefault was set on ``log_in_button`` (via Qt Designer),
        # which makes pressing Enter work for logging in.
        self.login_dialog.log_in_button.clicked.connect(self.handle_log_in)

        # set models on table views and update view columns
        self.ts_datasources = ts_datasources
        self.resultTableView.setModel(self.ts_datasources)
        self.ts_datasources.set_column_sizes_on_view(self.resultTableView)

        self.downloadable_results = downloadable_results
        self.download_proxy_model = QSortFilterProxyModel()
        self.download_proxy_model.setSourceModel(self.downloadable_results)
        self.download_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filterLineEdit.textChanged.connect(
            self.download_proxy_model.setFilterFixedString)
        self.downloadResultTableView.setModel(self.download_proxy_model)

        self.toggle_login_interface()

        # connect signals
        self.selectTsDatasourceButton.clicked.connect(
            self.select_ts_datasource)
        self.closeButton.clicked.connect(self.close)
        self.removeTsDatasourceButton.clicked.connect(
            self.remove_selected_ts_datasource)
        self.selectModelSpatialiteButton.clicked.connect(
            self.select_model_spatialite_file)
        self.loginButton.clicked.connect(self.on_login_button_clicked)

        # set combobox list
        combo_list = [
            datasource for datasource in self.get_3di_spatialites_legendlist()
        ]

        if (self.ts_datasources.model_spatialite_filepath
                and self.ts_datasources.model_spatialite_filepath
                not in combo_list):
            combo_list.append(self.ts_datasources.model_spatialite_filepath)

        if not self.ts_datasources.model_spatialite_filepath:
            combo_list.append("")

        self.modelSpatialiteComboBox.addItems(combo_list)

        if self.ts_datasources.model_spatialite_filepath:
            current_index = self.modelSpatialiteComboBox.findText(
                self.ts_datasources.model_spatialite_filepath)

            self.modelSpatialiteComboBox.setCurrentIndex(current_index)
        else:
            current_index = self.modelSpatialiteComboBox.findText("")
            self.modelSpatialiteComboBox.setCurrentIndex(current_index)

        self.modelSpatialiteComboBox.currentIndexChanged.connect(
            self.model_spatialite_change)

        self.thread = None

    def on_close(self):
        """
        Clean object on close
        """
        self.selectTsDatasourceButton.clicked.disconnect(
            self.select_ts_datasource)
        self.closeButton.clicked.disconnect(self.close)
        self.removeTsDatasourceButton.clicked.disconnect(
            self.remove_selected_ts_datasource)
        self.selectModelSpatialiteButton.clicked.disconnect(
            self.select_model_spatialite_file)
        self.loginButton.clicked.disconnect(self.on_login_button_clicked)

        # stop the thread when we close the widget
        if self.thread:
            self.thread.output.disconnect(self.update_download_result_model)
            self.thread.stop()

    def closeEvent(self, event):
        """
        Close widget, called by Qt on close
        :param event: QEvent, close event
        """
        self.closingDialog.emit()
        self.on_close()
        event.accept()

    def keyPressEvent(self, event):
        """Handle key press events on the widget."""
        # Close window if the Escape key is pressed
        if event.key() == Qt.Key_Escape:
            self.close()

    def select_ts_datasource(self):
        """
        Open File dialog for selecting netCDF result files, triggered by button
        :return: boolean, if file is selected
        """

        settings = QSettings("3di", "qgisplugin")

        try:
            init_path = settings.value("last_used_datasource_path", type=str)
        except TypeError:
            logger.debug(
                "Last used datasource path is no string, setting it to our home dir."
            )
            init_path = os.path.expanduser("~")

        filename, __ = QFileDialog.getOpenFileName(
            self,
            "Open resultaten file",
            init_path,
            "NetCDF (subgrid_map.nc results_3di.nc)",
        )

        if filename:
            # Little test for checking if there is an id mapping file available
            # If not we check if an .h5 file is available
            # If not we're not going to proceed

            datasource_type = detect_netcdf_version(filename)
            logger.info("Netcdf result file selected: %s, type is %s",
                        filename, datasource_type)
            if datasource_type == "netcdf-groundwater":
                try:
                    find_h5_file(filename)
                except FileNotFoundError:
                    logger.warning(
                        "Groundwater h5 not found (%s), warning the user.",
                        filename)
                    pop_up_info(
                        "You selected a netcdf that was created "
                        "(after May 2018) with a 3Di calculation"
                        "core that is able to include groundwater"
                        " calculations. The ThreeDiToolbox reads "
                        "this netcdf together with an .h5 file, we "
                        "could however not find this .h5 file. Please "
                        "add this file next to the netcdf and try "
                        "again",
                        title="Error",
                    )
                    return False
            elif datasource_type == "netcdf":
                logger.warning(
                    "Result file (%s) version is too old. Warning the user.",
                    filename)
                pop_up_info(
                    "The selected result data is too old and no longer "
                    "supported in this version of ThreediToolbox. Please "
                    "recalculate the results with a newer version of the "
                    "threedicore or use the ThreediToolbox plugin for QGIS 2",
                    title="Error",
                )
                # TODO: the below "return False" was previously missing. Check
                # if Reinout was right in adding it :-)
                return False

            items = [{
                "type": datasource_type,
                "name": os.path.basename(filename).lower().rstrip(".nc"),
                "file_path": filename,
            }]
            self.ts_datasources.insertRows(items)
            settings.setValue("last_used_datasource_path",
                              os.path.dirname(filename))
            return True
        return False

    def remove_selected_ts_datasource(self):
        """
        Remove selected result files from model, called by 'remove' button
        """

        selection_model = self.resultTableView.selectionModel()
        # get unique rows in selected fields
        rows = set(
            [index.row() for index in selection_model.selectedIndexes()])
        for row in reversed(sorted(rows)):
            self.ts_datasources.removeRows(row, 1)

    def get_3di_spatialites_legendlist(self):
        """
        Get list of spatialite data sources currently active in canvas
        :return: list of strings, unique spatialite paths
        """

        tdi_spatialites = []
        for layer in self.iface.layerTreeView().selectedLayers():
            if (layer.name() in list(LAYER_QH_TYPE_MAPPING.keys())
                    and layer.dataProvider().name() == "spatialite"):
                source = layer.dataProvider().dataSourceUri().split("'")[1]
                if source not in tdi_spatialites:
                    tdi_spatialites.append(source)

        return tdi_spatialites

    def model_spatialite_change(self, nr):
        """
        Change active modelsource. Called by combobox when selected
        spatialite changed
        :param nr: integer, nr of item selected in combobox
        """
        filepath = self.modelSpatialiteComboBox.currentText()
        logger.info("Different spatialite 3di model selected: %s", filepath)
        self.ts_datasources.model_spatialite_filepath = filepath
        # Just emitting some dummy model indices cuz what else can we do, there
        # is no corresponding rows/columns that's been changed
        self.ts_datasources.dataChanged.emit(QModelIndex(), QModelIndex())

    def select_model_spatialite_file(self):
        """
        Open file dialog on click on button 'load model'
        :return: Boolean, if file is selected
        """

        settings = QSettings("3di", "qgisplugin")

        try:
            init_path = settings.value("last_used_spatialite_path", type=str)
        except TypeError:
            logger.debug(
                "Last used datasource path is no string, setting it to our home dir."
            )
            init_path = os.path.expanduser("~")

        filepath, __ = QFileDialog.getOpenFileName(
            self, "Open 3Di model spatialite file", init_path,
            "Spatialite (*.sqlite)")

        if filepath == "":
            return False

        self.ts_datasources.spatialite_filepath = filepath
        index_nr = self.modelSpatialiteComboBox.findText(filepath)
        if index_nr < 0:
            self.modelSpatialiteComboBox.addItem(filepath)
            index_nr = self.modelSpatialiteComboBox.findText(filepath)

        self.modelSpatialiteComboBox.setCurrentIndex(index_nr)

        add_spatialite_connection(filepath, self.iface)
        settings.setValue("last_used_spatialite_path",
                          os.path.dirname(filepath))
        return True

    def on_login_button_clicked(self):
        """Handle log in and out."""
        if self.logged_in:
            self.handle_log_out()
        else:
            self.login_dialog.user_name_input.setFocus()
            self.login_dialog.show()

    def handle_log_out(self):
        self.set_logged_out_status()
        if self.thread:
            self.thread.stop()
        num_rows = len(self.downloadable_results.rows)
        self.downloadable_results.removeRows(0, num_rows)
        self.toggle_login_interface()

    def toggle_login_interface(self):
        """Enable/disable aspects of the interface based on login status."""
        # TODO: better to use signals maybe?
        if self.logged_in:
            self.loginButton.setText("Log out")
            self.downloadResultTableView.setEnabled(True)
            self.downloadResultButton.setEnabled(True)
        else:
            self.loginButton.setText("Log in")
            self.downloadResultTableView.setEnabled(False)
            self.downloadResultButton.setEnabled(False)

    def handle_log_in(self):
        """Handle logging in and populating DownloadableResultModel."""
        # Get the username and password
        username = self.login_dialog.user_name_input.text()
        password = self.login_dialog.user_password_input.text()

        if username == "" or password == "":
            pop_up_info("Username or password cannot be empty.")
            return

        try:
            scenarios_endpoint = Endpoint(username=username,
                                          password=password,
                                          endpoint="scenarios")
            endpoint = scenarios_endpoint.get_paginated(page_size=10)
        except HTTPError as e:
            logger.exception("Error trying to log in")
            if e.code == 401:
                pop_up_info("Incorrect username and/or password.")
            else:
                pop_up_info(str(e))
            return

        self.set_logged_in_status(username, password)
        self.toggle_login_interface()
        # don't persist info in the dialog: useful when logged out
        self.login_dialog.user_name_input.clear()
        self.login_dialog.user_password_input.clear()

        # start thread
        self.thread = DownloadWorker(endpoint=endpoint,
                                     username=username,
                                     password=password)
        self.thread.connection_failure.connect(self.handle_connection_failure)
        self.thread.output.connect(self.update_download_result_model)
        self.thread.start()

        # return to widget
        self.login_dialog.close()

    def update_download_result_model(self, items):
        self.downloadable_results.insertRows(items)

    def handle_connection_failure(self, status, reason):
        pop_up_info("Something went wrong trying to connect to "
                    "lizard: {0} {1}".format(status, reason))
        self.handle_log_out()

    @property
    def username(self):
        return self.tool.username

    @username.setter
    def username(self, username):
        self.tool.username = username

    @property
    def password(self):
        return self.tool.password

    @password.setter
    def password(self, password):
        self.tool.password = password

    @property
    def logged_in(self):
        """Return the logged in status."""
        return self.tool.logged_in

    def set_logged_in_status(self, username, password):
        """Set logged in status to True."""
        # TODO: it doesn't really do that. I *suspect* that the parent class
        # has a logged_in() method that checks if username and password are
        # set there. It's all quite indirect.
        self.username = username
        self.password = password

    def set_logged_out_status(self):
        """Set logged in status to False."""
        self.username = None
        self.password = None
class RasterAttributeTableDialog(QDialog):
    def __init__(self, raster_layer, iface=None):

        QDialog.__init__(self)
        # Set up the user interface from Designer.
        ui_path = os.path.join(os.path.dirname(__file__),
                               'Ui_RasterAttributeTableDialog.ui')
        uic.loadUi(ui_path, self)

        self.raster_layer = raster_layer
        self.iface = iface
        self.editable = False
        self.is_dirty = False

        self.mRasterBandsComboBox.addItems([
            raster_layer.bandName(bn)
            for bn in range(1,
                            raster_layer.bandCount() + 1)
        ])

        self.mToggleEditingToolButton.setIcon(
            QgsApplication.getThemeIcon("/mActionEditTable.svg"))
        self.mAddColumnToolButton.setIcon(
            QgsApplication.getThemeIcon("/mActionNewAttribute.svg"))
        self.mAddRowToolButton.setIcon(
            QgsApplication.getThemeIcon("/mActionNewTableRow.svg"))
        self.mRemoveRowToolButton.setIcon(
            QgsApplication.getThemeIcon("/mActionRemoveSelectedFeature.svg"))
        self.mRemoveColumnToolButton.setIcon(
            QgsApplication.getThemeIcon("/mActionDeleteAttribute.svg"))
        self.mSaveChangesToolButton.setIcon(
            QgsApplication.getThemeIcon("/mActionSaveAllEdits.svg"))

        stylesheet = "QToolButton {padding: 1px;}"
        self.mToggleEditingToolButton.setStyleSheet(stylesheet)
        self.mAddColumnToolButton.setStyleSheet(stylesheet)
        self.mRemoveColumnToolButton.setStyleSheet(stylesheet)
        self.mSaveChangesToolButton.setStyleSheet(stylesheet)

        assert self.loadRat(0)

        self.setEditable(False)

        # Connections
        self.mClassifyButton.clicked.connect(self.classify)
        self.mRasterBandsComboBox.currentIndexChanged.connect(self.loadRat)
        self.mButtonBox.accepted.connect(self.accept)
        self.mButtonBox.rejected.connect(self.reject)

        self.mToggleEditingToolButton.toggled.connect(self.setEditable)
        self.mSaveChangesToolButton.clicked.connect(self.saveChanges)
        self.mAddColumnToolButton.clicked.connect(self.addColumn)
        self.mRemoveColumnToolButton.clicked.connect(self.removeColumn)
        self.mAddRowToolButton.clicked.connect(self.addRow)
        self.mRemoveRowToolButton.clicked.connect(self.removeRow)

        try:
            self.restoreGeometry(QgsSettings().value(
                "RasterAttributeTable/geometry", None, QByteArray,
                QgsSettings.Plugins))
        except:
            pass

        self.updateButtons()

    def addRow(self):

        current_row = self.proxyModel.mapToSource(
            self.mRATView.selectionModel().currentIndex()).row()
        dlg = AddRowDialog(current_row)

        if dlg.exec_() == QDialog.Accepted:
            if not self.model.insert_row(
                    current_row + (0 if dlg.mBefore.isChecked() else 1)):
                QMessageBox.warning(
                    None, QCoreApplication.translate('RAT',
                                                     "Error Adding Row"),
                    QCoreApplication.translate(
                        'RAT',
                        "An error occourred while adding a new row to the RAT!"
                    ))

    def removeRow(self):

        if QMessageBox.question(
                None, QCoreApplication.translate('RAT', "Remove Row"),
                QCoreApplication.translate(
                    'RAT',
                    "Removing a row will remove the value from the RAT, do you want to continue?"
                )) == QMessageBox.Yes:

            current_row = self.proxyModel.mapToSource(
                self.mRATView.selectionModel().currentIndex()).row()
            if not self.model.remove_row(current_row):
                QMessageBox.warning(
                    None,
                    QCoreApplication.translate('RAT', "Error Removing Row"),
                    QCoreApplication.translate(
                        'RAT',
                        "An error occourred while removing a row from the RAT!"
                    ))

    def allowedAddedUsages(self) -> list:
        """Return the list of not-color usages that can be added

        :return: allowed usages that can be added
        :rtype: list
        """

        allowed_usages = []
        usages = self.model.rat.field_usages
        for usage, info in rat_supported_column_info().items():
            if not info['is_color'] and (not info['unique']
                                         or usage not in usages):
                allowed_usages.append(usage)

        return allowed_usages

    def canAddAnyColumn(self) -> bool:
        """Check if any column can be added"""

        return not self.model.has_color or len(self.allowedAddedUsages()) > 0

    def addColumn(self):

        dlg = AddColumnDialog(self.model, self.iface)

        if self.model.has_color:
            dlg.mColumnType.hide()

        # List columns where insertion is allowed: skip value and count
        for field in self.model.rat.fields.values():
            if field.usage not in {gdal.GFU_MinMax, gdal.GFU_PixelCount}:
                dlg.mColumn.addItem(field.name)

        # List allowed usages
        allowed_usages = self.allowedAddedUsages()

        # Set insertion point
        col = self.proxyModel.mapToSource(
            self.mRATView.selectionModel().currentIndex()).column()
        header = self.model.headers[col]
        dlg.mColumn.setCurrentIndex(dlg.mColumn.findText(header))

        if not allowed_usages:
            if not self.model.has_color:
                dlg.mColor.setChecked(True)
                dlg.mStandardColumn.setEnabled(False)
            else:  # We cannot add any field, we should never get here!
                rat_log(
                    'Cannot add any column: this should have been checked before getting so far!',
                    Qgis.Critical)

        else:
            usages_info = rat_column_info()
            for usage in allowed_usages:
                dlg.mUsage.addItem(usages_info[usage]['name'], usage)

        if dlg.exec_() == QDialog.Accepted:
            position = dlg.mColumn.currentText()
            after = dlg.mAfter.isChecked()
            insertion_point = self.model.headers.index(position) + (1 if after
                                                                    else 0)

            if dlg.mColor.isChecked():
                if not self.model.insert_color(insertion_point):
                    QMessageBox.warning(
                        None,
                        QCoreApplication.translate('RAT',
                                                   "Error Adding Colors"),
                        QCoreApplication.translate(
                            'RAT',
                            "An error occourred while adding colors to the RAT!"
                        ))
                else:
                    # Try to update colors from current raster
                    self.model.rat.update_colors_from_raster(self.raster_layer)
                    self.is_dirty = True

            else:
                data_type = dlg.mDataType.currentData()
                usage = dlg.mUsage.currentData()
                name = dlg.mName.text()
                field = RATField(name, usage, data_type)
                result, error_message = self.model.insert_column(
                    insertion_point, field)
                if not result:
                    QMessageBox.warning(
                        None,
                        QCoreApplication.translate('RAT',
                                                   "Error Adding Column"),
                        QCoreApplication.translate(
                            'RAT',
                            "An error occourred while adding a column to the RAT: %s"
                            % error_message))
                else:
                    self.is_dirty = True

    def columnIsColor(self, column_name) -> bool:

        return (column_name == RAT_COLOR_HEADER_NAME
                ) or self.model.rat.fields[column_name].is_color

    def selectedColumnCanBeRemoved(self) -> bool:

        selected_column = self.mRATView.selectionModel().currentIndex().column(
        )
        column_can_be_removed = False
        try:
            column_name = self.model.headers[selected_column]
            usage = self.model.rat.fields[column_name].usage
            if self.columnIsColor(column_name) or usage in {gdal.GFU_Generic}:
                column_can_be_removed = True
            elif usage == gdal.GFU_Name:
                # Check if it's not the only one
                names_count = len([
                    field for field in self.model.rat.fields.values()
                    if field.usage == gdal.GFU_Name
                ])
                if names_count > 1:
                    column_can_be_removed = True
        except Exception as ex:
            rat_log('Could not get selected column type: %s' % ex)

        return column_can_be_removed

    def removeColumn(self):

        if not self.selectedColumnCanBeRemoved():
            rat_log('Selected column cannot be removed!')
        else:
            selected_column = self.mRATView.selectionModel().currentIndex(
            ).column()
            column_name = self.model.headers[selected_column]

            # Handle color columns
            if self.columnIsColor(column_name):
                if QMessageBox.question(
                        None,
                        QCoreApplication.translate('RAT', "Remove All Colors"),
                        QCoreApplication.translate(
                            'RAT',
                            "<p>All color information (Red, Green, Blue and Alpha) will be removed from the RAT.</p><p>Do you want continue?</p>"
                        )) == QMessageBox.Yes:
                    # Remove all colors
                    if not self.model.remove_color():
                        QMessageBox.warning(
                            None,
                            QCoreApplication.translate(
                                'RAT', "Error Removing Colors"),
                            QCoreApplication.translate(
                                'RAT',
                                "An error occourred while removing colors from the RAT!"
                            ))
                    else:
                        self.is_dirty = True

            # Normal columns
            elif QMessageBox.question(
                    None, QCoreApplication.translate('RAT', "Remove Column"),
                    QCoreApplication.translate(
                        'RAT',
                        "Column <b>%s</b> will be removed from the RAT. Do you want continue?"
                        % column_name)) == QMessageBox.Yes:
                result, error_message = self.model.remove_column(
                    selected_column)
                if not result:
                    QMessageBox.warning(
                        None,
                        QCoreApplication.translate('RAT',
                                                   "Error Removing Column"),
                        QCoreApplication.translate(
                            'RAT',
                            "An error occourred while removing colum <b>%s</b> from the RAT: %s!"
                            % (column_name, error_message)))
                else:
                    self.is_dirty = True

    def updateButtons(self):

        enable_editing_buttons = self.mRATView.selectionModel().currentIndex(
        ).isValid() and self.editable

        self.mAddColumnToolButton.setEnabled(enable_editing_buttons
                                             and self.canAddAnyColumn())
        self.mRemoveColumnToolButton.setEnabled(enable_editing_buttons)
        self.mAddRowToolButton.setEnabled(enable_editing_buttons)
        self.mRemoveRowToolButton.setEnabled(enable_editing_buttons)
        self.mSaveChangesToolButton.setEnabled(self.is_dirty)

    def setEditable(self, editable):

        if not editable and self.is_dirty:
            if QMessageBox.question(
                    None, QCoreApplication.translate('RAT',
                                                     "Save RAT changes"),
                    QCoreApplication.translate(
                        'RAT',
                        "RAT has been modified, Do you want to save the changes?"
                    )) == QMessageBox.Yes:
                self.saveChanges()
            else:
                self.loadRat(self.mRasterBandsComboBox.currentIndex())

        self.editable = editable
        self.model.setEditable(editable)
        self.updateButtons()

    def saveChanges(self):
        """Store changes back into the RAT"""

        rat = self.model.rat
        band = self.mRasterBandsComboBox.currentIndex() + 1
        if rat.save(band):
            self.is_dirty = False

    def accept(self):
        QgsSettings().setValue("RasterAttributeTable/geometry",
                               self.saveGeometry(), QgsSettings.Plugins)
        super().accept()

    def reject(self):

        if not self.is_dirty or QMessageBox.question(
                None, QCoreApplication.translate('RAT', "Save RAT changes"),
                QCoreApplication.translate(
                    'RAT',
                    "<p>RAT has been modified, if you do not save the changes now or export the RAT they will be lost.</p><p>Exit without saving?<p>"
                )) == QMessageBox.Yes:
            self.accept()

    def classify(self):
        """Create classification on the selected criteria"""

        if QMessageBox.question(
                None,
                QCoreApplication.translate('RAT', "Overwrite classification"),
                QCoreApplication.translate(
                    'RAT',
                    "The existing classification will be overwritten, do you want to continue?"
                )) == QMessageBox.Yes:
            band = self.mRasterBandsComboBox.currentIndex() + 1
            criteria = self.mClassifyComboBox.currentText()
            # TODO: ramp & feedback
            unique_class_row_indexes = rat_classify(self.raster_layer, band,
                                                    self.rat, criteria)
            unique_class_row_indexes.insert(0, 0)
            if self.iface is not None:
                deduplicate_legend_entries(self.iface,
                                           self.raster_layer,
                                           criteria,
                                           unique_class_row_indexes,
                                           expand=True)
            # Adopt the layer
            self.raster_layer.setCustomProperty(
                RAT_CUSTOM_PROPERTY_CLASSIFICATION_CRITERIA, criteria)

    def updateClassify(self):

        current_index = self.mClassifyComboBox.currentIndex()
        self.mClassifyComboBox.clear()
        self.mClassifyComboBox.addItems([
            field.name for field in self.rat.fields.values()
            if field.usage in {gdal.GFU_Name, gdal.GFU_Generic}
        ])

        if current_index > 0:
            self.mClassifyComboBox.setCurrentIndex(current_index)
        else:
            headers = self.rat.keys
            criteria = self.raster_layer.customProperty(
                RAT_CUSTOM_PROPERTY_CLASSIFICATION_CRITERIA)
            if criteria in headers:
                self.mClassifyComboBox.setCurrentIndex(
                    self.mClassifyComboBox.findText(criteria))

    def dirty(self, *args):

        self.is_dirty = True
        rat_log('Model is dirty')
        self.updateButtons()

    def loadRat(self, band_0_based) -> bool:
        """Load RAT for raster band 0-based"""

        if type(band_0_based) != int:
            rat_log(
                QCoreApplication.translate(
                    'RAT', 'Invalid band number for the selected raster.'),
                Qgis.Critical)
            return False

        self.mClassifyComboBox.clear()

        self.rat = get_rat(self.raster_layer, band_0_based + 1)

        if self.rat.keys:
            self.model = RATModel(self.rat)
            if os.environ.get('CI'):
                self.tester = QAbstractItemModelTester(self.model)
            self.model.dataChanged.connect(self.dirty)
            self.model.rowsInserted.connect(self.dirty)
            self.model.rowsRemoved.connect(self.dirty)
            self.model.columnsInserted.connect(self.dirty)
            self.model.columnsRemoved.connect(self.dirty)
            self.model.columnsInserted.connect(self.updateClassify)
            self.model.columnsRemoved.connect(self.updateClassify)
            self.proxyModel = QSortFilterProxyModel(self)
            self.proxyModel.setSourceModel(self.model)
            self.mRATView.setModel(self.proxyModel)
            self.mRATView.selectionModel().selectionChanged.connect(
                self.updateButtons)

            # Color picker
            if self.rat.has_color:
                if gdal.GFU_Alpha in self.rat.field_usages:
                    colorDelegate = ColorAlphaDelegate(self.mRATView)
                else:
                    colorDelegate = ColorDelegate(self.mRATView)
                self.mRATView.setItemDelegateForColumn(0, colorDelegate)

            self.updateClassify()
            self.mRATView.sortByColumn(
                self.model.headers.index(self.rat.value_columns[0]),
                Qt.AscendingOrder)
            return True
        else:
            rat_log(
                QCoreApplication.translate(
                    'RAT',
                    'There is no Raster Attribute Table for the selected raster.'
                ), Qgis.Critical)
            return False
Esempio n. 28
0
class ConfigurationDialog(QDialog, Ui_Configuration, SettingDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setupUi(self)
        self.settings = MySettings()
        SettingDialog.__init__(self, self.settings)

        # new declaration of ProjectFinder since changes can be cancelled
        self.project_finder = ProjectFinder(self)

        # table model
        self.project_search_model = ProjectSearchModel(self.project_finder)

        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setSourceModel(self.project_search_model)
        self.projectSearchTable.setModel(self.proxyModel)

        header = self.projectSearchTable.horizontalHeader()
        #        header.setResizeMode(QHeaderView.ResizeToContents)
        header.setSectionResizeMode(QHeaderView.ResizeToContents)

        # open/create QuickFinder file
        self.createFileButton.clicked.connect(self.create_QFTS_file)
        self.openFileButton.clicked.connect(self.open_QFTS_file)
        self.read_QFTS_file()

        # project search
        self.addSearchButton.clicked.connect(self.add_project_search)
        self.removeSearchButton.clicked.connect(self.remove_project_search)
        self.editSearchButton.clicked.connect(self.edit_project_search)
        self.refreshButton.clicked.connect(self.refresh_project_search)
        self.projectSearchTable.selectionModel().selectionChanged.connect(
            self.enableButtons)
        self.enableButtons()

    def reject(self):
        if self.close_and_control():
            QDialog.reject(self)

    def accept(self):
        if self.close_and_control():
            QDialog.accept(self)

    def close_and_control(self):
        self.project_finder.close()
        for search in list(self.project_finder.searches.values()):
            if search.dateEvaluated is None:
                box = QMessageBox(
                    QMessageBox.Warning, "Quick Finder",
                    QCoreApplication.translate(
                        "Configuration dialog",
                        "Some searches are still not recorded to the file. Do you want to record them now ? "
                    ),
                    QMessageBox.Cancel | QMessageBox.Yes | QMessageBox.Close,
                    self)
                ret = box.exec_()
                if ret == QMessageBox.Cancel:
                    return False
                elif ret == QMessageBox.Yes:
                    self.refresh_project_search()
                    return False
        return True

    def read_QFTS_file(self):
        filepath = self.qftsfilepath.text()
        self.project_finder.setFile(filepath)
        self.projectSearchTable.setEnabled(self.project_finder.isValid)
        self.projectSearchButtonsWidget.setEnabled(self.project_finder.isValid)

    def create_QFTS_file(self):
        prjPath = QgsProject.instance().homePath()
        filepath, __ = QFileDialog.getSaveFileName(
            self, "Create Quickfinder index file", prjPath,
            "Quickfinder file (*.qfts)")
        if filepath:
            if filepath[-5:] != ".qfts":
                filepath += ".qfts"
            if path.isfile(filepath):
                remove(filepath)
            create_FTS_file(filepath)
            self.qftsfilepath.setText(filepath)
            self.read_QFTS_file()

    def open_QFTS_file(self):
        prjPath = QgsProject.instance().homePath()
        filepath, __ = QFileDialog.getOpenFileName(
            self, "Open Quickfinder index file", prjPath,
            "Quickfinder file (*.qfts)")
        if filepath:
            self.qftsfilepath.setText(filepath)
            self.read_QFTS_file()

    def add_project_search(self):
        ProjectSearchDialog(self.project_finder,
                            self.project_search_model).exec_()

    def remove_project_search(self):
        sel = self.selected_search_ids()
        if len(sel) == 0:
            return
        box = QMessageBox(
            QMessageBox.Warning, "Quick Finder",
            QCoreApplication.translate(
                "Configuration dialog",
                "Are you sure to remove {0} search(es) ? ").format(len(sel)),
            QMessageBox.Yes | QMessageBox.Cancel, self)
        ret = box.exec_()
        if ret == QMessageBox.Cancel:
            return
        self.project_search_model.removeSearches(sel)

    def edit_project_search(self):
        sel = self.selected_search_ids()
        if len(sel) != 1:
            return
        if sel[0] not in self.project_search_model.searches:
            return
        search = self.project_search_model.searches[sel[0]]
        if search:
            ProjectSearchDialog(self.project_finder, self.project_search_model,
                                search).exec_()

    def refresh_project_search(self):
        RefreshDialog(self.project_finder, self.project_search_model,
                      self.selected_search_ids()).exec_()

    def selected_search_ids(self):
        selectedSearchId = []
        for idx in self.projectSearchTable.selectionModel().selectedRows():
            selectedSearchId.append(self.proxyModel.data(idx, SearchIdRole))
        return selectedSearchId

    def remove_postgis_search(self):
        sel = self.selected_postgis_search_ids()
        if len(sel) == 0:
            return
        box = QMessageBox(
            QMessageBox.Warning, "Quick Finder",
            QCoreApplication.translate(
                "Configuration dialog",
                "Are you sure to remove {0} search(es) ? ").format(len(sel)),
            QMessageBox.Yes | QMessageBox.Cancel, self)
        ret = box.exec_()
        if ret == QMessageBox.Cancel:
            return
        self.postgis_search_model.removeSearches(sel)

    def dbConnectionList(self):
        connection_names = []
        settings = QSettings()
        settings.beginGroup(u"/PostgreSQL/connections")
        for name in settings.childGroups():
            connection_names.append(name)
        settings.endGroup()
        return connection_names

    def enableButtons(self):
        n = len(self.selected_search_ids())
        self.removeSearchButton.setEnabled(n > 0)
        self.editSearchButton.setEnabled(n == 1)
        self.projectSearchButtonsWidget.setEnabled(self.project_finder.isValid)

    def geomapfishCrsButtonClicked(self):
        dlg = QgsProjectionSelectionTreeWidget(self)
        dlg.setMessage('Select GeoMapFish CRS')
        dlg.setSelectedAuthId(self.geomapfishCrs.text())
        if dlg.exec_():
            self.geomapfishCrs.setText(dlg.selectedAuthId())