Beispiel #1
0
class SQLiteCompleterText(QTextEdit):
    def __init__(self, parent=None):
        super(SQLiteCompleterText, self).__init__(parent)
        self.cp = QCompleter(words)
        self.cp.setWrapAround(False)
        self.cp.setWidget(self)
        self.cp.setCompletionMode(QCompleter.PopupCompletion)
        self.cp.activated.connect(self.insertCompletion)

    def insertCompletion(self, completion):
        tc = self.textCursor()
        extra = len(completion) - len(self.cp.completionPrefix())
        tc.movePosition(QTextCursor.Left)
        tc.movePosition(QTextCursor.EndOfWord)
        tc.insertText(completion[-extra:])
        self.setTextCursor(tc)

    def textUnderCursor(self):
        tc = self.textCursor()
        tc.select(QTextCursor.WordUnderCursor)
        return tc.selectedText()

    def focusInEvent(self, e):
        self.cp.setWidget(self)
        super(SQLiteCompleterText, self).focusInEvent(e)

    def keyPressEvent(self, e):
        if self.cp.popup().isVisible():
            if e.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab, Qt.Key_Backtab):
                e.ignore()
                return

        is_shortcut = ((e.modifiers() & Qt.ControlModifier) != 0 and e.key() == Qt.Key_E & Qt.ControlModifier)
        if not is_shortcut:
            super(SQLiteCompleterText, self).keyPressEvent(e)

        ctrl_or_shift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
        if ctrl_or_shift and len(e.text()) == 0:
            return

        eo = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="
        has_modifier = (e.modifiers() != Qt.NoModifier) and not ctrl_or_shift
        cp = self.textUnderCursor()

        if not is_shortcut and (cp in words or has_modifier or len(e.text()) == 0 or len(cp) < 1 or e.text()[-1] in eo):
            self.cp.popup().hide()
            return

        if cp != self.cp.completionPrefix():
            self.cp.setCompletionPrefix(cp)
            self.cp.popup().setCurrentIndex(self.cp.completionModel().index(0, 0))

        cr = self.cursorRect()
        cr.setWidth(self.cp.popup().sizeHintForColumn(0) + self.cp.popup().verticalScrollBar().sizeHint().width())
        self.cp.complete(cr)
Beispiel #2
0
class CompletingTextEdit(QTextEdit):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.completerSequence = QKeySequence("Ctrl+Space")

        self._completer = QCompleter()
        self._completer.setWidget(self)
        self._completer.activated.connect(self.insertCompletion)

    def insertCompletion(self, completion):
        if self._completer.widget() is not self:
            return

        tc = self.textCursor()
        extra = len(completion) - len(self._completer.completionPrefix())
        tc.movePosition(QTextCursor.Left)
        tc.movePosition(QTextCursor.EndOfWord)
        tc.insertText(completion[-extra:])
        self.setTextCursor(tc)

    def textUnderCursor(self):
        tc = self.textCursor()
        tc.select(QTextCursor.WordUnderCursor)

        return tc.selectedText()

    def loadFromFile(self, fileName):
        f = QFile(fileName)
        if not f.open(QFile.ReadOnly):
            model = QStringListModel()
            self._completer.setModel(model)

        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))

        words = []
        while not f.atEnd():
            line = f.readLine().trimmed()
            if line.length() != 0:
                try:
                    line = str(line, encoding='utf-8')
                except TypeError:
                    line = str(line)

                words.append(line)

        QApplication.restoreOverrideCursor()

        model = QStringListModel(words)
        self._completer.setModel(model)

    def loadFromList(self, words):
        model = QStringListModel(words)
        self._completer.setModel(model)

    def keyPressEvent(self, e):
        if self._completer.popup().isVisible():
            # The following keys are forwarded by the completer to the widget.
            if e.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape,
                           Qt.Key_Tab, Qt.Key_Backtab):
                e.ignore()
                # Let the completer do default behavior.
                return

        newSeq = QKeySequence(e.modifiers() | e.key())
        isShortcut = newSeq == self.completerSequence

        if not isShortcut:
            # Do not process the shortcut when we have a completer.
            super().keyPressEvent(e)
            return

        ctrlOrShift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
        if ctrlOrShift and not e.text():
            return

        eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="
        hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
        completionPrefix = self.textUnderCursor()

        if not isShortcut and (hasModifier or not e.text()
                               or len(completionPrefix) < 3
                               or e.text()[-1] in eow):
            self._completer.popup().hide()
            return

        if completionPrefix != self._completer.completionPrefix():
            self._completer.setCompletionPrefix(completionPrefix)
            self._completer.popup().setCurrentIndex(
                self._completer.completionModel().index(0, 0))

        cr = self.cursorRect()
        cr.setWidth(
            self._completer.popup().sizeHintForColumn(0) +
            self._completer.popup().verticalScrollBar().sizeHint().width())
        self._completer.complete(cr)
