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, static_cast< int >( placeholderMinWidth * 1.8 ) );
    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();
    74   mResultsView->setModel( mModelBridge->
proxyModel() );
    75   mResultsView->setUniformRowHeights( 
true );
    78   mResultsView->setIconSize( QSize( iconSize, iconSize ) );
    79   mResultsView->recalculateSize();
    80   mResultsView->setContextMenuPolicy( Qt::CustomContextMenu );
    82   connect( mLineEdit, &QLineEdit::textChanged, 
this, &QgsLocatorWidget::scheduleDelayedPopup );
    83   connect( mResultsView, &QAbstractItemView::activated, 
this, &QgsLocatorWidget::acceptCurrentEntry );
    84   connect( mResultsView, &QAbstractItemView::customContextMenuRequested, 
this, &QgsLocatorWidget::showContextMenu );
    91   mPopupTimer.setInterval( 100 );
    92   mPopupTimer.setSingleShot( 
true );
    93   connect( &mPopupTimer, &QTimer::timeout, 
this, &QgsLocatorWidget::performSearch );
    94   mFocusTimer.setInterval( 110 );
    95   mFocusTimer.setSingleShot( 
true );
    96   connect( &mFocusTimer, &QTimer::timeout, 
this, &QgsLocatorWidget::triggerSearchAndShowList );
    98   mLineEdit->installEventFilter( 
this );
    99   mResultsContainer->installEventFilter( 
this );
   100   mResultsView->installEventFilter( 
this );
   101   installEventFilter( 
this );
   102   window()->installEventFilter( 
this );
   106   mMenu = 
