Skip to content

Commit

Permalink
Merge pull request #5597 from pblottiere/bugfix-clickxy
Browse files Browse the repository at this point in the history
[bugfix]  Fixes #16852 by adding click_x and click_y variables to resolve actions
  • Loading branch information
pblottiere committed Nov 15, 2017
2 parents db5b1df + 96e597a commit bd30e12
Show file tree
Hide file tree
Showing 19 changed files with 305 additions and 12 deletions.
15 changes: 15 additions & 0 deletions python/core/qgsaction.sip
Expand Up @@ -184,6 +184,21 @@ Checks if the action is runable on the current platform
.. versionadded:: 3.0
%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

};


Expand Down
11 changes: 8 additions & 3 deletions python/core/qgsactionmanager.sip
Expand Up @@ -62,10 +62,15 @@ Constructor
.. versionadded:: 3.0
%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
Does the given action. defaultValueIndex is the index of the
field to be used if the action has a $currfield placeholder.
Does the given action.

\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
Expand Down
15 changes: 15 additions & 0 deletions python/gui/qgsactionmenu.sip
Expand Up @@ -73,6 +73,21 @@ class QgsActionMenu : QMenu
as long as the menu is displayed and the action is running.
%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:
void reinit();

Expand Down
15 changes: 15 additions & 0 deletions python/gui/qgsidentifymenu.sip
Expand Up @@ -74,6 +74,21 @@ define if the menu will be shown with a single idetify result
:rtype: bool
%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 );
%Docstring
define if attribute actions(1) and map layer actions(2) can be listed and run from the menu
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -1273,6 +1273,9 @@ QgisApp::QgisApp()
mUndoWidget = new QgsUndoWidget( nullptr, mMapCanvas );
mInfoBar = new QgsMessageBar( centralWidget() );
mAdvancedDigitizingDockWidget = new QgsAdvancedDigitizingDockWidget( mMapCanvas, this );
mPanelMenu = new QMenu( this );
mProgressBar = new QProgressBar( this );
mStatusBar = new QgsStatusBar( this );
// More tests may need more members to be initialized
}

Expand Down
14 changes: 13 additions & 1 deletion src/app/qgsidentifyresultsdialog.cpp
Expand Up @@ -1164,6 +1164,8 @@ void QgsIdentifyResultsDialog::clear()
delete curve;
mPlotCurves.clear();

mExpressionContextScope = QgsExpressionContextScope();

// keep it visible but disabled, it can switch from disabled/enabled
// after raster format change
mActionPrint->setDisabled( true );
Expand Down Expand Up @@ -1245,7 +1247,7 @@ void QgsIdentifyResultsDialog::doAction( QTreeWidgetItem *item, const QString &a
}

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 )
Expand Down Expand Up @@ -1978,3 +1980,13 @@ void QgsIdentifyResultsDialog::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#identify" ) );
}

void QgsIdentifyResultsDialog::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
}

QgsExpressionContextScope QgsIdentifyResultsDialog::expressionContextScope() const
{
return mExpressionContextScope;
}
18 changes: 18 additions & 0 deletions src/app/qgsidentifyresultsdialog.h
Expand Up @@ -25,6 +25,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsmaptoolidentify.h"
#include "qgswebview.h"
#include "qgsexpressioncontext.h"

#include <QWidget>
#include <QList>
Expand Down Expand Up @@ -150,6 +151,22 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
//! Map tool was activated
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:
void selectedFeatureChanged( QgsVectorLayer *, QgsFeatureId featureId );

Expand Down Expand Up @@ -233,6 +250,7 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
QgsMapCanvas *mCanvas = nullptr;
QList<QgsFeature> mFeatures;
QMap< QString, QMap< QString, QVariant > > mWidgetCaches;
QgsExpressionContextScope mExpressionContextScope;

QgsMapLayer *layer( QTreeWidgetItem *item );
QgsVectorLayer *vectorLayer( QTreeWidgetItem *item );
Expand Down
15 changes: 15 additions & 0 deletions src/app/qgsmaptoolidentifyaction.cpp
Expand Up @@ -37,6 +37,7 @@
#include "qgsrenderer.h"
#include "qgsunittypes.h"
#include "qgsstatusbar.h"
#include "qgsactionscoperegistry.h"

#include "qgssettings.h"
#include <QMouseEvent>
Expand Down Expand Up @@ -119,6 +120,8 @@ void QgsMapToolIdentifyAction::canvasReleaseEvent( QgsMapMouseEvent *e )
connect( this, &QgsMapToolIdentifyAction::identifyProgress, QgisApp::instance(), &QgisApp::showProgress );
connect( this, &QgsMapToolIdentifyAction::identifyMessage, QgisApp::instance(), &QgisApp::showStatusMessage );

setClickContextScope( toMapCoordinates( e->pos() ) );

identifyMenu()->setResultsIfExternalAction( false );

