Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[locator] allow to have context menu entries for results
  • Loading branch information
3nids committed Nov 28, 2018
1 parent 7bce934 commit 1bc0fbf
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 12 deletions.
14 changes: 14 additions & 0 deletions python/core/auto_generated/locator/qgslocatorfilter.sip.in
Expand Up @@ -10,6 +10,7 @@




class QgsLocatorResult
{
%Docstring
Expand Down Expand Up @@ -47,6 +48,8 @@ Constructor for QgsLocatorResult.

QString group;

QList<QAction *> contextMenuActions;

};

class QgsLocatorFilter : QObject
Expand Down Expand Up @@ -172,6 +175,17 @@ by a user. The filter subclass must implement logic here
to perform the desired operation for the search result.
E.g. a file search filter would open file associated with the triggered
result.
%End

virtual void triggerResultFromContextMenu( const QgsLocatorResult &result, const QAction *action );
%Docstring
Triggers a filter ``result`` from this filter for a given action.
Actions are specified in the result given by this filter and shown
as context menu entries.

.. seealso:: :py:func:`triggerResult`

.. versionadded:: 3.6
%End

virtual void clearPreviousResults();
Expand Down
1 change: 1 addition & 0 deletions python/core/auto_generated/locator/qgslocatormodel.sip.in
Expand Up @@ -36,6 +36,7 @@ in order to ensure correct sorting of results by priority and match level.
ResultScoreRole,
ResultFilterNameRole,
ResultFilterGroupSortingRole,
ResultContextMenuActionsRole,
};

QgsLocatorModel( QObject *parent /TransferThis/ = 0 );
Expand Down
Expand Up @@ -12,6 +12,7 @@