new QMenu( 
this );
   107   QAction *menuAction = mLineEdit->addAction( 
QgsApplication::getThemeIcon( QStringLiteral( 
"/search.svg" ) ), QLineEdit::LeadingPosition );
   108   connect( menuAction, &QAction::triggered, 
this, [ = ]
   111     mResultsContainer->hide();
   112     mMenu->exec( QCursor::pos() );
   114   connect( mMenu, &QMenu::aboutToShow, 
this, &QgsLocatorWidget::configMenuAboutToShow );
   120   return mModelBridge->
locator();
   125   if ( mMapCanvas == canvas )
   128   for ( 
const QMetaObject::Connection &conn : qgis::as_const( mCanvasConnections ) )
   132   mCanvasConnections.clear();
   147   mLineEdit->setText( 
string );
   148   window()->activateWindow(); 
   149   mLineEdit->setFocus();
   156   mResultsContainer->hide();
   159 void QgsLocatorWidget::scheduleDelayedPopup()
   164 void QgsLocatorWidget::resultAdded()
   166   bool selectFirst = !mHasSelectedResult || mModelBridge->
proxyModel()->rowCount() == 0;
   170     bool selectable = 
false;
   171     while ( !selectable && row < mModelBridge->proxyModel()->rowCount() )
   174       selectable = mModelBridge->
proxyModel()->flags( mModelBridge->
proxyModel()->index( row, 0 ) ).testFlag( Qt::ItemIsSelectable );
   177       mResultsView->setCurrentIndex( mModelBridge->
proxyModel()->index( row, 0 ) );
   181 void QgsLocatorWidget::showContextMenu( 
const QPoint &point )
   183   QModelIndex index = mResultsView->indexAt( point );
   184   if ( !index.isValid() )
   187   const QList<QgsLocatorResult::ResultAction> actions = mResultsView->model()->data( index, 
QgsLocatorModel::ResultActionsRole ).value<QList<QgsLocatorResult::ResultAction>>();
   188   QMenu *contextMenu = 
new QMenu( mResultsView );
   189   for ( 
auto resultAction : actions )
   191     QAction *menuAction = 
new QAction( resultAction.text, contextMenu );
   192     if ( !resultAction.iconPath.isEmpty() )
   193       menuAction->setIcon( QIcon( resultAction.iconPath ) );
   194     connect( menuAction, &QAction::triggered, 
this, [ = ]() {mModelBridge->
triggerResult( index, resultAction.id );} );
   195     contextMenu->addAction( menuAction );
   197   contextMenu->exec( mResultsView->viewport()->mapToGlobal( point ) );
   200 void QgsLocatorWidget::performSearch()
   207 void QgsLocatorWidget::showList()
   209   mResultsContainer->show();
   210   mResultsContainer->raise();
   213 void QgsLocatorWidget::triggerSearchAndShowList()
   215   if ( mModelBridge->
proxyModel()->rowCount() == 0 )
   223   if ( obj == mLineEdit && event->type() == QEvent::KeyPress )
   225     QKeyEvent *keyEvent = 
static_cast<QKeyEvent *
>( event );
   226     switch ( keyEvent->key() )
   231       case Qt::Key_PageDown:
   232         triggerSearchAndShowList();
   233         mHasSelectedResult = 
true;
   234         QgsApplication::sendEvent( mResultsView, event );
   238         if ( keyEvent->modifiers() & Qt::ControlModifier )
   240           triggerSearchAndShowList();
   241           mHasSelectedResult = 
true;
   242           QgsApplication::sendEvent( mResultsView, event );
   248         acceptCurrentEntry();
   251         mResultsContainer->hide();
   254         mHasSelectedResult = 
true;
   255         mResultsView->selectNextResult();
   257       case Qt::Key_Backtab:
   258         mHasSelectedResult = 
true;
   259         mResultsView->selectPreviousResult();
   265   else if ( obj == mResultsView && event->type() == QEvent::MouseButtonPress )
   267     mHasSelectedResult = 
true;
   269   else if ( event->type() == QEvent::FocusOut && ( obj == mLineEdit || obj == mResultsContainer || obj == mResultsView ) )
   271     if ( !mLineEdit->hasFocus() && !mResultsContainer->hasFocus() && !mResultsView->hasFocus() )
   274       mResultsContainer->hide();
   277   else if ( event->type() == QEvent::FocusIn && obj == mLineEdit )
   281   else if ( obj == window() && event->type() == QEvent::Resize )
   283     mResultsView->recalculateSize();
   285   return QWidget::eventFilter( obj, event );
   288 void QgsLocatorWidget::configMenuAboutToShow()
   293     if ( !filter->enabled() )
   296     QAction *action = 
new QAction( filter->displayName(), mMenu );
   297     connect( action, &QAction::triggered, 
this, [ = ]
   299       QString currentText = mLineEdit->text();
   300       if ( currentText.isEmpty() )
   301         currentText = tr( 
"<type here>" );
   304         QStringList parts = currentText.split( 
' ' );
   305         if ( parts.count() > 1 && mModelBridge->
locator()->
filters( parts.at( 0 ) ).count() > 0 )
   308           currentText = parts.join( 
' ' );
   312       mLineEdit->setText( filter->activePrefix() + 
' ' + currentText );
   313       mLineEdit->setSelection( filter->activePrefix().length() + 1, currentText.length() );
   315     mMenu->addAction( action );
   317   mMenu->addSeparator();
   318   QAction *configAction = 
new QAction( tr( 
"Configure…" ), mMenu );
   320   mMenu->addAction( configAction );
   325 void QgsLocatorWidget::acceptCurrentEntry()
   333     if ( !mResultsView->isVisible() )
   336     QModelIndex index = mResultsView->currentIndex();
   337     if ( !index.isValid() )
   340     mResultsContainer->hide();
   341     mLineEdit->clearFocus();
   354 QgsLocatorResultsView::QgsLocatorResultsView( QWidget *parent )
   355   : QTreeView( parent )
   357   setRootIsDecorated( 
false );
   358   setUniformRowHeights( 
true );
   360   header()->setStretchLastSection( 
true );
   363 void QgsLocatorResultsView::recalculateSize()
   366   int rowSize = 20 * itemDelegate()->sizeHint( viewOptions(), model()->index( 0, 0 ) ).height();
   369   int width = std::max( 300, window()->size().width() / 2 );
   370   QSize newSize( width, rowSize + frameWidth() * 2 );
   372   parentWidget()->resize( newSize );
   373   QTreeView::resize( newSize );
   375   header()->resizeSection( 0, width / 2 );
   376   header()->resizeSection( 1, 0 );
   379 void QgsLocatorResultsView::selectNextResult()
   381   int nextRow = currentIndex().row() + 1;
   382   nextRow = nextRow % model()->rowCount( QModelIndex() );
   383   setCurrentIndex( model()->index( nextRow, 0 ) );
   386 void QgsLocatorResultsView::selectPreviousResult()
   388   int previousRow = currentIndex().row() - 1;
   389   if ( previousRow < 0 )
   390     previousRow = model()->rowCount( QModelIndex() ) - 1;
   391   setCurrentIndex( model()->index( previousRow, 0 ) );
   400   , mLocator( locator )
   403 QgsLocatorFilterFilter *QgsLocatorFilterFilter::clone()
 const   405   return new QgsLocatorFilterFilter( mLocator );
   408 QgsLocatorFilter::Flags QgsLocatorFilterFilter::flags()
 const   415   if ( !
string.isEmpty() )
   426     if ( filter == 
this || !filter || !filter->enabled() )
   432     result.
userData = filter->activePrefix() + 
' ';
   434     emit resultFetched( result );
   438 void QgsLocatorFilterFilter::triggerResult( 
const QgsLocatorResult &result )
   440   mLocator->search( result.
userData.toString() );
 void registerFilter(QgsLocatorFilter *filter)
Registers a filter within the locator. 
 
void updateCanvasCrs(const QgsCoordinateReferenceSystem &crs)
Update the canvas CRS used to create search context. 
 
QIcon icon
Icon for result. 
 
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly...
 
Q_INVOKABLE void performSearch(const QString &text)
Perform a search. 
 
The actions to be shown for the given result in a context menu. 
 
void setShowSpinner(bool showSpinner)
Show a spinner icon. 
 
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon. 
 
QString description
Descriptive text for result. 
 
The QgsLocatorModelBridge class provides the core functionality to be used in a locator widget...
 
QList< QgsLocatorFilter * > filters(const QString &prefix=QString())
Returns the list of filters registered in the locator. 
 
void updateCanvasExtent(const QgsRectangle &extent)
Update the canvas extent used to create search context. 
 
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. 
 
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...
 
QVariant userData
Custom reference or other data set by the filter. 
 
void isRunningChanged()
Emitted when the running status changes. 
 
void triggerResult(const QModelIndex &index, const int actionId=-1)
Triggers the result at given index and with optional actionId if an additional action was triggered...
 
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. 
 
void destinationCrsChanged()
Emitted when map CRS has changed. 
 
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 resultsCleared()
Emitted when the results are cleared. 
 
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering. 
 
Q_INVOKABLE QgsLocatorProxyModel * proxyModel() const
Returns the proxy model. 
 
bool isCanceled() const
Tells whether the operation has been canceled already. 
 
void invalidateResults()
This will invalidate current search results. 
 
bool hasQueueRequested() const
Returns true if some text to be search is pending in the queue. 
 
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 extentsChanged()
Emitted when the extents of the map change. 
 
QgsLocator * locator() const
Returns the locator. 
 
void resultAdded()
Emitted when a result is added.