Beispiel #3
0
class TextStatusEditComplete(TextStatusEdit):
    """ Adds Completion functions to the base class

    This class extends 'TextStatusEdit' by:

    1.  providing a QCompleter to validate lines for the
        'fixupText' and 'lineChanged' signals
    2.  providing a popup for suggested completions as
        the user is typing
    3.  auto-completing the line when the user selects
        a suggestion.

    The task of auto completion and providing suggestions
    is provided directly by this class.

    The task validating and cleaning up text is provided by
    the PluginFinder.
    """
    def __init__(self, parent: QWidget = None):
        super().__init__(parent)
        self._dataModel = None
        self._monitorDbChanges = False
        self._enableAutoCompletion = False
        self._completedAndSelected = False
        self._completer = QCompleter(self)

        self._completer.setWidget(self)
        self._completer.setWrapAround(False)
        self._completer.setCompletionMode(QCompleter.PopupCompletion)
        self._completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._completer.setFilterMode(Qt.MatchStartsWith)
        self._completer.setModelSorting(
            QCompleter.CaseInsensitivelySortedModel)
        self._completer.activated.connect(self.replaceLine)

        self._pluginFinder = PluginFinder(self._completer, self)
        self.fixupText.connect(self._pluginFinder.fixupText)
        self.lineChanged.connect(self._pluginFinder.setRowForLine)

        QShortcut(Qt.CTRL + Qt.Key_E, self, self.toggleAutoCompletion)
        QShortcut(Qt.CTRL + Qt.Key_T, self, self.suggestCompletions)

    # --- Methods related to the completer's underlying data model

    def setModel(self, model: QAbstractItemModel):
        self._completer.setModel(model)

    def _updateModelSignals(self):
        """ We do not need to check for column changes due to
        the way our PluginModel is structured. """

        if self._dataModel is not None:
            self._dataModel.rowsMoved.disconnect(self.resetData)
            self._dataModel.rowsInserted.disconnect(self.resetData)
            self._dataModel.rowsRemoved.disconnect(self.resetData)
            self._dataModel.modelReset.disconnect(self.resetData)
            self._dataModel.dataChanged.disconnect(self.resetData)
            self._dataModel.layoutChanged.disconnect(self.resetData)

        if self._monitorDbChanges:
            self._dataModel = self._completer.model()
            if self._dataModel is not None:
                self._dataModel.rowsMoved.connect(self.resetData)
                self._dataModel.rowsInserted.connect(self.resetData)
                self._dataModel.rowsRemoved.connect(self.resetData)
                self._dataModel.modelReset.connect(self.resetData)
                self._dataModel.dataChanged.connect(self.resetData)
                self._dataModel.layoutChanged.connect(self.resetData)
        else:
            self._dataModel = None

    def monitorDbChanges(self, enable: bool):
        """ Enable invalidating line status when
        the data model changes.

        Depending on the underlying data model, it may
        be unnecessary to monitor these changes, or, a
        higher level class can monitor specific signals
        more efficiently.  So, this is not enabled
        by default.  """

        if self._monitorDbChanges == enable:
            return

        self._monitorDbChanges = enable
        if enable:
            self._dataModel = self._completer.model()
            self._completer.completionModel().sourceModelChanged.connect(
                self._updateModelSignals)
        else:
            self._completer.completionModel().sourceModelChanged.disconnect(
                self._updateModelSignals)
        self._updateModelSignals()

    # ---- Methods related to line completion

    def completer(self):
        return self._completer

    def enableAutoCompletion(self, enable: bool):
        self._enableAutoCompletion = enable

    def toggleAutoCompletion(self):
        self.enableAutoCompletion(not self._enableAutoCompletion)

    def _textUnderCursor(self):
        tc = self.textCursor()
        if tc.positionInBlock() == 0 and len(tc.block().text()) > 1:
            tc.movePosition(QTextCursor.NextCharacter)
        tc.movePosition(QTextCursor.StartOfLine, QTextCursor.KeepAnchor)
        return tc.selectedText().lstrip()

    def suggestCompletions(self):
        if self.isLineInvalid(self.textCursor().blockNumber()):
            self._suggestCompletionsForText(self._textUnderCursor())

    def _suggestCompletionsForText(self, prefix: str):
        if not prefix:
            return
        if prefix != self._completer.completionPrefix():
            self._completer.setCompletionPrefix(prefix)
            self._completer.popup().setCurrentIndex(
                self._completer.completionModel().index(0, 0))
        if self._completer.completionCount() == 1:
            self._insertSuggestion(self._completer.currentCompletion())
        else:
            rect = self.cursorRect()
            rect.moveRight(self.statusAreaWidth())
            rect.setWidth(
                self._completer.popup().sizeHintForColumn(
                    self._completer.completionColumn()) +
                self._completer.popup().verticalScrollBar().sizeHint().width())
            self._completer.complete(rect)

    def _insertSuggestion(self, text: str):
        """ Only one suggestion matched, prefill line """

        cursor = self.textCursor()
        # handle when cursor is in middle of line
        if not cursor.atBlockEnd():
            cursor.beginEditBlock()
            cursor.select(QTextCursor.LineUnderCursor)
            cursor.removeSelectedText()
            cursor.insertText(text)
            cursor.movePosition(QTextCursor.StartOfLine)
            cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
            self._completedAndSelected = True
            self.setTextCursor(cursor)
            cursor.endEditBlock()
            return

        # handle when cursor at end of line
        cursor.beginEditBlock()
        numCharsToComplete = len(text) - len(
            self._completer.completionPrefix())
        insertionPosition = cursor.position()
        cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
        cursor.removeSelectedText()
        cursor.insertText(text[-numCharsToComplete:])
        cursor.setPosition(insertionPosition)
        cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
        self._completedAndSelected = True
        self.setTextCursor(cursor)
        cursor.endEditBlock()

    def keyPressEvent(self, event: QKeyEvent):
        if self._completedAndSelected and self.handledCompletedAndSelected(
                event):
            return

        self._completedAndSelected = False
        if self._completer.popup().isVisible():
            ignoredKeys = [
                Qt.Key_Up,
                Qt.Key_Down,
                Qt.Key_Enter,
                Qt.Key_Return,
                Qt.Key_Tab,
                Qt.Key_Escape,
            ]
            if event.key() in ignoredKeys:
                event.ignore()
                return
            self._completer.popup().hide()

        super().keyPressEvent(event)
        if not self._enableAutoCompletion:
            return

        ctrlOrShift = (event.modifiers() & Qt.ShiftModifier == Qt.ShiftModifier
                       or event.modifiers() & Qt.ControlModifier
                       == Qt.ControlModifier)

        if ctrlOrShift and not event.text():
            return

        if self.textCursor().atBlockEnd():
            self.suggestCompletions()

    def mousePressEvent(self, event: QMouseEvent):
        if self._completedAndSelected:
            self._completedAndSelected = False
            self.document().undo()
        super().mousePressEvent(event)

    def handledCompletedAndSelected(self, event: QKeyEvent):
        """ The line is prefilled when only one completion matches. The user
        can accept the suggestion by pressing 'Enter'. The user can reject
        the suggestion by pressing 'Esc' or by continuing to type. """

        self._completedAndSelected = False
        cursor = self.textCursor()
        acceptKeys = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Tab]
        if event.key() in acceptKeys:
            self.replaceLine(self._completer.currentCompletion())
        elif event.key() == Qt.Key_Escape:
            self.document().undo()
        else:
            self.document().undo()
            return False

        self.setTextCursor(cursor)
        event.accept()
        return True

    def replaceLine(self, text: str):
        cursor = self.textCursor()
        cursor.beginEditBlock()
        cursor.select(QTextCursor.LineUnderCursor)
        cursor.removeSelectedText()
        cursor.insertText(text)
        cursor.movePosition(QTextCursor.EndOfLine)
        self.setTextCursor(cursor)
        cursor.endEditBlock()

    # ---- Methods related to Context Menu

    def createStandardContextMenu(self, pos: QPoint):
        menu = super().createStandardContextMenu(pos)
        menu.addSeparator()
        autoCompletionAction = menu.addAction(
            QIcon(),
            self.tr("Enable Auto Complete"),
            self.toggleAutoCompletion,
            QKeySequence(Qt.CTRL + Qt.Key_E),
        )
        autoCompletionAction.setCheckable(True)
        autoCompletionAction.setChecked(self._enableAutoCompletion)

        completionAction = menu.addAction(
            QIcon(),
            self.tr("Suggest Completions"),
            self.suggestCompletions,
            QKeySequence(Qt.CTRL + Qt.Key_T),
        )
        completionAction.setEnabled(
            self.isLineInvalid(self.textCursor().blockNumber()))
        return menu