class QgsLocatorModelBridge : QObject
{
%Docstring
Expand Down Expand Up @@ -56,9 +57,9 @@ Returns true if some text to be search is pending in the queue
Returns true if the a search is currently running
%End

void triggerResult( const QModelIndex &index );
void triggerResult( const QModelIndex &index, const QAction *action = 0 );
%Docstring
Triggers the result at given index
Triggers the result at given ``index`` and with optional \action if context menu entry was triggered
%End

signals:
Expand Down
36 changes: 33 additions & 3 deletions src/app/locator/qgsinbuiltlocatorfilters.cpp
Expand Up @@ -15,6 +15,8 @@
* *
***************************************************************************/

#include <QToolButton>
#include <QClipboard>

#include "qgsinbuiltlocatorfilters.h"
#include "qgsproject.h"
Expand All @@ -25,8 +27,7 @@
#include "qgsmaplayermodel.h"
#include "qgslayoutmanager.h"
#include "qgsmapcanvas.h"
#include <QToolButton>
#include <QClipboard>
#include "qgsfeatureaction.h"

QgsLayerTreeLocatorFilter::QgsLayerTreeLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
Expand Down Expand Up @@ -400,6 +401,8 @@ void QgsAllLayersFeaturesLocatorFilter::fetchResults( const QString &string, con
result.userData = QVariantList() << f.id() << preparedLayer.layerId;
result.icon = preparedLayer.layerIcon;
result.score = static_cast< double >( string.length() ) / result.displayString.size();

result.contextMenuActions << new QAction( tr( "Open form" ) );
emit resultFetched( result );

foundInCurrentLayer++;
Expand All @@ -413,6 +416,11 @@ void QgsAllLayersFeaturesLocatorFilter::fetchResults( const QString &string, con
}

void QgsAllLayersFeaturesLocatorFilter::triggerResult( const QgsLocatorResult &result )
{
triggerResultFromContextMenu( result, nullptr );
}

void QgsAllLayersFeaturesLocatorFilter::triggerResultFromContextMenu( const QgsLocatorResult &result, const QAction *action )
{
QVariantList dataList = result.userData.toList();
QgsFeatureId id = dataList.at( 0 ).toLongLong();
Expand All @@ -421,7 +429,29 @@ void QgsAllLayersFeaturesLocatorFilter::triggerResult( const QgsLocatorResult &r
if ( !layer )
return;

QgisApp::instance()->mapCanvas()->zoomToFeatureIds( layer, QgsFeatureIds() << id );
if ( !action )
{
QgisApp::instance()->mapCanvas()->zoomToFeatureIds( layer, QgsFeatureIds() << id );
}
else
{
// no need to check for which action, since the filter shows only one
QgsFeature f;
QgsFeatureRequest request;
request.setFilterFid( id );
bool fetched = layer->getFeatures( request ).nextFeature( f );
if ( !fetched )
return;
QgsFeatureAction action( tr( "Attributes changed" ), f, layer, QString(), -1, QgisApp::instance() );
if ( layer->isEditable() )
{
action.editFeature( false );
}
else
{
action.viewFeatureForm();
}
}
}

//
Expand Down
1 change: 1 addition & 0 deletions src/app/locator/qgsinbuiltlocatorfilters.h
Expand Up @@ -140,6 +140,7 @@ class APP_EXPORT QgsAllLayersFeaturesLocatorFilter : public QgsLocatorFilter
void prepare( const QString &string, const QgsLocatorContext &context ) override;
void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;
void triggerResultFromContextMenu( const QgsLocatorResult &result, const QAction *action ) override;

private:
int mMaxResultsPerLayer = 6;
Expand Down
6 changes: 6 additions & 0 deletions src/core/locator/qgslocatorfilter.cpp
Expand Up @@ -33,6 +33,12 @@ QgsLocatorFilter::Flags QgsLocatorFilter::flags() const
return nullptr;
}

void QgsLocatorFilter::triggerResultFromContextMenu( const QgsLocatorResult &result, const QAction *action )
{
Q_UNUSED( result );
Q_UNUSED( action );
}

bool QgsLocatorFilter::stringMatches( const QString &candidate, const QString &search )
{
return !search.isEmpty() && candidate.contains( search, Qt::CaseInsensitive );
Expand Down
22 changes: 19 additions & 3 deletions src/core/locator/qgslocatorfilter.h
Expand Up @@ -18,12 +18,14 @@
#ifndef QGSLOCATORFILTER_H
#define QGSLOCATORFILTER_H

#include <QAction>
#include <QIcon>
#include <QString>
#include <QVariant>

#include "qgis_core.h"
#include "qgslocatorcontext.h"
#include "qgslogger.h"
#include <QString>
#include <QVariant>
#include <QIcon>

class QgsFeedback;
class QgsLocatorFilter;
Expand Down Expand Up @@ -91,6 +93,11 @@ class CORE_EXPORT QgsLocatorResult
*/
QString group = QString();

/**
* Actions to be used in a context menu for the result
*/
QList<QAction *> contextMenuActions = QList<QAction *>();

};

/**
Expand Down Expand Up @@ -209,6 +216,15 @@ class CORE_EXPORT QgsLocatorFilter : public QObject
*/
virtual void triggerResult( const QgsLocatorResult &result ) = 0;

/**
* Triggers a filter \a result from this filter for a given action.
* Actions are specified in the result given by this filter and shown
* as context menu entries.
* \see triggerResult()
* \since QGIS 3.6
*/
virtual void triggerResultFromContextMenu( const QgsLocatorResult &result, const QAction *action );

/**
* This method will be called on main thread on the original filter (not a clone)
* before fetching results or before triggering a result to clear any change made
Expand Down
3 changes: 3 additions & 0 deletions src/core/locator/qgslocatormodel.cpp
Expand Up @@ -160,6 +160,9 @@ QVariant QgsLocatorModel::data( const QModelIndex &index, int role ) const
return 1;
else
return 0;

case ResultContextMenuActionsRole:
return QVariant::fromValue( mResults.at( index.row() ).result.contextMenuActions );
}

return QVariant();
Expand Down
1 change: 1 addition & 0 deletions src/core/locator/qgslocatormodel.h
Expand Up @@ -56,6 +56,7 @@ class CORE_EXPORT QgsLocatorModel : public QAbstractTableModel
ResultScoreRole, //!< Result match score, used by QgsLocatorProxyModel for sorting roles.
ResultFilterNameRole, //!< Associated filter name which created the result
ResultFilterGroupSortingRole, //!< Group results within the same filter results
ResultContextMenuActionsRole, //!< The actions to be shown for the given result in a context menu
};

/**
Expand Down
9 changes: 7 additions & 2 deletions src/core/locator/qgslocatormodelbridge.cpp
Expand Up @@ -37,12 +37,17 @@ bool QgsLocatorModelBridge::isRunning() const
return mIsRunning;
}

void QgsLocatorModelBridge::triggerResult( const QModelIndex &index )
void QgsLocatorModelBridge::triggerResult( const QModelIndex &index, const QAction *action )
{
mLocator->clearPreviousResults();
QgsLocatorResult result = mProxyModel->data( index, QgsLocatorModel::ResultDataRole ).value< QgsLocatorResult >();
if ( result.filter )
result.filter->triggerResult( result );
{
if ( action )
result.filter->triggerResultFromContextMenu( result, action );
else
result.filter->triggerResult( result );
}
}

void QgsLocatorModelBridge::setIsRunning( bool isRunning )
Expand Down
6 changes: 4 additions & 2 deletions src/core/locator/qgslocatormodelbridge.h
Expand Up @@ -24,6 +24,8 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsrectangle.h"

class QAction;

class QgsLocatorResult;
class QgsLocator;
class QgsLocatorContext;
Expand Down Expand Up @@ -61,8 +63,8 @@ class CORE_EXPORT QgsLocatorModelBridge : public QObject
//! Returns true if the a search is currently running
bool isRunning() const;

//! Triggers the result at given index
void triggerResult( const QModelIndex &index );
//! Triggers the result at given \a index and with optional \action if context menu entry was triggered
void triggerResult( const QModelIndex &index, const QAction *action = nullptr );

signals:
//! Emitted when a result is added
Expand Down
20 changes: 20 additions & 0 deletions src/gui/locator/qgslocatorwidget.cpp
Expand Up @@ -74,9 +74,12 @@ QgsLocatorWidget::QgsLocatorWidget( QWidget *parent )
mResultsView->setUniformRowHeights( true );
mResultsView->setIconSize( QSize( 16, 16 ) );
mResultsView->recalculateSize();
mResultsView->setContextMenuPolicy( Qt::CustomContextMenu );

connect( mLineEdit, &QLineEdit::textChanged, this, &QgsLocatorWidget::scheduleDelayedPopup );
connect( mResultsView, &QAbstractItemView::activated, this, &QgsLocatorWidget::acceptCurrentEntry );
connect( mResultsView, &QAbstractItemView::customContextMenuRequested, this, &QgsLocatorWidget::showContextMenu );

connect( mModelBridge, &QgsLocatorModelBridge::resultAdded, this, &QgsLocatorWidget::resultAdded );
connect( mModelBridge, &QgsLocatorModelBridge::isRunningChanged, this, [ = ]() {mLineEdit->setShowSpinner( mModelBridge->isRunning() );} );
connect( mModelBridge, & QgsLocatorModelBridge::resultsCleared, this, [ = ]() {mHasSelectedResult = false;} );
Expand Down Expand Up @@ -172,6 +175,23 @@ void QgsLocatorWidget::resultAdded()
}
}

void QgsLocatorWidget::showContextMenu( const QPoint &point )
{
QModelIndex index = mResultsView->indexAt( point );
if ( !index.isValid() )
return;

const QList<QAction *> actions = mResultsView->model()->data( index, QgsLocatorModel::ResultContextMenuActionsRole ).value<QList<QAction *>>();
for ( const QAction *action : actions )
{
connect( action, &QAction::triggered, this, [ = ]() {mModelBridge->triggerResult( index, action );} );
}

QMenu *contextMenu = new QMenu( mResultsView );
contextMenu->addActions( actions );
contextMenu->exec( mResultsView->viewport()->mapToGlobal( point ) );
}

void QgsLocatorWidget::performSearch()
{
mPopupTimer.stop();
Expand Down
1 change: 1 addition & 0 deletions src/gui/locator/qgslocatorwidget.h
Expand Up @@ -94,6 +94,7 @@ class GUI_EXPORT QgsLocatorWidget : public QWidget
void configMenuAboutToShow();
void scheduleDelayedPopup();
void resultAdded();
void showContextMenu( const QPoint &point );

private:
QgsLocatorModelBridge *mModelBridge = nullptr;
Expand Down

0 comments on commit 1bc0fbf

Please sign in to comment.