Fixes #16852 by adding click_x and click_y variables to resolve actions

This commit is contained in:
Blottiere Paul 2017-11-10 15:01:08 +00:00
parent 2ca4ee5ba8
commit c9c1c34952
16 changed files with 200 additions and 12 deletions

View File

@ -184,6 +184,21 @@ Checks if the action is runable on the current platform
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
void setExpressionContextScope( const QgsExpressionContextScope &scope );
%Docstring
Sets an expression context scope to use for running the action.
.. versionadded:: 3.0
%End
QgsExpressionContextScope expressionContextScope() const;
%Docstring
Returns an expression context scope used for running the action.
.. versionadded:: 3.0
:rtype: QgsExpressionContextScope
%End
}; };

View File

@ -62,10 +62,15 @@ Constructor
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
void doAction( const QUuid &actionId, const QgsFeature &feature, int defaultValueIndex = 0 ) /PyName=doActionFeature/; void doAction( const QUuid &actionId, const QgsFeature &feature, int defaultValueIndex = 0, const QgsExpressionContextScope &scope = QgsExpressionContextScope() ) /PyName=doActionFeature/;
%Docstring %Docstring
Does the given action. defaultValueIndex is the index of the Does the given action.
field to be used if the action has a $currfield placeholder.
\param actionId action id
\param feature feature to run action for
\param defaultValueIndex index of the field to be used if the action has a $currfield placeholder.
\param scope expression context scope to add during expression evaluation
.. note:: .. note::
available in Python bindings as doActionFeature available in Python bindings as doActionFeature

View File

@ -73,6 +73,21 @@ class QgsActionMenu : QMenu
as long as the menu is displayed and the action is running. as long as the menu is displayed and the action is running.
%End %End
void setExpressionContextScope( const QgsExpressionContextScope &scope );
%Docstring
Sets an expression context scope used to resolve underlying actions.
.. versionadded:: 3.0
%End
QgsExpressionContextScope expressionContextScope() const;
%Docstring
Returns an expression context scope used to resolve underlying actions.
.. versionadded:: 3.0
:rtype: QgsExpressionContextScope
%End
signals: signals:
void reinit(); void reinit();

View File

@ -71,6 +71,21 @@ define if the menu will be shown with a single idetify result
:rtype: bool :rtype: bool
%End %End
void setExpressionContextScope( const QgsExpressionContextScope &scope );
%Docstring
Sets an expression context scope used to resolve underlying actions.
.. versionadded:: 3.0
%End
QgsExpressionContextScope expressionContextScope() const;
%Docstring
Returns an expression context scope used to resolve underlying actions.
.. versionadded:: 3.0
:rtype: QgsExpressionContextScope
%End
void setShowFeatureActions( bool showFeatureActions ); void setShowFeatureActions( bool showFeatureActions );
%Docstring %Docstring
define if attribute actions(1) and map layer actions(2) can be listed and run from the menu define if attribute actions(1) and map layer actions(2) can be listed and run from the menu

View File

@ -1164,6 +1164,8 @@ void QgsIdentifyResultsDialog::clear()
delete curve; delete curve;
mPlotCurves.clear(); mPlotCurves.clear();
mExpressionContextScope = QgsExpressionContextScope();
// keep it visible but disabled, it can switch from disabled/enabled // keep it visible but disabled, it can switch from disabled/enabled
// after raster format change // after raster format change
mActionPrint->setDisabled( true ); mActionPrint->setDisabled( true );
@ -1245,7 +1247,7 @@ void QgsIdentifyResultsDialog::doAction( QTreeWidgetItem *item, const QString &a
} }
int featIdx = featItem->data( 0, Qt::UserRole + 1 ).toInt(); int featIdx = featItem->data( 0, Qt::UserRole + 1 ).toInt();
layer->actions()->doAction( action, mFeatures[ featIdx ], idx ); layer->actions()->doAction( action, mFeatures[ featIdx ], idx, mExpressionContextScope );
} }
void QgsIdentifyResultsDialog::doMapLayerAction( QTreeWidgetItem *item, QgsMapLayerAction *action ) void QgsIdentifyResultsDialog::doMapLayerAction( QTreeWidgetItem *item, QgsMapLayerAction *action )
@ -1978,3 +1980,13 @@ void QgsIdentifyResultsDialog::showHelp()
{ {
QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#identify" ) ); QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#identify" ) );
} }
void QgsIdentifyResultsDialog::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
}
QgsExpressionContextScope QgsIdentifyResultsDialog::expressionContextScope() const
{
return mExpressionContextScope;
}

