QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsactionmenu.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsactionmenu.cpp
3 --------------------------------------
4 Date : 11.8.2014
5 Copyright : (C) 2014 Matthias Kuhn
6 Email : matthias at opengis dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsactionmenu.h"
17#include "qgsvectorlayer.h"
19#include "qgsmaplayeraction.h"
21#include "qgsactionmanager.h"
22#include "qgsfeatureiterator.h"
23#include "qgsgui.h"
24
25QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent )
26 : QMenu( parent )
27 , mLayer( layer )
28 , mFeature( feature )
29 , mFeatureId( feature.id() )
30 , mActionScope( actionScope )
31{
32 init();
33}
34
35QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeatureId fid, const QString &actionScope, QWidget *parent )
36 : QMenu( parent )
37 , mLayer( layer )
38 , mFeatureId( fid )
39 , mActionScope( actionScope )
40{
41 init();
42}
43
45{
46 mContextGenerator = generator;
47 reloadActions();
48}
49
50void QgsActionMenu::init()
51{
52 setTitle( tr( "&Actions" ) );
53
54 connect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
55 connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsActionMenu::reloadActions );
56 connect( mLayer, &QgsVectorLayer::editingStopped, this, &QgsActionMenu::reloadActions );
57 connect( mLayer, &QgsVectorLayer::readOnlyChanged, this, &QgsActionMenu::reloadActions );
58 connect( mLayer, &QgsMapLayer::willBeDeleted, this, &QgsActionMenu::layerWillBeDeleted );
59
60 reloadActions();
61}
62
63QgsFeature QgsActionMenu::feature()
64{
65 if ( !mFeature.isValid() )
66 {
67 mLayer->getFeatures( QgsFeatureRequest( mFeatureId ) ).nextFeature( mFeature );
68 }
69
70 return mFeature;
71}
72
74{
75 mFeature = feature;
76}
77
79{
80 mMode = mode;
81 reloadActions();
82}
83
84void QgsActionMenu::triggerAction()
85{
86 if ( !feature().isValid() )
87 return;
88
89 QAction *action = qobject_cast<QAction *>( sender() );
90 if ( !action )
91 return;
92
93 if ( !action->data().isValid() || !action->data().canConvert<ActionData>() )
94 return;
95
96 const ActionData data = action->data().value<ActionData>();
97
98 switch ( data.actionType )
99 {
101 return;
103 {
104 QgsMapLayerAction *mapLayerAction = data.actionData.value<QgsMapLayerAction *>();
105
106 const QgsMapLayerActionContext context = mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext();
108 mapLayerAction->triggerForFeature( data.mapLayer, mFeature );
110 mapLayerAction->triggerForFeature( data.mapLayer, mFeature, context );
111 break;
112 }
114 {
115 // define custom substitutions: layer id and clicked coords
117 context.setFeature( mFeature );
118
120 actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "action_scope" ), mActionScope, true ) );
121 context << actionScope;
122 const QgsAction act = data.actionData.value<QgsAction>();
123 act.run( context );
124 break;
125 }
126 }
127}
128
129void QgsActionMenu::reloadActions()
130{
131 clear();
132
133 mVisibleActionCount = 0;
134
135 mActions = mLayer->actions()->actions( mActionScope );
136
137 const auto constMActions = mActions;
138 for ( const QgsAction &action : constMActions )
139 {
140 if ( !mLayer->isEditable() && action.isEnabledOnlyWhenEditable() )
141 continue;
142
143 if ( action.isEnabledOnlyWhenEditable() && ( mMode == QgsAttributeEditorContext::AddFeatureMode || mMode == QgsAttributeEditorContext::IdentifyMode ) )
144 continue;
145
146 QgsAction act( action );
147 act.setExpressionContextScope( mExpressionContextScope );
148
149 QAction *qAction = new QAction( action.icon(), action.name(), this );
150 qAction->setData( QVariant::fromValue<ActionData>( ActionData( act, mFeatureId, mLayer ) ) );
151 qAction->setIcon( action.icon() );
152
153 // Only enable items on supported platforms
154 if ( !action.runable() )
155 {
156 qAction->setEnabled( false );
157 qAction->setToolTip( tr( "Not supported on your platform" ) );
158 }
159 else
160 {
161 qAction->setToolTip( action.command() );
162 }
163 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
164 addAction( qAction );
165
166 mVisibleActionCount++;
167 }
168
169 const QList<QgsMapLayerAction *> mapLayerActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, Qgis::MapLayerActionTarget::SingleFeature, mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext() );
170
171 if ( !mapLayerActions.isEmpty() )
172 {
173 //add a separator between user defined and standard actions
174 if ( mVisibleActionCount > 0 )
175 addSeparator();
176
177 for ( int i = 0; i < mapLayerActions.size(); ++i )
178 {
179 QgsMapLayerAction *mapLayerAction = mapLayerActions.at( i );
180
182 continue;
183
184 QAction *qAction = new QAction( mapLayerAction->icon(), mapLayerAction->text(), this );
185 qAction->setData( QVariant::fromValue<ActionData>( ActionData( mapLayerAction, mFeatureId, mLayer ) ) );
186 addAction( qAction );
187 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
188 mVisibleActionCount++;
189 }
190 }
191
192 emit reinit();
193}
194
195void QgsActionMenu::layerWillBeDeleted()
196{
197 // here we are just making sure that we are not going to have reloadActions() called again
198 // with a dangling pointer to a layer when actions get removed on QGIS exit
199 clear();
200 mLayer = nullptr;
201 disconnect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
202}
203
204
206 : actionType( Qgis::ActionType::MapLayerAction )
207 , actionData( QVariant::fromValue<QgsMapLayerAction*>( action ) )
208 , featureId( featureId )
209 , mapLayer( mapLayer )
210{}
211
212
214 : actionType( Qgis::ActionType::AttributeAction )
215 , actionData( QVariant::fromValue<QgsAction>( action ) )
216 , featureId( featureId )
217 , mapLayer( mapLayer )
218{}
219
220
222{
223 mExpressionContextScope = scope;
224 reloadActions();
225}
226
228{
229 return mExpressionContextScope;
230}
231
233{
234 return mActions;
235}
236
238{
239 return mVisibleActionCount == 0;
240}
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:54
@ AttributeAction
Custom actions (manually defined in layer properties), corresponds to QgsAction class.
@ Invalid
Invalid.
@ MapLayerAction
Standard actions (defined by core or plugins), corresponds to QgsMapLayerAction class.
@ SingleFeature
Action targets a single feature from a layer.
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QgsActionMenu(QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent=nullptr)
Constructs a new QgsActionMenu.
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope used to resolve underlying actions.
void setMode(QgsAttributeEditorContext::Mode mode)
Change the mode of the actions.
void setActionContextGenerator(QgsMapLayerActionContextGenerator *generator)
Sets a QgsMapLayerActionContextGenerator to create action contexts for the menu.
void setFeature(const QgsFeature &feature)
Change the feature on which actions are performed.
QgsExpressionContextScope expressionContextScope() const
Returns an expression context scope used to resolve underlying actions.
QList< QgsAction > menuActions()
Returns menu actions.
bool isEmpty() const
Returns true if the menu has no valid actions.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:37
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition: qgsaction.cpp:78
@ IdentifyMode
Identify the feature.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition: qgsgui.cpp:129
An interface for objects which can create a QgsMapLayerActionContext.
virtual QgsMapLayerActionContext createActionContext()=0
Creates a QgsMapLayerActionContext.
Encapsulates the context in which a QgsMapLayerAction action is executed.
void changed()
Triggered when an action is added or removed from the registry.
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, Qgis::MapLayerActionTargets targets=Qgis::MapLayerActionTarget::AllActions, const QgsMapLayerActionContext &context=QgsMapLayerActionContext())
Returns the map layer actions which can run on the specified layer.
An action which can run on map layers The class can be used in two manners:
bool isEnabledOnlyWhenEditable() const
Returns true if the action is only enabled for layers in editable mode.
virtual Q_DECL_DEPRECATED void triggerForFeature(QgsMapLayer *layer, const QgsFeature &feature)
Triggers the action with the specified layer and feature.
Base class for all map layer types.
Definition: qgsmaplayer.h:75
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
void editingStarted()
Emitted when editing on this layer has started.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
ActionData()=default
Constructor for ActionData.
Single variable definition for use within a QgsExpressionContextScope.