35 , mResultsView( new QgsLocatorResultsView() )
39 mLineEdit->setPlaceholderText( tr(
"Type to locate (⌘K)" ) );
41 mLineEdit->setPlaceholderText( tr(
"Type to locate (Ctrl+K)" ) );
44 int placeholderMinWidth = mLineEdit->fontMetrics().width( mLineEdit->placeholderText() );
45 int minWidth = std::max( 200, (
int )( placeholderMinWidth * 1.6 ) );
46 resize( minWidth, 30 );
47 QSizePolicy sizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
48 sizePolicy.setHorizontalStretch( 0 );
49 sizePolicy.setVerticalStretch( 0 );
50 setSizePolicy( sizePolicy );
51 setMinimumSize( QSize( minWidth, 0 ) );
53 QHBoxLayout *layout =
new QHBoxLayout();
54 layout->setMargin( 0 );
55 layout->setContentsMargins( 0, 0, 0, 0 );
56 layout->addWidget( mLineEdit );
59 setFocusProxy( mLineEdit );
67 QHBoxLayout *containerLayout =
new QHBoxLayout();
68 containerLayout->setMargin( 0 );
69 containerLayout->setContentsMargins( 0, 0, 0, 0 );
70 containerLayout->addWidget( mResultsView );
71 mResultsContainer->setLayout( containerLayout );
72 mResultsContainer->hide();
75 mProxyModel->setSourceModel( mLocatorModel );
76 mResultsView->setModel( mProxyModel );
77 mResultsView->setUniformRowHeights(
true );
78 mResultsView->setIconSize( QSize( 16, 16 ) );
79 mResultsView->recalculateSize();
83 connect( mLineEdit, &QLineEdit::textChanged,
this, &QgsLocatorWidget::scheduleDelayedPopup );
84 connect( mResultsView, &QAbstractItemView::activated,
this, &QgsLocatorWidget::acceptCurrentEntry );
87 mPopupTimer.setInterval( 100 );
88 mPopupTimer.setSingleShot(
true );
89 connect( &mPopupTimer, &QTimer::timeout,
this, &QgsLocatorWidget::performSearch );
90 mFocusTimer.setInterval( 110 );
91 mFocusTimer.setSingleShot(
true );
92 connect( &mFocusTimer, &QTimer::timeout,
this, &QgsLocatorWidget::triggerSearchAndShowList );
94 mLineEdit->installEventFilter(
this );
95 mResultsContainer->installEventFilter(
this );
96 mResultsView->installEventFilter(
this );
97 installEventFilter(
this );
98 window()->installEventFilter(
this );
100 mLocator->
registerFilter(
new QgsLocatorFilterFilter(
this,
this ) );
102 mMenu =
new QMenu(
this );
103 QAction *menuAction = mLineEdit->addAction(
QgsApplication::getThemeIcon( QStringLiteral(
"/search.svg" ) ), QLineEdit::LeadingPosition );
104 connect( menuAction, &QAction::triggered,
this, [ = ]
107 mResultsContainer->hide();
108 mMenu->exec( QCursor::pos() );
110 connect( mMenu, &QMenu::aboutToShow,
this, &QgsLocatorWidget::configMenuAboutToShow );
126 mLineEdit->setText(
string );
127 window()->activateWindow();
128 mLineEdit->setFocus();
135 mLocatorModel->
clear();
136 mResultsContainer->hide();
139 void QgsLocatorWidget::scheduleDelayedPopup()
144 void QgsLocatorWidget::performSearch()
147 updateResults( mLineEdit->text() );
151 void QgsLocatorWidget::showList()
153 mResultsContainer->show();
154 mResultsContainer->raise();
157 void QgsLocatorWidget::triggerSearchAndShowList()
159 if ( mProxyModel->rowCount() == 0 )
165 void QgsLocatorWidget::searchFinished()
167 if ( mHasQueuedRequest )
170 QString nextSearch = mNextRequestedString;
171 mNextRequestedString.clear();
172 mHasQueuedRequest =
false;
173 updateResults( nextSearch );
184 if ( obj == mLineEdit && event->type() == QEvent::KeyPress )
186 QKeyEvent *keyEvent =
static_cast<QKeyEvent *
>( event );
187 switch ( keyEvent->key() )
192 case Qt::Key_PageDown:
193 triggerSearchAndShowList();
194 mHasSelectedResult =
true;
195 QgsApplication::sendEvent( mResultsView, event );
199 if ( keyEvent->modifiers() & Qt::ControlModifier )
201 triggerSearchAndShowList();
202 mHasSelectedResult =
true;
203 QgsApplication::sendEvent( mResultsView, event );
209 acceptCurrentEntry();
212 mResultsContainer->hide();
215 mHasSelectedResult =
true;
216 mResultsView->selectNextResult();
218 case Qt::Key_Backtab:
219 mHasSelectedResult =
true;
220 mResultsView->selectPreviousResult();
226 else if ( obj == mResultsView && event->type() == QEvent::MouseButtonPress )
228 mHasSelectedResult =
true;
230 else if ( event->type() == QEvent::FocusOut && ( obj == mLineEdit || obj == mResultsContainer || obj == mResultsView ) )
232 if ( !mLineEdit->hasFocus() && !mResultsContainer->hasFocus() && !mResultsView->hasFocus() )
235 mResultsContainer->hide();
238 else if ( event->type() == QEvent::FocusIn && obj == mLineEdit )
242 else if ( obj == window() && event->type() == QEvent::Resize )
244 mResultsView->recalculateSize();
246 return QWidget::eventFilter( obj, event );
251 bool selectFirst = !mHasSelectedResult || mProxyModel->rowCount() == 0;
256 bool selectable =
false;
257 while ( !selectable && row < mProxyModel->rowCount() )
260 selectable = mProxyModel->flags( mProxyModel->index( row, 0 ) ).testFlag( Qt::ItemIsSelectable );
263 mResultsView->setCurrentIndex( mProxyModel->index( row, 0 ) );
267 void QgsLocatorWidget::configMenuAboutToShow()
272 if ( !filter->enabled() )
275 QAction *action =
new QAction( filter->displayName(), mMenu );
276 connect( action, &QAction::triggered,
this, [ = ]
278 QString currentText = mLineEdit->text();
279 if ( currentText.isEmpty() )
280 currentText = tr(
"<type here>" );
283 QStringList parts = currentText.split(
' ' );
284 if ( parts.count() > 1 && mLocator->
filters( parts.at( 0 ) ).count() > 0 )
287 currentText = parts.join(
' ' );
291 mLineEdit->setText( filter->activePrefix() +
' ' + currentText );
292 mLineEdit->setSelection( filter->activePrefix().length() + 1, currentText.length() );
294 mMenu->addAction( action );
296 mMenu->addSeparator();
297 QAction *configAction =
new QAction( tr(
"Configure…" ), mMenu );
299 mMenu->addAction( configAction );
303 void QgsLocatorWidget::updateResults(
const QString &text )
312 mNextRequestedString = text;
313 mHasQueuedRequest =
true;
318 mHasSelectedResult =
false;
324 void QgsLocatorWidget::acceptCurrentEntry()
326 if ( mHasQueuedRequest )
332 if ( !mResultsView->isVisible() )
335 QModelIndex index = mResultsView->currentIndex();
336 if ( !index.isValid() )
340 mResultsContainer->hide();
341 mLineEdit->clearFocus();
364 QgsLocatorResultsView::QgsLocatorResultsView( QWidget *parent )
365 : QTreeView( parent )
367 setRootIsDecorated(
false );
368 setUniformRowHeights(
true );
370 header()->setStretchLastSection(
true );
373 void QgsLocatorResultsView::recalculateSize()
376 int rowSize = 20 * itemDelegate()->sizeHint( viewOptions(), model()->index( 0, 0 ) ).height();
379 int width = std::max( 300, window()->size().width() / 2 );
380 QSize newSize( width, rowSize + frameWidth() * 2 );
382 parentWidget()->resize( newSize );
383 QTreeView::resize( newSize );
385 header()->resizeSection( 0, width / 2 );
386 header()->resizeSection( 1, 0 );
389 void QgsLocatorResultsView::selectNextResult()
391 int nextRow = currentIndex().row() + 1;
392 nextRow = nextRow % model()->rowCount( QModelIndex() );
393 setCurrentIndex( model()->index( nextRow, 0 ) );
396 void QgsLocatorResultsView::selectPreviousResult()
398 int previousRow = currentIndex().row() - 1;
399 if ( previousRow < 0 )
400 previousRow = model()->rowCount( QModelIndex() ) - 1;
401 setCurrentIndex( model()->index( previousRow, 0 ) );
410 , mLocator( locator )
413 QgsLocatorFilterFilter *QgsLocatorFilterFilter::clone()
const 415 return new QgsLocatorFilterFilter( mLocator );
418 QgsLocatorFilter::Flags QgsLocatorFilterFilter::flags()
const 425 if ( !
string.isEmpty() )
436 if ( filter ==
this || !filter || !filter->enabled() )
442 result.
userData = filter->activePrefix() +
' ';
444 emit resultFetched( result );
448 void QgsLocatorFilterFilter::triggerResult(
const QgsLocatorResult &result )
450 mLocator->search( result.
userData.toString() );
void registerFilter(QgsLocatorFilter *filter)
Registers a filter within the locator.
void cancelWithoutBlocking()
Triggers cancelation of any current running query without blocking.
QIcon icon
Icon for result.
void fetchResults(const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback=nullptr)
Triggers the background fetching of filter results for a specified search string. ...
A sort proxy model for QgsLocatorModel, which automatically sorts results by precedence.
void setShowSpinner(bool showSpinner)
Show a spinner icon.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
bool isRunning() const
Returns true if a query is currently being executed by the locator.
QString description
Descriptive text for result.
QList< QgsLocatorFilter * > filters(const QString &prefix=QString())
Returns the list of filters registered in the locator.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
Map canvas is a class for displaying all GIS data types on a canvas.
void finished()
Emitted when locator has finished a query, either as a result of successful completion or early cance...
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
Base class for feedback objects to be used for cancelation of something running in a worker thread...
QgsRectangle targetExtent
Map extent to target in results.
virtual void triggerResult(const QgsLocatorResult &result)=0
Triggers a filter result from this filter.
QVariant userData
Custom reference or other data set by the filter.
QString displayString
String displayed for result.
QLineEdit subclass with built in support for clearing the widget's value and handling custom null val...
Encapsulates the properties relating to the context of a locator search.
Encapsulates properties of an individual matching result found by a QgsLocatorFilter.
Abstract base class for filters which collect locator results.
Handles the management of QgsLocatorFilter objects and async collection of search results from them...
void foundResult(const QgsLocatorResult &result)
Emitted whenever a filter encounters a matching result after the fetchResults() method is called...
An abstract list model for displaying the results of locator searches.
QgsCoordinateReferenceSystem targetExtentCrs
Coordinate reference system for the map extent variable.
void deferredClear()
Resets the model and clears all existing results after a short delay, or whenever the next result is ...
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsLocatorFilter * filter
Filter from which the result was obtained.
bool isCanceled() const
Tells whether the operation has been canceled already.
void addResult(const QgsLocatorResult &result)
Adds a new result to the model.
Filter finds results quickly and can be safely run in the main thread.
void setShowClearButton(bool visible)
Sets whether the widget's clear button is visible.
void clear()
Resets the model and clears all existing results.
void clearPreviousResults()
Will call clearPreviousResults on all filters.