class DiscoveryPlugin:
    def __init__(self, _iface):
        # Save reference to the QGIS interface
        self.iface = _iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # Variables to facilitate delayed queries and database connection management
        self.icon_loading = ':plugins/_Discovery_sqlite/icons/loading.gif'
        self.db_timer = QTimer()
        self.line_edit_timer = QTimer()
        self.line_edit_timer.setSingleShot(True)
        self.line_edit_timer.timeout.connect(self.reset_line_edit_after_move)
        self.next_query_time = None
        self.last_query_time = time.time()
        self.db_conn = None
        self.search_delay = 0.5  # s
        self.query_sql = ''
        self.query_text = ''
        self.query_dict = {}
        self.db_idle_time = 60.0  # s

        self.search_results = []
        self.tool_bar = None
        self.search_line_edit = None
        self.completer = None

        self.marker = QgsVertexMarker(iface.mapCanvas())
        self.marker.setIconSize(15)
        self.marker.setPenWidth(2)
        self.marker.setColor(QColor(226, 27, 28))  #51,160,44))
        self.marker.setZValue(11)
        self.marker.setVisible(False)
        self.marker2 = QgsVertexMarker(iface.mapCanvas())
        self.marker2.setIconSize(16)
        self.marker2.setPenWidth(4)
        self.marker2.setColor(QColor(255, 255, 255, 200))
        self.marker2.setZValue(10)
        self.marker2.setVisible(False)

    def initGui(self):

        # Create a new toolbar
        self.tool_bar = self.iface.addToolBar(u'Панель поиска')
        self.tool_bar.setObjectName('Discovery_sqlite_Plugin')

        # Add search edit box
        self.search_line_edit = QgsFilterLineEdit()
        self.search_line_edit.setSelectOnFocus(True)
        self.search_line_edit.setShowSearchIcon(True)
        self.search_line_edit.setPlaceholderText(
            u'Поиск адреса или участка...')
        # self.search_line_edit.setMaximumWidth(768)
        self.tool_bar.addWidget(self.search_line_edit)

        # loading indicator
        self.load_movie = QMovie()
        self.label_load = QLabel()
        self.tool_bar.addWidget(self.label_load)

        # Set up the completer
        model = QStandardItemModel()
        self.completer = QCompleter([])  # Initialise with en empty list
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setMaxVisibleItems(30)
        self.completer.setModelSorting(
            QCompleter.UnsortedModel)  # Sorting done in PostGIS
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion
                                         )  # Show all fetched possibilities
        self.completer.setModel(model)
        tableView = QTableView()
        tableView.verticalHeader().setVisible(False)
        tableView.horizontalHeader().setVisible(False)
        tableView.setSelectionBehavior(QTableView.SelectRows)
        tableView.setShowGrid(False)
        # tableView.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        tableView.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
        fontsize = QFontMetrics(
            tableView.verticalHeader().font()).height() + 2  #font size
        tableView.verticalHeader().setDefaultSectionSize(
            fontsize)  #font size 15
        tableView.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        tableView.horizontalHeader().setStretchLastSection(True)
        tableView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.completer.setCompletionColumn(0)
        self.completer.setPopup(tableView)

        self.completer.activated[QModelIndex].connect(self.on_result_selected)
        self.completer.highlighted[QModelIndex].connect(
            self.on_result_highlighted)
        self.search_line_edit.setCompleter(self.completer)

        # Connect any signals
        self.search_line_edit.textEdited.connect(self.on_search_text_changed)
        self.search_line_edit.returnPressed.connect(self.returnPressed)

        self.read_config()

        # Search results
        self.search_results = []

        # Set up a timer to periodically perform db queries as required
        self.db_timer.timeout.connect(self.schedule_search)

    def read_config(self):
        qstring = ''
        self.data = self.settings_path()
        try:
            for line in self.data[1:]:
                words = line.split(';')
                postgissearchcolumn = words[2].strip()
                postgistable = words[0].strip()
                geomcolumn = words[3].strip()
                layername = words[4].strip()
                isSelect = int(words[5].strip())

                connection = sqlite3.connect(os.path.join(self.dbfile.strip()))

                cur = connection.cursor()

                qstring = u'select {2} from {0} where length({1})>0 LIMIT 1'.format(
                    postgistable, postgissearchcolumn, geomcolumn)
                cur.execute(qstring)
                connection.close()
            self.make_enabled(True)  # assume the config is invalid first
        except Exception as E:
            print(E)
            self.make_enabled(False)

    # включить или выключить поисковую строку в зависимости от результата проверки настроек
    def make_enabled(self, enabled):
        self.search_line_edit.setEnabled(enabled)
        self.search_line_edit.setPlaceholderText(
            u"Поиск адреса или участка..."
            if enabled else u"Поиск отключен: проверьте конфигурацию")

    def settings_path(self):
        p = os.path.join(self.plugin_dir, 'layers.ini')
        f = codecs.open(p, 'r', encoding='cp1251')
        data = f.readlines()

        dbfileline = data[0]
        if dbfileline[:2] == u'\\\\':
            self.dbfile = dbfileline
        elif dbfileline[1] == u':':
            self.dbfile = dbfileline
        else:
            self.dbfile = os.path.join(self.plugin_dir, dbfileline)
        f.close()
        return data

    def unload(self):
        self.db_timer.stop()
        self.db_timer.timeout.disconnect(self.schedule_search)
        self.completer.highlighted[QModelIndex].disconnect(
            self.on_result_highlighted)
        self.completer.activated[QModelIndex].disconnect(
            self.on_result_selected)
        self.search_line_edit.textEdited.disconnect(
            self.on_search_text_changed)
        self.search_line_edit.returnPressed.disconnect(self.returnPressed)
        self.tool_bar.clear()  # Clear all actions
        self.iface.mainWindow().removeToolBar(self.tool_bar)

    def clear_suggestions(self):
        model = self.completer.model()
        model.clear()
        # model.setStringList([])

    def returnPressed(self):
        if self.completer.popup().isHidden():
            self.do_search(self.search_line_edit.text())

    # def setLoading(self, isLoading):
    #     if self.label_load is None:
    #         return
    #     if isLoading:
    #         load_movie = QMovie()
    #         load_movie.setFileName(self.icon_loading)
    #         self.label_load.setMovie(load_movie)
    #         load_movie.start()
    #     else:
    #         load_movie = QMovie()
    #         load_movie.stop()
    #         self.label_load.setMovie(load_movie)

    def schedule_search(self):

        if self.next_query_time is not None and self.next_query_time < time.time(
        ):
            self.next_query_time = None  # Prevent this query from being repeated
            self.last_query_time = time.time()
            self.do_search(self.search_line_edit.text())
            self.db_timer.stop()
            # self.setLoading(False)
            self.search_line_edit.setShowSpinner(False)
        else:
            # self.setLoading(True)
            self.search_line_edit.setShowSpinner(True)
            if time.time() > self.last_query_time + self.db_idle_time:
                self.db_conn = None

    # def on_search_text_changed(self, new_search_text):
    def on_search_text_changed(self, new_search_text):
        # self.setLoading(False)
        self.search_line_edit.setShowSpinner(False)
        if len(new_search_text) < 3:
            self.db_timer.stop()
            self.clear_suggestions()
            return
        self.db_timer.start(300)
        self.next_query_time = time.time() + self.search_delay

    def do_search(self, new_search_text):

        if len(new_search_text) < 3:
            self.clear_suggestions()
            return

        self.clear_suggestions()

        self.query_text = new_search_text

        self.search_results = []
        self.suggestions = []

        for index, line in enumerate(self.data[1:]):
            curline_layer = line
            words = curline_layer.split(';')
            searchcolumn = words[2].strip()  # поле со значением для поиска
            postgistable = words[0].strip()  # таблица
            geomcolumn = words[3].strip()  # поле с геометрией
            layername = words[4].strip(
            )  # имя слоя в легенде для соответствий и выделения
            isSelect = int(
                words[5].strip())  # выделять ли объект в слое layername
            descript = words[1].strip(
            )  # описание. Выводится в списке результатов

            query_text, query_dict = self.get_search_sql(
                new_search_text, searchcolumn, postgistable)

            query_sql = query_text
            query_dict = query_dict
            self.perform_search(query_sql, query_dict, descript, postgistable,
                                layername, isSelect, searchcolumn)

        # QStringList - просто одна строка в выводе
        # if len(self.suggestions) > 0:
        #     model = self.completer.model()
        #     model.setStringList(self.suggestions)
        #     print(model)
        #     self.completer.complete()

        if len(self.suggestions) > 0:
            # model = self.completer.model()
            model = QStandardItemModel()
            font = QFont()
            font.setItalic(True)
            font.setPointSize(7)
            # заполняем модель
            for i, line in enumerate(self.suggestions):
                #icon
                pixmap = QPixmap(':plugins/_Discovery_sqlite/icons/' +
                                 line[2] + '.png')
                pixmap = pixmap.scaledToHeight(10)
                pixmap = pixmap.scaledToWidth(10)
                # itemImage = QStandardItem()
                # itemImage.setData(pixmap, Qt.DecorationRole)
                # model.setItem(i, 0, itemImage)

                itemLayer = QStandardItem(u"{1}[{0}]".format(
                    line[1], u' ' * 50))
                itemLayer.setFont(font)
                itemValue = QStandardItem(line[0])
                itemValue.setData(pixmap, Qt.DecorationRole)
                model.setItem(i, 0, itemValue)
                model.setItem(i, 1, itemLayer)

            self.completer.setModel(model)
            self.completer.complete()

        else:
            model = self.completer.model()
            # self.suggestions.append(u"<Не найдено>")   # для QStringList
            # model.setStringList(self.suggestions)   # для QStringList
            model.setItem(
                0, 0, QStandardItem('<Не найдено>'))  # для QStandardItemModel
            self.completer.complete()

    def perform_search(self, query_sql, query_dict, descript, tablename,
                       layername, isSelect, searchcolumn):
        cur = self.get_db_cur()
        cur.execute(query_sql, query_dict)
        for row in cur.fetchall():
            geom, suggestion_text = row[0], row[1]
            self.search_results.append(geom)
            self.suggestions.append([
                suggestion_text, descript, tablename, layername, isSelect,
                searchcolumn
            ])
            # self.suggestions.append(suggestion_text)   # для QStringList

    def get_search_sql(self, search_text, search_column, table):

        wildcarded_search_string = ''
        for part in search_text.split():
            wildcarded_search_string += '%' + part  #.lower()
        wildcarded_search_string += '%'
        wildcarded_search_string = wildcarded_search_string
        query_dict = {'search_text': wildcarded_search_string}

        # wildcarded_search_string = wildcarded_search_string.encode('cp1251')
        query_text = u"SELECT WKT_GEOMETRY AS geom, {0} AS suggestion_string FROM {1} WHERE ({0}) LIKE '{2}' ORDER BY {0} LIMIT 1000".format(
            search_column, table, wildcarded_search_string)
        # query_text = query_text.decode('cp1251')
        return query_text, query_dict

    def on_result_selected(self, result_index):
        resultIndexRow = result_index.row()

        if len(self.search_results) < 1:
            self.search_line_edit.setPlaceholderText(u'')
            return
        # What to do when the user makes a selection
        geometry_text = self.search_results[resultIndexRow]
        location_geom = QgsGeometry.fromWkt(geometry_text)
        canvas = self.iface.mapCanvas()
        # dst_srid = canvas.mapRenderer().destinationCrs().authid()
        # Ensure the geometry from the DB is reprojected to the same SRID as the map canvas
        location_centroid = location_geom.centroid().asPoint()

        result_text = self.completer.completionModel().index(
            resultIndexRow, 0).data()

        if self.suggestions[resultIndexRow][2] in (
                u"adres_nd") and location_geom.type() == 0:  # point
            self.show_marker(location_centroid)
            self.iface.mapCanvas().setExtent(location_geom.boundingBox())
            self.iface.mapCanvas().zoomScale(1000)
            layer_build = self.find_layer(u"Здания")
            if layer_build != None:
                layer_build.selectByIds([])
                for feat in layer_build.getFeatures(
                        QgsFeatureRequest().setFilterRect(
                            QgsRectangle(self.iface.mapCanvas().extent()))):
                    if location_geom.intersects(feat.geometry()):
                        # self.show_marker_feature(feat.geometry())
                        self.iface.setActiveLayer(layer_build)
                        layer_build.selectByIds([feat.id()])
                        layer_build.triggerRepaint()
                        return

        else:  #not point
            layername = self.suggestions[resultIndexRow][3]
            isSelect = self.suggestions[resultIndexRow][4]
            searchcolumn = self.suggestions[resultIndexRow][5]

            box = location_geom.boundingBox()
            if box.height() > box.width():
                max = box.height()
            else:
                max = box.width()
            box.grow(max * 0.10)
            self.iface.mapCanvas().setExtent(box)

            if isSelect == 1:
                selLayer = self.find_layer(layername)
                if selLayer is not None:
                    for feat in selLayer.getFeatures(
                            QgsFeatureRequest().setFilterRect(box)):
                        # print(feat[searchcolumn], str(result_text).strip())
                        try:
                            if str(feat[searchcolumn]) == str(
                                    result_text).strip():
                                self.iface.setActiveLayer(selLayer)
                                selLayer.selectByIds([feat.id()])
                                selLayer.triggerRepaint()
                                break
                        except Exception as E:
                            print(E)
                            break

            self.show_marker_feature(location_geom)

        canvas.refresh()
        self.line_edit_timer.start(0)
        # self.db_timer.stop()

    def get_db_cur(self):
        # Create a new new connection if required
        if self.db_conn is None:
            self.db_conn = sqlite3.connect(os.path.join(self.dbfile.strip()))
        return self.db_conn.cursor()

    def on_result_highlighted(self, result_idx):
        self.line_edit_timer.start(0)

    def reset_line_edit_after_move(self):
        self.search_line_edit.setText(self.query_text)

    def find_layer(self, layer_name):
        for search_layer in self.iface.mapCanvas().layers():
            if search_layer.name() == layer_name:
                return search_layer
        return None

    def show_marker(self, point):
        for m in [self.marker, self.marker2]:
            m.setCenter(point)
            m.setOpacity(1.0)
            m.setVisible(True)
        QTimer.singleShot(4000, self.hide_marker)

    def hide_marker(self):
        opacity = self.marker.opacity()
        if opacity > 0.:
            # produce a fade out effect
            opacity -= 0.1
            self.marker.setOpacity(opacity)
            self.marker2.setOpacity(opacity)
            QTimer.singleShot(100, self.hide_marker)
        else:
            self.marker.setVisible(False)
            self.marker2.setVisible(False)

    def show_marker_feature(self, geom):
        if geom.type() == 2:  #poly
            self.r = QgsRubberBand(iface.mapCanvas(), True)
        elif geom.type() == 1:  #line
            self.r = QgsRubberBand(iface.mapCanvas(), False)
        self.r.setToGeometry(geom, None)
        self.r.setColor(QColor(255, 0, 0, 200))
        self.r.setFillColor(QColor(255, 0, 0, 50))
        self.r.setWidth(2)
        self.r.setZValue(9)

        QTimer.singleShot(4000, self.hide_marker_feature)

    def hide_marker_feature(self):
        opacity = self.r.opacity()
        if opacity > 0.:
            # produce a fade out effect
            opacity -= 0.1
            self.r.setOpacity(opacity)
            QTimer.singleShot(100, self.hide_marker_feature)
        else:
            iface.mapCanvas().scene().removeItem(self.r)
