QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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 <QString>
27
28#include "moc_qgsactionmenu.cpp"
29
30using namespace Qt::StringLiterals;
31
32QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent )
33 : QMenu( parent )
34 , mLayer( layer )
35 , mFeature( feature )
36 , mFeatureId( feature.id() )
37 , mActionScope( actionScope )
38{
39 init();
40}
41
42QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeatureId fid, const QString &actionScope, QWidget *parent )
43 : QMenu( parent )
44 , mLayer( layer )
45 , mFeatureId( fid )
46 , mActionScope( actionScope )
47{
48 init();
49}
50
52{
53 mContextGenerator = generator;
54 reloadActions();
55}
56
57void QgsActionMenu::init()
58{
59 setTitle( tr( "&Actions" ) );
60
61 connect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
62 connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsActionMenu::reloadActions );
63 connect( mLayer, &QgsVectorLayer::editingStopped, this, &QgsActionMenu::reloadActions );
64 connect( mLayer, &QgsVectorLayer::readOnlyChanged, this, &QgsActionMenu::reloadActions );
65 connect( mLayer, &QgsMapLayer::willBeDeleted, this, &QgsActionMenu::layerWillBeDeleted );
66
67 reloadActions();
68}
69
70QgsFeature QgsActionMenu::feature()
71{
72 if ( !mFeature.isValid() )
73 {
74 mLayer->getFeatures( QgsFeatureRequest( mFeatureId ) ).nextFeature( mFeature );
75 }
76
77 return mFeature;
78}
79
81{
82 mFeature = feature;
83}
84
86{
87 mMode = mode;
88 reloadActions();
89}
90
91void QgsActionMenu::triggerAction()
92{
93 if ( !feature().isValid() )
94 return;
95
96 QAction *action = qobject_cast<QAction *>( sender() );
97 if ( !action )
98 return;
99
100 if ( !action->data().isValid() || !action->data().canConvert<ActionData>() )
101 return;
102
103 const ActionData data = action->data().value<ActionData>();
104
105 switch ( data.actionType )
106 {
108 return;
110 {
111 QgsMapLayerAction *mapLayerAction = data.actionData.value<QgsMapLayerAction *>();
112
113 const QgsMapLayerActionContext context = mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext();
115 mapLayerAction->triggerForFeature( data.mapLayer, mFeature );
117 mapLayerAction->triggerForFeature( data.mapLayer, mFeature, context );
118 break;
119 }
121 {
122 const QgsAction act = data.actionData.value<QgsAction>();
123 switch ( act.type() )
124 {
129 {
131 if ( !allowed )
132 {
133 emit messageEmitted( tr( "The action contains embedded scripts which have been denied execution." ), Qgis::MessageLevel::Warning );
134 return;
135 }
136 break;
137 }
138
143 {
144 break;
145 }
146 }
147
148 // define custom substitutions: layer id and clicked coords
149 QgsExpressionContext context = mLayer->createExpressionContext();
150 context.setFeature( mFeature );
151
152 QgsExpressionContextScope *actionScope = new QgsExpressionContextScope();
153 actionScope->addVariable( QgsExpressionContextScope::StaticVariable( u"action_scope"_s, mActionScope, true ) );
154 context << actionScope;
155 act.run( context );
156 break;
157 }
158 }
159}
160
161void QgsActionMenu::reloadActions()
162{
163 clear();
164
165 mVisibleActionCount = 0;
166
167 mActions = mLayer->actions()->actions( mActionScope );
168
169 const auto constMActions = mActions;
170 for ( const QgsAction &action : constMActions )
171 {
172 if ( !mLayer->isEditable() && action.isEnabledOnlyWhenEditable() )
173 continue;
174
175 if ( action.isEnabledOnlyWhenEditable() && ( mMode == QgsAttributeEditorContext::AddFeatureMode || mMode == QgsAttributeEditorContext::IdentifyMode ) )
176 continue;
177
178 QgsAction act( action );
179 act.setExpressionContextScope( mExpressionContextScope );
180
181 QAction *qAction = new QAction( action.icon(), action.name(), this );
182 qAction->setData( QVariant::fromValue<ActionData>( ActionData( act, mFeatureId, mLayer ) ) );
183 qAction->setIcon( action.icon() );
184
185 // Only enable items on supported platforms
186 if ( !action.runable() )
187 {
188 qAction->setEnabled( false );
189 qAction->setToolTip( tr( "Not supported on your platform" ) );
190 }
191 else
192 {
193 qAction->setToolTip( action.command() );
194 }
195 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
196 addAction( qAction );
197
198 mVisibleActionCount++;
199 }
200
201 const QList<QgsMapLayerAction *> mapLayerActions
202 = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, Qgis::MapLayerActionTarget::SingleFeature, mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext() );
203
204 if ( !mapLayerActions.isEmpty() )
205 {
206 //add a separator between user defined and standard actions
207 if ( mVisibleActionCount > 0 )
208 addSeparator();
209
210 for ( int i = 0; i < mapLayerActions.size(); ++i )
211 {
212 QgsMapLayerAction *mapLayerAction = mapLayerActions.at( i );
213
215 continue;
216
217 QAction *qAction = new QAction( mapLayerAction->icon(), mapLayerAction->text(), this );
218 qAction->setData( QVariant::fromValue<ActionData>( ActionData( mapLayerAction, mFeatureId, mLayer ) ) );
219 addAction( qAction );
220 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
221 mVisibleActionCount++;
222 }
223 }
224
225 emit reinit();
226}
227
228void QgsActionMenu::layerWillBeDeleted()
229{
230 // here we are just making sure that we are not going to have reloadActions() called again
231 // with a dangling pointer to a layer when actions get removed on QGIS exit
232 clear();
233 mLayer = nullptr;
234 disconnect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
235}
236
237
239 : actionType( Qgis::ActionType::MapLayerAction )
240 , actionData( QVariant::fromValue<QgsMapLayerAction *>( action ) )
242 , mapLayer( mapLayer )
243{}
244
245
247 : actionType( Qgis::ActionType::AttributeAction )
248 , actionData( QVariant::fromValue<QgsAction>( action ) )
250 , mapLayer( mapLayer )
251{}
252
253
255{
256 mExpressionContextScope = scope;
257 reloadActions();
258}
259
261{
262 return mExpressionContextScope;
263}
264
265QList<QgsAction> QgsActionMenu::menuActions() const
266{
267 return mActions;
268}
269
271{
272 return mVisibleActionCount == 0;
273}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
@ Mac
MacOS specific.
Definition qgis.h:4835
@ OpenUrl
Open URL action.
Definition qgis.h:4838
@ Unix
Unix specific.
Definition qgis.h:4837
@ SubmitUrlMultipart
POST data to an URL using "multipart/form-data".
Definition qgis.h:4840
@ Windows
Windows specific.
Definition qgis.h:4836
@ SubmitUrlEncoded
POST data to an URL, using "application/x-www-form-urlencoded" or "application/json" if the body is v...
Definition qgis.h:4839
@ Warning
Warning message.
Definition qgis.h:162
@ AttributeAction
Custom actions (manually defined in layer properties), corresponds to QgsAction class.
Definition qgis.h:4770
@ Invalid
Invalid.
Definition qgis.h:4768
@ MapLayerAction
Standard actions (defined by core or plugins), corresponds to QgsMapLayerAction class.
Definition qgis.h:4769
@ SingleFeature
Action targets a single feature from a layer.
Definition qgis.h:4784
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:38
Qgis::AttributeActionType type() const
The action type.
Definition qgsaction.h:174
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition qgsaction.cpp:81
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:60
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition qgsgui.cpp:149
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:397
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:83
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:7504
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7503
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Qgis::ActionType actionType