View File

@ -25,6 +25,7 @@
#include "qgscoordinatereferencesystem.h" #include "qgscoordinatereferencesystem.h"
#include "qgsmaptoolidentify.h" #include "qgsmaptoolidentify.h"
#include "qgswebview.h" #include "qgswebview.h"
#include "qgsexpressioncontext.h"
#include <QWidget> #include <QWidget>
#include <QList> #include <QList>
@ -150,6 +151,22 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
//! Map tool was activated //! Map tool was activated
void activate(); void activate();
/**
* Sets an expression context scope to consider for resolving underlying
* actions.
*
* \since QGIS 3.0
*/
void setExpressionContextScope( const QgsExpressionContextScope &scope );
/**
* Returns an expression context scope used for resolving underlying
* actions.
*
* \since QGIS 3.0
*/
QgsExpressionContextScope expressionContextScope() const;
signals: signals:
void selectedFeatureChanged( QgsVectorLayer *, QgsFeatureId featureId ); void selectedFeatureChanged( QgsVectorLayer *, QgsFeatureId featureId );
@ -233,6 +250,7 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
QgsMapCanvas *mCanvas = nullptr; QgsMapCanvas *mCanvas = nullptr;
QList<QgsFeature> mFeatures; QList<QgsFeature> mFeatures;
QMap< QString, QMap< QString, QVariant > > mWidgetCaches; QMap< QString, QMap< QString, QVariant > > mWidgetCaches;
QgsExpressionContextScope mExpressionContextScope;
QgsMapLayer *layer( QTreeWidgetItem *item ); QgsMapLayer *layer( QTreeWidgetItem *item );
QgsVectorLayer *vectorLayer( QTreeWidgetItem *item ); QgsVectorLayer *vectorLayer( QTreeWidgetItem *item );

View File

@ -37,6 +37,7 @@
#include "qgsrenderer.h" #include "qgsrenderer.h"
#include "qgsunittypes.h" #include "qgsunittypes.h"
#include "qgsstatusbar.h" #include "qgsstatusbar.h"
#include "qgsactionscoperegistry.h"
#include "qgssettings.h" #include "qgssettings.h"
#include <QMouseEvent> #include <QMouseEvent>
@ -119,6 +120,8 @@ void QgsMapToolIdentifyAction::canvasReleaseEvent( QgsMapMouseEvent *e )
connect( this, &QgsMapToolIdentifyAction::identifyProgress, QgisApp::instance(), &QgisApp::showProgress ); connect( this, &QgsMapToolIdentifyAction::identifyProgress, QgisApp::instance(), &QgisApp::showProgress );
connect( this, &QgsMapToolIdentifyAction::identifyMessage, QgisApp::instance(), &QgisApp::showStatusMessage ); connect( this, &QgsMapToolIdentifyAction::identifyMessage, QgisApp::instance(), &QgisApp::showStatusMessage );
setClickContextScope( toMapCoordinates( e->pos() ) );
identifyMenu()->setResultsIfExternalAction( false ); identifyMenu()->setResultsIfExternalAction( false );
// enable the right click for extended menu so it behaves as a contextual menu // enable the right click for extended menu so it behaves as a contextual menu
@ -201,4 +204,16 @@ void QgsMapToolIdentifyAction::handleCopyToClipboard( QgsFeatureStore &featureSt
emit copyToClipboard( featureStore ); emit copyToClipboard( featureStore );
} }
void QgsMapToolIdentifyAction::setClickContextScope( const QgsPointXY &point )
{
QgsExpressionContextScope clickScope;
clickScope.addVariable( QgsExpressionContextScope::StaticVariable( QString( "click_x" ), point.x(), true ) );
clickScope.addVariable( QgsExpressionContextScope::StaticVariable( QString( "click_y" ), point.y(), true ) );
resultsDialog()->setExpressionContextScope( clickScope );
if ( mIdentifyMenu )
{
mIdentifyMenu->setExpressionContextScope( clickScope );
}
}

View File

@ -78,7 +78,9 @@ class APP_EXPORT QgsMapToolIdentifyAction : public QgsMapToolIdentify
virtual QgsUnitTypes::DistanceUnit displayDistanceUnits() const override; virtual QgsUnitTypes::DistanceUnit displayDistanceUnits() const override;
virtual QgsUnitTypes::AreaUnit displayAreaUnits() const override; virtual QgsUnitTypes::AreaUnit displayAreaUnits() const override;
void setClickContextScope( const QgsPointXY &point );
friend class TestQgsMapToolIdentifyAction;
}; };
#endif #endif