Beispiel #5
0
class TextEditTechnique(QTextEdit):
    def __init__(self, text_file, input_trigger=None, active=True):
        super(TextEditTechnique, self).__init__()
        self._completer = None
        self.isActive = active
        word_list = self.get_suggestion_words(text_file)
        self.input_trigger = input_trigger
        # connects the text textChanged event
        self.textChanged.connect(self.handle_input)
        self.char_length = 1
        self.set_completer(word_list)
        self.technique_used = False
        self.no_suggestion_input = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-= "

    # gets words for suggestion
    def get_suggestion_words(self, text_file):
        words = []
        file = open(text_file)
        for line in file:
            for word in line.split(' '):
                word = word.strip().lower().replace('.', '').replace(
                    ',', '').replace(':', '').replace('?', '')
                if word and word not in words:
                    words.append(word)
        file.close()
        return words

    # initializes the completer
    def set_completer(self, words):
        if self._completer is not None:
            self._completer.activated.disconnect()
        self._completer = QCompleter(words, self)
        self._completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._completer.setWrapAround(False)
        self._completer.setWidget(self)
        self._completer.setCompletionMode(QCompleter.PopupCompletion)
        self._completer.activated.connect(self.insert_sel_suggestion)

    # insert the selected suggestion and moves the text cursor
    def insert_sel_suggestion(self, suggestion):
        if self._completer.widget() is not self:
            return
        text_cursor = self.textCursor()
        extra = len(suggestion) - len(self._completer.completionPrefix())
        text_cursor.movePosition(QTextCursor.Left)
        text_cursor.movePosition(QTextCursor.EndOfWord)
        text_cursor.insertText(suggestion[-extra:])
        self.setTextCursor(text_cursor)

    # returns the current typed word
    def text_under_cursor(self):
        text_cursor = self.textCursor()
        text_cursor.select(QTextCursor.WordUnderCursor)
        return text_cursor.selectedText()

    # sets the widget
    def focusInEvent(self, e):
        if self._completer is not None and self.isActive:
            self._completer.setWidget(self)
        super(TextEditTechnique, self).focusInEvent(e)

    def keyPressEvent(self, e):

        # behaves like a normal input field!
        if not self.isActive or self._completer is None:
            super(TextEditTechnique, self).keyPressEvent(e)
            return

        # ignore events funktion keys on Textedit if popup is visible --> popup behaves default
        if self._completer.popup().isVisible():
            if e.key() in (Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape,
                           Qt.Key_Tab, Qt.Key_Backtab):
                e.ignore()
                self.technique_used = True
                return
        # writes text in the editfield
        super(TextEditTechnique, self).keyPressEvent(e)

        ctrl_or_shift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
        if self._completer is None or (ctrl_or_shift and len(e.text()) == 0):
            return

        has_modifier = (e.modifiers() != Qt.NoModifier) and not ctrl_or_shift
        completion_prefix = self.text_under_cursor()
        # hide the popup for no chars, modifiers, shift and no text
        if (has_modifier or len(e.text()) == 0
                or len(completion_prefix) < self.char_length
                or e.text()[-1] in self.no_suggestion_input):
            self._completer.popup().hide()
            return

        # shows the popup with the suggested words
        if completion_prefix != self._completer.completionPrefix():
            self._completer.setCompletionPrefix(completion_prefix)
            self._completer.popup().setCurrentIndex(
                self._completer.completionModel().index(0, 0))

        cursor = self.cursorRect()
        cursor.setWidth(
            self._completer.popup().sizeHintForColumn(0) +
            self._completer.popup().verticalScrollBar().sizeHint().width())
        self._completer.complete(cursor)

    # event called if textedit input has changed
    def handle_input(self):
        timestamp = time.time()
        self.input_trigger.emit(self.toPlainText(), timestamp)

    # clears the text input
    def clear_input(self):
        self.setHtml('')

    # deactivates the completer
    def deactivate_completer(self):
        self.isActive = False

    # activates the completer
    def activate_completer(self):
        self.isActive = True