Ejemplo n.º 1
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))
Ejemplo n.º 2
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 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()
Ejemplo n.º 4
0
class SPAQLunicornDialog(QtWidgets.QDialog, FORM_CLASS):
    ## The triple store configuration file
    triplestoreconf = None
    ## Prefix map
    prefixes = None

    enrichtab = None

    interlinktab = None

    conceptList = None

    completerClassList = None

    columnvars = {}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        self._initGui()

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

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

        self.gh = geometryHelper(self.iface)

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        wfsUri = makeWFSuri(url, layerName, crs )

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

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