View File

@ -59,7 +59,11 @@ void QgsAction::run( const QgsExpressionContext &expressionContext ) const
return; return;
} }
QString expandedAction = QgsExpression::replaceExpressionText( mCommand, &expressionContext ); QgsExpressionContextScope *scope = new QgsExpressionContextScope( mExpressionContextScope );
QgsExpressionContext context( expressionContext );
context << scope;
QString expandedAction = QgsExpression::replaceExpressionText( mCommand, &context );
if ( mType == QgsAction::OpenUrl ) if ( mType == QgsAction::OpenUrl )
{ {
@ -146,3 +150,13 @@ void QgsAction::writeXml( QDomNode &actionsNode ) const
actionsNode.appendChild( actionSetting ); actionsNode.appendChild( actionSetting );
} }
void QgsAction::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
}
QgsExpressionContextScope QgsAction::expressionContextScope() const
{
return mExpressionContextScope;
};

View File

@ -191,6 +191,20 @@ class CORE_EXPORT QgsAction
*/ */
void writeXml( QDomNode &actionsNode ) const; void writeXml( QDomNode &actionsNode ) const;
/**
* Sets an expression context scope to use for running the action.
*
* \since QGIS 3.0
*/
void setExpressionContextScope( const QgsExpressionContextScope &scope );
/**
* Returns an expression context scope used for running the action.
*
* \since QGIS 3.0
*/
QgsExpressionContextScope expressionContextScope() const;
private: private:
ActionType mType = Generic; ActionType mType = Generic;
QString mDescription; QString mDescription;
@ -202,6 +216,7 @@ class CORE_EXPORT QgsAction
QString mNotificationMessage; QString mNotificationMessage;
mutable std::shared_ptr<QAction> mAction; mutable std::shared_ptr<QAction> mAction;
QUuid mId; QUuid mId;
QgsExpressionContextScope mExpressionContextScope;
}; };
Q_DECLARE_METATYPE( QgsAction ) Q_DECLARE_METATYPE( QgsAction )

View File

@ -123,10 +123,10 @@ void QgsActionManager::removeAction( const QUuid &actionId )
} }
} }
void QgsActionManager::doAction( const QUuid &actionId, const QgsFeature &feature, int defaultValueIndex ) void QgsActionManager::doAction( const QUuid &actionId, const QgsFeature &feature, int defaultValueIndex, const QgsExpressionContextScope &scope )
{ {
QgsExpressionContext context = createExpressionContext(); QgsExpressionContext context = createExpressionContext();
QgsExpressionContextScope *actionScope = new QgsExpressionContextScope(); QgsExpressionContextScope *actionScope = new QgsExpressionContextScope( scope );
actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_index" ), defaultValueIndex, true ) ); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_index" ), defaultValueIndex, true ) );
if ( defaultValueIndex >= 0 && defaultValueIndex < feature.fields().size() ) if ( defaultValueIndex >= 0 && defaultValueIndex < feature.fields().size() )
actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_name" ), feature.fields().at( defaultValueIndex ).name(), true ) ); actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_name" ), feature.fields().at( defaultValueIndex ).name(), true ) );

View File

