class ExtendedCombo(QComboBox): def __init__(self, items=None, parent=None): super().__init__(parent) self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) self.completer = QCompleter(self) # always show all completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.pFilterModel = QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.completer.setPopup(self.view()) self.setCompleter(self.completer) self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString) self.completer.activated.connect(self.setTextIfCompleterIsClicked) def setItems(self, items: list or set): self.items = list(items) model = QStandardItemModel() for i, student in enumerate(items): item = UserItem(student) model.setItem(i, 0, item) self.setModel(model) self.setModelColumn(0) def setModel(self, model): super(ExtendedCombo, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(ExtendedCombo, self).setModelColumn(column) def view(self): return self.completer.popup() def index(self): return self.currentIndex() def setTextIfCompleterIsClicked(self, text): if text: index = self.findText(text) self.setCurrentIndex(index) def currentItem(self): return self.items[self.currentIndex()]
class SearchableComboBox(QComboBox): def __init__(self, parent=None): QComboBox.__init__(self, parent) self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) self.completer = QCompleter(self) self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.p_filter_model = QSortFilterProxyModel() self.p_filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.completer.setPopup(self.completer.popup()) self.setCompleter(self.completer) self.lineEdit().textEdited.connect( self.p_filter_model.setFilterFixedString) def setModel(self, model): super().setModel(model) self.p_filter_model.setSourceModel(model) self.completer.setModel(self.p_filter_model) def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.p_filter_model.setFilterKeyColumn(column) super().setModelColumn(column) def setTextIfCompleterIsClicked(self, text): if text: self.setCurrentIndex(self.findText(text)) def setItems(self, items): self.clear() model = QStandardItemModel() for i, word in enumerate(items): item = QStandardItem(word) model.setItem(i, 0, item) self.setModel(model) self.setModelColumn(0)
class ExtendedCombo(QComboBox): def __init__(self): super().__init__() self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) self.completer = QCompleter(self) # always show all completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.pFilterModel = QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.completer.setPopup(self.view()) self.setCompleter(self.completer) self.lineEdit().textEdited[str].connect( self.pFilterModel.setFilterFixedString) self.completer.activated.connect(self.setTextIfCompleterIsClicked) def setModel(self, model): super(ExtendedCombo, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(ExtendedCombo, self).setModelColumn(column) def view(self): return self.completer.popup() def index(self): return self.currentIndex() def setTextIfCompleterIsClicked(self, text): if text: index = self.findText(text) self.setCurrentIndex(index)
class FilteredComboBox(QComboBox): def __init__(self, options, **kwargs): super().__init__() self.setFocusPolicy(Qt.StrongFocus) self.setEditable(True) # self.dropEvent() self.completer = QCompleter(self) # always show all completions self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.pFilterModel = QSortFilterProxyModel(self) self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.completer.setPopup(self.view()) self.setCompleter(self.completer) the_style = "border-top-left-radius: 10px; border-bottom-left-radius: 10px; background-color: #f5f5f5;" self.lineEdit().setStyleSheet(the_style) if "height" in kwargs: self.setFixedHeight(kwargs["height"]) else: self.setFixedHeight(37) self.lineEdit().textEdited.connect( self.pFilterModel.setFilterFixedString) self.completer.activated.connect(self.setTextIfCompleterIsClicked) model = QStandardItemModel() for i, word in enumerate(options): item = QStandardItem(word) model.setItem(i, 0, item) self.setModel(model) self.setModelColumn(0) if "width" in kwargs: self.setFixedWidth(kwargs["width"]) else: self.setFixedWidth(260) style = """ QComboBox { border-radius: 10px; } QComboBox::drop-down:button{ width: 25px; background-color: #f5f5f5; border-image: url(./resources/assets/images/drop_down.png); border-bottom-right-radius: 10px; border-top-right-radius: 10px; } QComboBox::drop-down:button:hover{ background-color: #f5f5f5; } """ self.setStyleSheet(style) def setModel(self, model): super(FilteredComboBox, self).setModel(model) self.pFilterModel.setSourceModel(model) self.completer.setModel(self.pFilterModel) def setModelColumn(self, column): self.completer.setCompletionColumn(column) self.pFilterModel.setFilterKeyColumn(column) super(FilteredComboBox, self).setModelColumn(column) def view(self): return self.completer.popup() def index(self): return self.currentIndex() def setTextIfCompleterIsClicked(self, text): if text: index = self.findText(text) self.setCurrentIndex(index) def setMaximumWidth(self, p_int): self.setFixedWidth(p_int)
class ExtendedLineEdit(QLineEdit): signal_send_movie = pyqtSignal(list) signal_search_movie = pyqtSignal(str) signal_request_movie_data = pyqtSignal(int) signal_set_loading = pyqtSignal(str, bool) DEBUG = False def __init__(self, parent=None): super(ExtendedLineEdit, self).__init__(parent) self.movies = [] self.completer_lw = QListWidget() self.model = self.completer_lw.model() self.completer = QCompleter(self.model, self) self.completer.setPopup(self.completer_lw) self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) self.completer.setCompletionRole( Qt.UserRole ) # Change role because default EditRole is paited to list somehow self.setCompleter(self.completer) self.textEdited.connect(self.text_edited) #self.completer.activated[QModelIndex].connect(self.on_completer_activated) #self.completer.activated[str].connect(self.on_completer_activated_str) self.completer_lw.itemClicked.connect(self.item_clicked) self.installEventFilter(self) def eventFilter(self, obj, event): if event.type() == QEvent.MouseButtonPress: if event.button() == Qt.LeftButton: self.completer.complete() return super(ExtendedLineEdit, self).eventFilter(obj, event) def setText(self, text: str) -> None: if self.DEBUG: print('setText', text, self.sender()) super(ExtendedLineEdit, self).setText(text) if not isinstance(self.sender(), QCompleter) and text: self.text_edited(text) @pyqtSlot(list) def update_movies_list(self, result): if self.DEBUG: print('update_movies_list', result[0], len(result) - 1) type = result.pop(0) if type == 'db': self.movies = [x + [ type, ] for x in result] self.completer_lw.clear() self.completer.complete() else: for item in result: self.movies.append(item + [ type, ]) for item in result: cwidget = MyWidget() cwidget.label_movie_name.setText(item[1] if item[1] else item[2]) cwidget.label_original_name.setText(item[2]) cwidget.label_source.setText(type) cwidget.label_year.setText(str(item[3])) completer_myQListWidgetItem = QListWidgetItem(self.completer_lw) completer_myQListWidgetItem.setSizeHint(cwidget.sizeHint()) completer_myQListWidgetItem.setData(Qt.UserRole, item[1]) self.completer_lw.addItem(completer_myQListWidgetItem) self.completer_lw.setItemWidget(completer_myQListWidgetItem, cwidget) if self.hasFocus() and not self.completer_lw.isVisible() and len( self.movies) > 0: self.completer.complete() @pyqtSlot(str) def text_edited(self, text): if self.DEBUG: print('text_edited', text, self.sender()) if text and isinstance(self.sender(), ExtendedLineEdit): self.signal_search_movie.emit(text) @pyqtSlot(str) def on_completer_activated_str(self, name: str): if self.DEBUG: print('on_completer_activated_str', name) @pyqtSlot(QModelIndex) def on_completer_activated(self, index: QModelIndex): if self.DEBUG: print('on_completer_activated', index.row()) item = self.movies[index.row()] if len(item) > 13: self.signal_send_movie.emit(item[:13]) self.signal_request_movie_data.emit(item[13]) else: self.signal_send_movie.emit(item) @pyqtSlot(QListWidgetItem) def item_clicked(self, item: QListWidgetItem): if self.DEBUG: print('item_clicked', item, [i[1] for i in self.movies]) index = self.completer_lw.indexFromItem(item) item = self.movies[index.row()] type = item[-1] if type == 'db': self.signal_send_movie.emit(item) else: self.signal_set_loading.emit('movie', True) if len(item) > 13: self.signal_send_movie.emit(item[:13]) self.signal_request_movie_data.emit(item[13]) else: self.signal_send_movie.emit(item) def reset(self): if self.DEBUG: print('reset') self.completer_lw.clear() self.clearFocus()
def init_toolbar(self): self.toolbar = QToolBar() self.toolbar.setFixedHeight(25) self.toolbar.setWindowTitle("Show") # text for the contextmenu #self.toolbar.setStyleSheet("QToolBar {border:0px}") # make it user defined? self.toolbar.setMovable(False) self.toolbar.setFloatable(False) #self.toolbar.setIconSize(QSize(20,20)) self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.toolbar.setIconSize(QSize(20,20)) spacer_start = QWidget() # aligns the first actions properly spacer_start.setFixedSize(QSize(10, 1)) self.toolbar.addWidget(spacer_start) self.favourite_btn = misc.ToolbarButton(self.toolbar, 'Favorites') self.toolbar.addWidget(self.favourite_btn) self.favourite_btn.clicked.connect(self.favourite_display) #need lambda to pass extra args self.library_btn = misc.ToolbarButton(self.toolbar, 'Library') self.toolbar.addWidget(self.library_btn) self.library_btn.clicked.connect(self.catalog_display) #need lambda to pass extra args self.library_btn.selected = True self.toolbar.addSeparator() gallery_menu = QMenu() gallery_action = QToolButton() gallery_action.setText('Gallery ') gallery_action.setPopupMode(QToolButton.InstantPopup) gallery_action.setToolTip('Contains various gallery related features') gallery_action.setMenu(gallery_menu) add_gallery_icon = QIcon(app_constants.PLUS_PATH) gallery_action_add = QAction(add_gallery_icon, "Add single gallery...", self) gallery_action_add.triggered.connect(self.manga_list_view.SERIES_DIALOG.emit) gallery_action_add.setToolTip('Add a single gallery thoroughly') gallery_menu.addAction(gallery_action_add) add_more_action = QAction(add_gallery_icon, "Add galleries...", self) add_more_action.setStatusTip('Add galleries from different folders') add_more_action.triggered.connect(lambda: self.populate(True)) gallery_menu.addAction(add_more_action) populate_action = QAction(add_gallery_icon, "Populate from directory/archive...", self) populate_action.setStatusTip('Populates the DB with galleries from a single folder or archive') populate_action.triggered.connect(self.populate) gallery_menu.addAction(populate_action) gallery_menu.addSeparator() metadata_action = QAction('Get metadata for all galleries', self) metadata_action.triggered.connect(self.get_metadata) gallery_menu.addAction(metadata_action) scan_galleries_action = QAction('Scan for new galleries', self) scan_galleries_action.triggered.connect(self.scan_for_new_galleries) scan_galleries_action.setStatusTip('Scan monitored folders for new galleries') gallery_menu.addAction(scan_galleries_action) gallery_action_random = gallery_menu.addAction("Open random gallery") gallery_action_random.triggered.connect(self.manga_list_view.open_random_gallery) self.toolbar.addWidget(gallery_action) misc_action = QToolButton() misc_action.setText('Tools ') misc_action_menu = QMenu() misc_action.setMenu(misc_action_menu) misc_action.setPopupMode(QToolButton.InstantPopup) misc_action.setToolTip("Contains misc. features") gallery_downloader = QAction("Gallery Downloader", misc_action_menu) gallery_downloader.triggered.connect(self.download_window.show) misc_action_menu.addAction(gallery_downloader) duplicate_check_simple = QAction("Simple Duplicate Finder", misc_action_menu) duplicate_check_simple.triggered.connect(lambda: self.manga_list_view.duplicate_check()) misc_action_menu.addAction(duplicate_check_simple) self.toolbar.addWidget(misc_action) spacer_middle = QWidget() # aligns buttons to the right spacer_middle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolbar.addWidget(spacer_middle) sort_action = QToolButton() sort_action.setIcon(QIcon(app_constants.SORT_PATH)) sort_action.setMenu(misc.SortMenu(self.toolbar, self.manga_list_view)) sort_action.setPopupMode(QToolButton.InstantPopup) self.toolbar.addWidget(sort_action) self.grid_toggle_g_icon = QIcon(app_constants.GRID_PATH) self.grid_toggle_l_icon = QIcon(app_constants.LIST_PATH) self.grid_toggle = QToolButton() if self.display.currentIndex() == self.m_l_view_index: self.grid_toggle.setIcon(self.grid_toggle_l_icon) else: self.grid_toggle.setIcon(self.grid_toggle_g_icon) self.grid_toggle.setObjectName('gridtoggle') self.grid_toggle.clicked.connect(self.toggle_view) self.toolbar.addWidget(self.grid_toggle) spacer_mid2 = QWidget() spacer_mid2.setFixedSize(QSize(5, 1)) self.toolbar.addWidget(spacer_mid2) def set_search_case(b): app_constants.GALLERY_SEARCH_CASE = b settings.set(b, 'Application', 'gallery search case') settings.save() def set_search_strict(b): app_constants.GALLERY_SEARCH_STRICT = b settings.set(b, 'Application', 'gallery search strict') settings.save() self.search_bar = misc.LineEdit() search_options = self.search_bar.addAction(QIcon(app_constants.SEARCH_OPTIONS_PATH), QLineEdit.TrailingPosition) search_options_menu = QMenu(self) search_options.triggered.connect(lambda: search_options_menu.popup(QCursor.pos())) search_options.setMenu(search_options_menu) case_search_option = search_options_menu.addAction('Case Sensitive') case_search_option.setCheckable(True) case_search_option.setChecked(app_constants.GALLERY_SEARCH_CASE) case_search_option.toggled.connect(set_search_case) strict_search_option = search_options_menu.addAction('Match whole terms') strict_search_option.setCheckable(True) strict_search_option.setChecked(app_constants.GALLERY_SEARCH_STRICT) strict_search_option.toggled.connect(set_search_strict) self.search_bar.setObjectName('search_bar') self.search_timer = QTimer(self) self.search_timer.setSingleShot(True) self.search_timer.timeout.connect(lambda: self.search(self.search_bar.text())) self._search_cursor_pos = [0, 0] def set_cursor_pos(old, new): self._search_cursor_pos[0] = old self._search_cursor_pos[1] = new self.search_bar.cursorPositionChanged.connect(set_cursor_pos) if app_constants.SEARCH_AUTOCOMPLETE: completer = QCompleter(self) completer_view = misc.CompleterPopupView() completer.setPopup(completer_view) completer_view._setup() completer.setModel(self.manga_list_view.gallery_model) completer.setCaseSensitivity(Qt.CaseInsensitive) completer.setCompletionMode(QCompleter.PopupCompletion) completer.setCompletionRole(Qt.DisplayRole) completer.setCompletionColumn(app_constants.TITLE) completer.setFilterMode(Qt.MatchContains) self.search_bar.setCompleter(completer) self.search_bar.returnPressed.connect(lambda: self.search(self.search_bar.text())) if not app_constants.SEARCH_ON_ENTER: self.search_bar.textEdited.connect(lambda: self.search_timer.start(800)) self.search_bar.setPlaceholderText("Search title, artist, namespace & tags") self.search_bar.setMinimumWidth(150) self.search_bar.setMaximumWidth(500) self.search_bar.setFixedHeight(19) self.manga_list_view.sort_model.HISTORY_SEARCH_TERM.connect(lambda a: self.search_bar.setText(a)) self.toolbar.addWidget(self.search_bar) def search_history(_, back=True): # clicked signal passes a bool sort_model = self.manga_list_view.sort_model nav = sort_model.PREV if back else sort_model.NEXT history_term = sort_model.navigate_history(nav) if back: self.search_forward.setVisible(True) back = QShortcut(QKeySequence(QKeySequence.Back), self, lambda: search_history(None)) forward = QShortcut(QKeySequence(QKeySequence.Forward), self, lambda: search_history(None, False)) search_backbutton = QToolButton(self.toolbar) search_backbutton.setText(u'\u25C0') search_backbutton.setFixedWidth(15) search_backbutton.clicked.connect(search_history) self.search_backward = self.toolbar.addWidget(search_backbutton) self.search_backward.setVisible(False) search_forwardbutton = QToolButton(self.toolbar) search_forwardbutton.setText(u'\u25B6') search_forwardbutton.setFixedWidth(15) search_forwardbutton.clicked.connect(lambda: search_history(None, False)) self.search_forward = self.toolbar.addWidget(search_forwardbutton) self.search_forward.setVisible(False) spacer_end = QWidget() # aligns settings action properly spacer_end.setFixedSize(QSize(10, 1)) self.toolbar.addWidget(spacer_end) settings_act = QToolButton(self.toolbar) settings_act.setIcon(QIcon(app_constants.SETTINGS_PATH)) settings_act.clicked.connect(self.settings) self.toolbar.addWidget(settings_act) spacer_end2 = QWidget() # aligns About action properly spacer_end2.setFixedSize(QSize(5, 1)) self.toolbar.addWidget(spacer_end2) self.addToolBar(self.toolbar)
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)
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__() self.setGeometry(300, 300, 400, 300) fid = open('example.db', 'w') fid.close() db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName('example.db') db.open() query = QSqlQuery(db) query.exec_('CREATE TABLE "airports" ("city" TEXT, "code" TEXT)') airports = [('Aberdeen, SD', 'ABR'), ('Abilene, TX', 'ABI'), ('Adak Island, AK', 'ADK'), ('Akiachak, AK', 'KKI'), ('Akiak, AK', 'AKI'), ('Akron/Canton, OH', 'CAK'), ('Akuton, AK', 'KQA'), ('Alakanuk, AK', 'AUK'), ('Alamogordo, NM', 'ALM'), ('Alamosa, CO', 'ALS'), ('Albany, NY', 'ALB'), ('Albuquerque, NM', 'ABQ')] for item in airports: sql = 'INSERT INTO airports(city, code) VALUES(?, ?)' query.prepare(sql) query.addBindValue(item[0]) query.addBindValue(item[1]) query.exec_() query.exec_('SELECT * FROM airports') model = QSqlQueryModel() model.setQuery(query) self.cb = QComboBox(parent=self) self.cb.setModel(model) self.cb.setModelColumn(1) self.cb.setView(QTableView(self.cb)) self.cb.setGeometry(50, 50, 250, 50) self.cb.currentIndexChanged.connect(self.indexer) self.label = QLabel(parent=self) self.label.setGeometry(20, 200, 250, 50) self.cb.view().setMinimumWidth(500) self.cb.setEditable(True) self.completer = QCompleter() self.completer.setCaseSensitivity(False) self.cb.setCompleter(self.completer) self.completer.setModel(model) self.completer.setCompletionColumn(1) self.completer.setPopup(QTableView()) self.completer.popup().setMinimumWidth(500) self.completer.popup().setMinimumHeight(500) self.completer.activated.connect(self.activatedHandler) #@pyqtSlot(QObject) def activatedHandler(self, arg): pass def indexer(self, idx): self.label.setText('%d' % idx)