QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
18#include "qgsactionmanager.h"
19#include "qgsfeatureiterator.h"
20#include "qgsgui.h"
21#include "qgsmaplayeraction.h"
24#include "qgsvectorlayer.h"
25
26#include "moc_qgsactionmenu.cpp"
27
28QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent )
29 : QMenu( parent )
30 , mLayer( layer )
31 , mFeature( feature )
32 , mFeatureId( feature.id() )
33 , mActionScope( actionScope )
34{
35 init();
36}
37
38QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeatureId fid, const QString &actionScope, QWidget *parent )
39 : QMenu( parent )
40 , mLayer( layer )
41 , mFeatureId( fid )
42 , mActionScope( actionScope )
43{
44 init();
45}
46
48{
49 mContextGenerator = generator;
50 reloadActions();
51}
52
53void QgsActionMenu::init()
54{
55 setTitle( tr( "&Actions" ) );
56
57 connect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
58 connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsActionMenu::reloadActions );
59 connect( mLayer, &QgsVectorLayer::editingStopped, this, &QgsActionMenu::reloadActions );
60 connect( mLayer, &QgsVectorLayer::readOnlyChanged, this, &QgsActionMenu::reloadActions );
61 connect( mLayer, &QgsMapLayer::willBeDeleted, this, &QgsActionMenu::layerWillBeDeleted );
62
63 reloadActions();
64}
65
66QgsFeature QgsActionMenu::feature()
67{
68 if ( !mFeature.isValid() )
69 {
70 mLayer->getFeatures( QgsFeatureRequest( mFeatureId ) ).nextFeature( mFeature );
71 }
72
73 return mFeature;
74}
75
77{
78 mFeature = feature;
79}
80
82{
83 mMode = mode;
84 reloadActions();
85}
86
87void QgsActionMenu::triggerAction()
88{
89 if ( !feature().isValid() )
90 return;
91
92 QAction *action = qobject_cast<QAction *>( sender() );
93 if ( !action )
94 return;
95
96 if ( !action->data().isValid() || !action->data().canConvert<ActionData>() )
97 return;
98
99 const ActionData data = action->data().value<ActionData>();
100
101 switch ( data.actionType )
102 {
104 return;
106 {
107 QgsMapLayerAction *mapLayerAction = data.actionData.value<QgsMapLayerAction *>();
108
109 const QgsMapLayerActionContext context = mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext();
111 mapLayerAction->triggerForFeature( data.mapLayer, mFeature );
113 mapLayerAction->triggerForFeature( data.mapLayer, mFeature, context );
114 break;
115 }
117 {
118 const QgsAction act = data.actionData.value<QgsAction>();
119 switch ( act.type() )
120 {
125 {
127 if ( !allowed )
128 {
129 emit messageEmitted( tr( "The action contains embedded scripts which have been denied execution." ), Qgis::MessageLevel::Warning );
130 return;
131 }
132 break;
133 }
134
139 {
140 break;
141 }
142 }
143
144 // define custom substitutions: layer id and clicked coords
145 QgsExpressionContext context = mLayer->createExpressionContext();
146 context.setFeature( mFeature );
147
148 QgsExpressionContextScope *actionScope = new QgsExpressionContextScope();
149 actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "action_scope" ), mActionScope, true ) );
150 context << actionScope;
151 act.run( context );
152 break;
153 }
154 }
155}
156
157void QgsActionMenu::reloadActions()
158{
159 clear();
160
161 mVisibleActionCount = 0;
162
163 mActions = mLayer->actions()->actions( mActionScope );
164
165 const auto constMActions = mActions;
166 for ( const QgsAction &action : constMActions )
167 {
168 if ( !mLayer->isEditable() && action.isEnabledOnlyWhenEditable() )
169 continue;
170
171 if ( action.isEnabledOnlyWhenEditable() && ( mMode == QgsAttributeEditorContext::AddFeatureMode || mMode == QgsAttributeEditorContext::IdentifyMode ) )
172 continue;
173
174 QgsAction act( action );
175 act.setExpressionContextScope( mExpressionContextScope );
176
177 QAction *qAction = new QAction( action.icon(), action.name(), this );
178 qAction->setData( QVariant::fromValue<ActionData>( ActionData( act, mFeatureId, mLayer ) ) );
179 qAction->setIcon( action.icon() );
180
181 // Only enable items on supported platforms
182 if ( !action.runable() )
183 {
184 qAction->setEnabled( false );
185 qAction->setToolTip( tr( "Not supported on your platform" ) );
186 }
187 else
188 {
189 qAction->setToolTip( action.command() );
190 }
191 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
192 addAction( qAction );
193
194 mVisibleActionCount++;
195 }
196
197 const QList<QgsMapLayerAction *> mapLayerActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, Qgis::MapLayerActionTarget::SingleFeature, mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext() );
198
199 if ( !mapLayerActions.isEmpty() )
200 {
201 //add a separator between user defined and standard actions
202 if ( mVisibleActionCount > 0 )
203 addSeparator();
204
205 for ( int i = 0; i < mapLayerActions.size(); ++i )
206 {
207 QgsMapLayerAction *mapLayerAction = mapLayerActions.at( i );
208
210 continue;
211
212 QAction *qAction = new QAction( mapLayerAction->icon(), mapLayerAction->text(), this );
213 qAction->setData( QVariant::fromValue<ActionData>( ActionData( mapLayerAction, mFeatureId, mLayer ) ) );
214 addAction( qAction );
215 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
216 mVisibleActionCount++;
217 }
218 }
219
220 emit reinit();
221}
222
223void QgsActionMenu::layerWillBeDeleted()
224{
225 // here we are just making sure that we are not going to have reloadActions() called again
226 // with a dangling pointer to a layer when actions get removed on QGIS exit
227 clear();
228 mLayer = nullptr;
229 disconnect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
230}
231
232
234 : actionType( Qgis::ActionType::MapLayerAction )
235 , actionData( QVariant::fromValue<QgsMapLayerAction *>( action ) )
237 , mapLayer( mapLayer )
238{}
239
240
242 : actionType( Qgis::ActionType::AttributeAction )
243 , actionData( QVariant::fromValue<QgsAction>( action ) )
245 , mapLayer( mapLayer )
246{}
247
248
250{
251 mExpressionContextScope = scope;
252 reloadActions();
253}
254
256{
257 return mExpressionContextScope;
258}
259
260QList<QgsAction> QgsActionMenu::menuActions() const
261{
262 return mActions;
263}
264
266{
267 return mVisibleActionCount == 0;
268}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:56
@ Mac
MacOS specific.
Definition qgis.h:4678
@ OpenUrl
Open URL action.
Definition qgis.h:4681
@ Unix
Unix specific.
Definition qgis.h:4680
@ SubmitUrlMultipart
POST data to an URL using "multipart/form-data".
Definition qgis.h:4683
@ Windows
Windows specific.
Definition qgis.h:4679
@ SubmitUrlEncoded
POST data to an URL, using "application/x-www-form-urlencoded" or "application/json" if the body is v...
Definition qgis.h:4682
@ Warning
Warning message.
Definition qgis.h:158
@ AttributeAction
Custom actions (manually defined in layer properties), corresponds to QgsAction class.
Definition qgis.h:4613
@ Invalid
Invalid.
Definition qgis.h:4611
@ MapLayerAction
Standard actions (defined by core or plugins), corresponds to QgsMapLayerAction class.
Definition qgis.h:4612
@ SingleFeature
Action targets a single feature from a layer.
Definition qgis.h:4627
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 messageEmitted(const QString &message, Qgis::MessageLevel level=Qgis::MessageLevel::Info)
Emitted when a message should be shown to the user in the application message bar.
void setMode(QgsAttributeEditorContext::Mode mode)
Change the mode of the actions.
void reinit()
Emitted after actions have been reloaded.
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() const
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
Qgis::AttributeActionType type() const
The action type.
Definition qgsaction.h:153
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition qgsaction.cpp:78
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope to use for running the action.
@ 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.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition qgsgui.cpp:146
static bool allowExecutionOfEmbeddedScripts(QgsProject *project, QgsMessageBar *messageBar=nullptr)
Returns true if python embedded in a project is currently allowed to be loaded.
Definition qgsgui.cpp:394
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.
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:80
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...
static QgsProject * instance()
Returns the QgsProject singleton instance.
Represents a vector layer which manages a vector based dataset.
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7170
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7169
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Qgis::ActionType actionType