@ -89,11 +89,16 @@ class CORE_EXPORT QgsActionManager: public QObject
void removeAction( const QUuid &actionId ); void removeAction( const QUuid &actionId );
/** /**
* Does the given action. defaultValueIndex is the index of the * Does the given action.
* field to be used if the action has a $currfield placeholder. *
* \note available in Python bindings as doActionFeature * \param actionId action id
* \param feature feature to run action for
* \param defaultValueIndex index of the field to be used if the action has a $currfield placeholder.
* \param scope expression context scope to add during expression evaluation
*
* \note available in Python bindings as doActionFeature
*/ */
void doAction( const QUuid &actionId, const QgsFeature &feature, int defaultValueIndex = 0 ) SIP_PYNAME( doActionFeature ); void doAction( const QUuid &actionId, const QgsFeature &feature, int defaultValueIndex = 0, const QgsExpressionContextScope &scope = QgsExpressionContextScope() ) SIP_PYNAME( doActionFeature );
/** /**
* Does the action using the expression engine to replace any embedded expressions * Does the action using the expression engine to replace any embedded expressions

View File

@ -107,8 +107,11 @@ void QgsActionMenu::reloadActions()
Q_FOREACH ( const QgsAction &action, mActions ) Q_FOREACH ( const QgsAction &action, mActions )
{ {
QgsAction act( action );
act.setExpressionContextScope( mExpressionContextScope );
QAction *qAction = new QAction( action.icon(), action.name(), this ); QAction *qAction = new QAction( action.icon(), action.name(), this );
qAction->setData( QVariant::fromValue<ActionData>( ActionData( action, mFeatureId, mLayer ) ) ); qAction->setData( QVariant::fromValue<ActionData>( ActionData( act, mFeatureId, mLayer ) ) );
qAction->setIcon( action.icon() ); qAction->setIcon( action.icon() );
// Only enable items on supported platforms // Only enable items on supported platforms
@ -160,3 +163,15 @@ QgsActionMenu::ActionData::ActionData( const QgsAction &action, QgsFeatureId fea
, featureId( featureId ) , featureId( featureId )
, mapLayer( mapLayer ) , mapLayer( mapLayer )
{} {}
void QgsActionMenu::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
reloadActions();
}
QgsExpressionContextScope QgsActionMenu::expressionContextScope() const
{
return mExpressionContextScope;
}

View File

@ -91,6 +91,20 @@ class GUI_EXPORT QgsActionMenu : public QMenu
*/ */
void setFeature( const QgsFeature &feature ); void setFeature( const QgsFeature &feature );
/**
* Sets an expression context scope used to resolve underlying actions.
*
* \since QGIS 3.0
*/
void setExpressionContextScope( const QgsExpressionContextScope &scope );
/**
* Returns an expression context scope used to resolve underlying actions.
*
* \since QGIS 3.0
*/
QgsExpressionContextScope expressionContextScope() const;
signals: signals:
void reinit(); void reinit();
@ -107,6 +121,7 @@ class GUI_EXPORT QgsActionMenu : public QMenu
QgsFeature mFeature; QgsFeature mFeature;
QgsFeatureId mFeatureId; QgsFeatureId mFeatureId;
QString mActionScope; QString mActionScope;
QgsExpressionContextScope mExpressionContextScope;
}; };

View File

@ -345,6 +345,7 @@ void QgsIdentifyMenu::addVectorLayer( QgsVectorLayer *layer, const QList<QgsMapT
if ( mShowFeatureActions ) if ( mShowFeatureActions )
{ {
featureActionMenu = new QgsActionMenu( layer, result.mFeature, QStringLiteral( "Feature" ), layerMenu ); featureActionMenu = new QgsActionMenu( layer, result.mFeature, QStringLiteral( "Feature" ), layerMenu );
featureActionMenu->setExpressionContextScope( mExpressionContextScope );
} }
// feature title // feature title
@ -639,3 +640,13 @@ void QgsIdentifyMenu::removeCustomActions()
mCustomActionRegistry.clear(); mCustomActionRegistry.clear();
} }
void QgsIdentifyMenu::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
}
QgsExpressionContextScope QgsIdentifyMenu::expressionContextScope() const
{
return mExpressionContextScope;
}

View File

@ -103,6 +103,20 @@ class GUI_EXPORT QgsIdentifyMenu : public QMenu
void setExecWithSingleResult( bool execWithSingleResult ) { mExecWithSingleResult = execWithSingleResult;} void setExecWithSingleResult( bool execWithSingleResult ) { mExecWithSingleResult = execWithSingleResult;}
bool execWithSingleResult() { return mExecWithSingleResult;} bool execWithSingleResult() { return mExecWithSingleResult;}
/**
* Sets an expression context scope used to resolve underlying actions.
*
* \since QGIS 3.0
*/
void setExpressionContextScope( const QgsExpressionContextScope &scope );
/**
* Returns an expression context scope used to resolve underlying actions.
*
* \since QGIS 3.0
*/
QgsExpressionContextScope expressionContextScope() const;
/** /**
* \brief define if attribute actions(1) and map layer actions(2) can be listed and run from the menu * \brief define if attribute actions(1) and map layer actions(2) can be listed and run from the menu
* \note custom actions will be shown in any case if they exist. * \note custom actions will be shown in any case if they exist.
@ -178,6 +192,8 @@ class GUI_EXPORT QgsIdentifyMenu : public QMenu
int mMaxLayerDisplay; int mMaxLayerDisplay;
int mMaxFeatureDisplay; int mMaxFeatureDisplay;
QgsExpressionContextScope mExpressionContextScope;
// name of the action to be displayed for feature default action, if other actions are shown // name of the action to be displayed for feature default action, if other actions are shown
QString mDefaultActionName; QString mDefaultActionName;