QGIS API Documentation 3.99.0-Master (d270888f95f)
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 = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, Qgis::MapLayerActionTarget::SingleFeature, mContextGenerator ? mContextGenerator->createActionContext() : QgsMapLayerActionContext() );
202
203 if ( !mapLayerActions.isEmpty() )
204 {
205 //add a separator between user defined and standard actions
206 if ( mVisibleActionCount > 0 )
207 addSeparator();
208
209 for ( int i = 0; i < mapLayerActions.size(); ++i )
210 {
211 QgsMapLayerAction *mapLayerAction = mapLayerActions.at( i );
212
214 continue;
215
216 QAction *qAction = new QAction( mapLayerAction->icon(), mapLayerAction->text(), this );
217 qAction->setData( QVariant::fromValue<ActionData>( ActionData( mapLayerAction, mFeatureId, mLayer ) ) );
218 addAction( qAction );
219 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
220 mVisibleActionCount++;
221 }
222 }
223
224 emit reinit();
225}
226
227void QgsActionMenu::layerWillBeDeleted()
228{
229 // here we are just making sure that we are not going to have reloadActions() called again
230 // with a dangling pointer to a layer when actions get removed on QGIS exit
231 clear();
232 mLayer = nullptr;
233 disconnect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
234}
235
236
238 : actionType( Qgis::ActionType::MapLayerAction )
239 , actionData( QVariant::fromValue<QgsMapLayerAction *>( action ) )
241 , mapLayer( mapLayer )
242{}
243
244
246 : actionType( Qgis::ActionType::AttributeAction )
247 , actionData( QVariant::fromValue<QgsAction>( action ) )
249 , mapLayer( mapLayer )
250{}
251
252
254{
255 mExpressionContextScope = scope;
256 reloadActions();
257}
258
260{
261 return mExpressionContextScope;
262}
263
264QList<QgsAction> QgsActionMenu::menuActions() const
265{
266 return mActions;
267}
268
270{
271 return mVisibleActionCount == 0;
272}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:59
@ Mac
MacOS specific.
Definition qgis.h:4750
@ OpenUrl
Open URL action.
Definition qgis.h:4753
@ Unix
Unix specific.
Definition qgis.h:4752
@ SubmitUrlMultipart
POST data to an URL using "multipart/form-data".
Definition qgis.h:4755
@ Windows
Windows specific.
Definition qgis.h:4751
@ SubmitUrlEncoded
POST data to an URL, using "application/x-www-form-urlencoded" or "application/json" if the body is v...
Definition qgis.h:4754
@ Warning
Warning message.
Definition qgis.h:161
@ AttributeAction
Custom actions (manually defined in layer properties), corresponds to QgsAction class.
Definition qgis.h:4685
@ Invalid
Invalid.
Definition qgis.h:4683
@ MapLayerAction
Standard actions (defined by core or plugins), corresponds to QgsMapLayerAction class.
Definition qgis.h:4684
@ SingleFeature
Action targets a single feature from a layer.
Definition qgis.h:4699
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:154
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:7451
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7450
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Qgis::ActionType actionType