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

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

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

            self.jobs_view.selectionModel().selectionChanged.connect(
                self.selection_changed)
Esempio n. 2
0
    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
Esempio n. 3
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)
Esempio n. 4
0
    def searchModel(self, columnIndex, columnValue):
        '''
        Searches for 'columnValue' in the column whose index is specified by 'columnIndex' in all
        rows contained in the model.
        '''
        if isinstance(columnValue, QVariant):
            columnValue = str(columnValue.toString())

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

        columnValue = columnValue.strip()

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

        return matchingIndex
Esempio n. 5
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 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
    def refresh_model(self, source_model, db_connector=None, silent=False):

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

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

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

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

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

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

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

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

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


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

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

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

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

        return True
Esempio n. 9
0
class DlgDownload(DlgCalculateBase, Ui_DlgDownload):
    def __init__(self, parent=None):
        """Constructor."""
        super(DlgDownload, self).__init__(parent)

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

        self.settings = QSettings()

        self.setupUi(self)

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

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

        self.update_data_table()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self.close()

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

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

            if resp:
                mb.pushMessage(self.tr("Success"),
                               self.tr("Download request submitted to Google Earth Engine."),
                               level=0, duration=5)
            else:
                mb.pushMessage(self.tr("Error"),
                               self.tr("Unable to submit download request to Google Earth Engine."),
                               level=0, duration=5)
Esempio n. 10
0
class DlgJobs(QtWidgets.QDialog, Ui_DlgJobs):
    # When a connection to the api starts, emit true. When it ends, emit False
    connectionEvent = pyqtSignal(bool)

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

        self.setupUi(self)

        self.connection_in_progress = False

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

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

        self.connectionEvent.connect(self.connection_event_changed)

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

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

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

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

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

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

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

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

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

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

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

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

        self.connectionEvent.emit(False)
        return False

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

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

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

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

        details_dlg = DlgJobsDetails(self)

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

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

        details_dlg.show()
        details_dlg.exec_()

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

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

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

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

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

        self.close()

        for row, f in zip(rows, filenames):
            job = self.jobs[row]
            log(u"Processing job {}.".format(job.get('id', None)))
            result_type = job['results'].get('type')
            if result_type == 'CloudResults':
                download_cloud_results(job, f, self.tr)
            elif result_type == 'TimeSeriesTable':
                download_timeseries(job, self.tr)
            else:
                raise ValueError(
                    "Unrecognized result type in download results: {}".format(
                        result_type))
class geopunt4QgisDataCatalog(QDialog):
    def __init__(self, iface):
        QDialog.__init__(self, None)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.iface = iface

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

        self._initGui()

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

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

        self.gh = geometryHelper(self.iface)

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        wfsUri = makeWFSuri(url, layerName, crs )

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

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