// enable the right click for extended menu so it behaves as a contextual menu
Expand Down Expand Up @@ -201,4 +204,16 @@ void QgsMapToolIdentifyAction::handleCopyToClipboard( QgsFeatureStore &featureSt
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 );
}
}
2 changes: 2 additions & 0 deletions src/app/qgsmaptoolidentifyaction.h
Expand Up @@ -78,7 +78,9 @@ class APP_EXPORT QgsMapToolIdentifyAction : public QgsMapToolIdentify

virtual QgsUnitTypes::DistanceUnit displayDistanceUnits() const override;
virtual QgsUnitTypes::AreaUnit displayAreaUnits() const override;
void setClickContextScope( const QgsPointXY &point );

friend class TestQgsMapToolIdentifyAction;
};

#endif
16 changes: 15 additions & 1 deletion src/core/qgsaction.cpp
Expand Up @@ -59,7 +59,11 @@ void QgsAction::run( const QgsExpressionContext &expressionContext ) const
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 )
{
Expand Down Expand Up @@ -146,3 +150,13 @@ void QgsAction::writeXml( QDomNode &actionsNode ) const

actionsNode.appendChild( actionSetting );
}

void QgsAction::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
}

QgsExpressionContextScope QgsAction::expressionContextScope() const
{
return mExpressionContextScope;
};
15 changes: 15 additions & 0 deletions src/core/qgsaction.h
Expand Up @@ -190,6 +190,20 @@ class CORE_EXPORT QgsAction
*/
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:
ActionType mType = Generic;
QString mDescription;
Expand All @@ -201,6 +215,7 @@ class CORE_EXPORT QgsAction
QString mNotificationMessage;
mutable std::shared_ptr<QAction> mAction;
QUuid mId;
QgsExpressionContextScope mExpressionContextScope;
};

Q_DECLARE_METATYPE( QgsAction )
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsactionmanager.cpp
Expand Up @@ -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();
QgsExpressionContextScope *actionScope = new QgsExpressionContextScope();
QgsExpressionContextScope *actionScope = new QgsExpressionContextScope( scope );
actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_index" ), defaultValueIndex, true ) );
if ( defaultValueIndex >= 0 && defaultValueIndex < feature.fields().size() )
actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "field_name" ), feature.fields().at( defaultValueIndex ).name(), true ) );
Expand Down
13 changes: 9 additions & 4 deletions src/core/qgsactionmanager.h
Expand Up @@ -89,11 +89,16 @@ class CORE_EXPORT QgsActionManager: public QObject
void removeAction( const QUuid &actionId );

/**
* Does the given action. defaultValueIndex is the index of the
* field to be used if the action has a $currfield placeholder.
* \note available in Python bindings as doActionFeature
* Does the given action.
*
* \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
Expand Down
17 changes: 16 additions & 1 deletion src/gui/qgsactionmenu.cpp
Expand Up @@ -107,8 +107,11 @@ void QgsActionMenu::reloadActions()

Q_FOREACH ( const QgsAction &action, mActions )
{
QgsAction act( action );
act.setExpressionContextScope( mExpressionContextScope );

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() );

// Only enable items on supported platforms
Expand Down Expand Up @@ -160,3 +163,15 @@ QgsActionMenu::ActionData::ActionData( const QgsAction &action, QgsFeatureId fea
, featureId( featureId )
, mapLayer( mapLayer )
{}


void QgsActionMenu::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
reloadActions();
}

QgsExpressionContextScope QgsActionMenu::expressionContextScope() const
{
return mExpressionContextScope;
}
15 changes: 15 additions & 0 deletions src/gui/qgsactionmenu.h
Expand Up @@ -91,6 +91,20 @@ class GUI_EXPORT QgsActionMenu : public QMenu
*/
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:
void reinit();

Expand All @@ -107,6 +121,7 @@ class GUI_EXPORT QgsActionMenu : public QMenu
QgsFeature mFeature;
QgsFeatureId mFeatureId;
QString mActionScope;
QgsExpressionContextScope mExpressionContextScope;
};


Expand Down
11 changes: 11 additions & 0 deletions src/gui/qgsidentifymenu.cpp
Expand Up @@ -345,6 +345,7 @@ void QgsIdentifyMenu::addVectorLayer( QgsVectorLayer *layer, const QList<QgsMapT
if ( mShowFeatureActions )
{
featureActionMenu = new QgsActionMenu( layer, result.mFeature, QStringLiteral( "Feature" ), layerMenu );
featureActionMenu->setExpressionContextScope( mExpressionContextScope );
}

// feature title
Expand Down Expand Up @@ -639,3 +640,13 @@ void QgsIdentifyMenu::removeCustomActions()
mCustomActionRegistry.clear();

}

void QgsIdentifyMenu::setExpressionContextScope( const QgsExpressionContextScope &scope )
{
mExpressionContextScope = scope;
}

QgsExpressionContextScope QgsIdentifyMenu::expressionContextScope() const
{
return mExpressionContextScope;
}

0 comments on commit bd30e12

Please sign in to comment.