QGIS API Documentation 3.28.14-Firenze (exported)
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#include "qgsvectorlayer.h"
19#include "qgsactionmanager.h"
20#include "qgsfeatureiterator.h"
21#include "qgsgui.h"
22
23QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent )
24 : QMenu( parent )
25 , mLayer( layer )
26 , mFeature( feature )
27 , mFeatureId( feature.id() )
28 , mActionScope( actionScope )
29{
30 init();
31}
32
33QgsActionMenu::QgsActionMenu( QgsVectorLayer *layer, const QgsFeatureId fid, const QString &actionScope, QWidget *parent )
34 : QMenu( parent )
35 , mLayer( layer )
36 , mFeatureId( fid )
37 , mActionScope( actionScope )
38{
39 init();
40}
41
42void QgsActionMenu::init()
43{
44 setTitle( tr( "&Actions" ) );
45
46 connect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
47 connect( mLayer, &QgsVectorLayer::editingStarted, this, &QgsActionMenu::reloadActions );
48 connect( mLayer, &QgsVectorLayer::editingStopped, this, &QgsActionMenu::reloadActions );
49 connect( mLayer, &QgsVectorLayer::readOnlyChanged, this, &QgsActionMenu::reloadActions );
50 connect( mLayer, &QgsMapLayer::willBeDeleted, this, &QgsActionMenu::layerWillBeDeleted );
51
52 reloadActions();
53}
54
55QgsFeature QgsActionMenu::feature()
56{
57 if ( !mFeature.isValid() )
58 {
59 mLayer->getFeatures( QgsFeatureRequest( mFeatureId ) ).nextFeature( mFeature );
60 }
61
62 return mFeature;
63}
64
66{
67 mFeature = feature;
68}
69
71{
72 mMode = mode;
73 reloadActions();
74}
75
76void QgsActionMenu::triggerAction()
77{
78 if ( !feature().isValid() )
79 return;
80
81 QAction *action = qobject_cast<QAction *>( sender() );
82 if ( !action )
83 return;
84
85 if ( !action->data().isValid() || !action->data().canConvert<ActionData>() )
86 return;
87
88 const ActionData data = action->data().value<ActionData>();
89
90 if ( data.actionType == Invalid )
91 return;
92
93 if ( data.actionType == MapLayerAction )
94 {
95 QgsMapLayerAction *mapLayerAction = data.actionData.value<QgsMapLayerAction *>();
96 mapLayerAction->triggerForFeature( data.mapLayer, mFeature );
97 }
98 else if ( data.actionType == AttributeAction )
99 {
100 // define custom substitutions: layer id and clicked coords
102 context.setFeature( mFeature );
103
105 actionScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "action_scope" ), mActionScope, true ) );
106 context << actionScope;
107 const QgsAction act = data.actionData.value<QgsAction>();
108 act.run( context );
109 }
110}
111
112void QgsActionMenu::reloadActions()
113{
114 clear();
115
116 mVisibleActionCount = 0;
117
118 mActions = mLayer->actions()->actions( mActionScope );
119
120 const auto constMActions = mActions;
121 for ( const QgsAction &action : constMActions )
122 {
123 if ( !mLayer->isEditable() && action.isEnabledOnlyWhenEditable() )
124 continue;
125
126 if ( action.isEnabledOnlyWhenEditable() && ( mMode == QgsAttributeEditorContext::AddFeatureMode || mMode == QgsAttributeEditorContext::IdentifyMode ) )
127 continue;
128
129 QgsAction act( action );
130 act.setExpressionContextScope( mExpressionContextScope );
131
132 QAction *qAction = new QAction( action.icon(), action.name(), this );
133 qAction->setData( QVariant::fromValue<ActionData>( ActionData( act, mFeatureId, mLayer ) ) );
134 qAction->setIcon( action.icon() );
135
136 // Only enable items on supported platforms
137 if ( !action.runable() )
138 {
139 qAction->setEnabled( false );
140 qAction->setToolTip( tr( "Not supported on your platform" ) );
141 }
142 else
143 {
144 qAction->setToolTip( action.command() );
145 }
146 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
147 addAction( qAction );
148
149 mVisibleActionCount++;
150 }
151
152 const QList<QgsMapLayerAction *> mapLayerActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, QgsMapLayerAction::SingleFeature );
153
154 if ( !mapLayerActions.isEmpty() )
155 {
156 //add a separator between user defined and standard actions
157 if ( mVisibleActionCount > 0 )
158 addSeparator();
159
160 for ( int i = 0; i < mapLayerActions.size(); ++i )
161 {
162 QgsMapLayerAction *mapLayerAction = mapLayerActions.at( i );
163
165 continue;
166
167 QAction *qAction = new QAction( mapLayerAction->icon(), mapLayerAction->text(), this );
168 qAction->setData( QVariant::fromValue<ActionData>( ActionData( mapLayerAction, mFeatureId, mLayer ) ) );
169 addAction( qAction );
170 connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
171 mVisibleActionCount++;
172 }
173 }
174
175 emit reinit();
176}
177
178void QgsActionMenu::layerWillBeDeleted()
179{
180 // here we are just making sure that we are not going to have reloadActions() called again
181 // with a dangling pointer to a layer when actions get removed on QGIS exit
182 clear();
183 mLayer = nullptr;
184 disconnect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
185}
186
187
189 : actionType( MapLayerAction )
190 , actionData( QVariant::fromValue<QgsMapLayerAction*>( action ) )
191 , featureId( featureId )
192 , mapLayer( mapLayer )
193{}
194
195
197 : actionType( AttributeAction )
198 , actionData( QVariant::fromValue<QgsAction>( action ) )
199 , featureId( featureId )
200 , mapLayer( mapLayer )
201{}
202
203
205{
206 mExpressionContextScope = scope;
207 reloadActions();
208}
209
211{
212 return mExpressionContextScope;
213}
214
216{
217 return mActions;
218}
219
221{
222 return mVisibleActionCount == 0;
223}
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.
@ Invalid
Invalid.
@ AttributeAction
Custom actions (manually defined in layer properties)
@ MapLayerAction
Standard actions (defined by core or plugins)
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:35
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition qgsaction.cpp:59
@ 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)
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.
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition qgsgui.cpp:123
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
void changed()
Triggered when an action is added or removed from the registry.
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 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:73
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.
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
ActionData()=default
Constructor for ActionData.
Single variable definition for use within a QgsExpressionContextScope.