Exemplo 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)
Exemplo n.º 2
0
    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 __init__(self, parent):
        """Constructor for the model.

        :param parent: Parent widget of this model.
        :type parent: QWidget
        """
        QSortFilterProxyModel.__init__(self, parent)
Exemplo n.º 4
0
    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()
Exemplo n.º 5
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
    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
Exemplo n.º 7
0
    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)
Exemplo n.º 8
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[str].connect(self.pFilterModel.setFilterFixedString)
    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)
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
    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)
Exemplo n.º 12
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)
Exemplo n.º 13
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)
Exemplo n.º 14
0
def set_autocompleter(combobox, list_items=None):
    """ Iterate over the items in the QCombobox, create a list,
        create the model, and set the model according to the list
    """

    if list_items is None:
        list_items = [combobox.itemText(i) for i in range(combobox.count())]
    proxy_model = QSortFilterProxyModel()
    set_model_by_list(list_items, combobox, proxy_model)
    combobox.editTextChanged.connect(partial(filter_by_list, combobox, proxy_model))
Exemplo n.º 15
0
    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())
Exemplo n.º 16
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)
Exemplo n.º 17
0
    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)
Exemplo n.º 18
0
    def __init__(self, parent=None):
        super(DsgCustomComboBox, self).__init__(parent=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)
Exemplo n.º 19
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
Exemplo n.º 20
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))
Exemplo n.º 21
0
    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)
Exemplo n.º 22
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)
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)
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
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)
    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()
Exemplo n.º 27
0
 def makeProxyModel(self, model):
     proxyModel = QSortFilterProxyModel()
     proxyModel.setDynamicSortFilter(True)
     proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive)
     proxyModel.setSourceModel(model)
     return proxyModel
Exemplo n.º 28
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()
Exemplo n.º 29
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)
Exemplo n.º 30
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()
 def index(self, row, column, parent):
     new_idx = QSortFilterProxyModel.index(self, row, self.LAYER_COL, parent)
     if column == self.LAYER_COL:
         return new_idx
     idx = self.createIndex(row, column, new_idx.internalId())
     return idx
Exemplo n.º 32
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()
 def parent(self, child):
     return QSortFilterProxyModel.parent(self, self.createIndex(child.row(), self.LAYER_COL, child.internalId()))