QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
23 QgsActionMenu::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 
33 QgsActionMenu::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 
42 void 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 
55 QgsFeature QgsActionMenu::feature()
56 {
57  if ( !mFeature.isValid() )
58  {
59  mLayer->getFeatures( QgsFeatureRequest( mFeatureId ) ).nextFeature( mFeature );
60  }
61 
62  return mFeature;
63 }
64 
65 void QgsActionMenu::setFeature( const QgsFeature &feature )
66 {
67  mFeature = feature;
68 }
69 
71 {
72  mMode = mode;
73  reloadActions();
74 }
75 
76 void 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
101  QgsExpressionContext context = mLayer->createExpressionContext();
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 
112 void QgsActionMenu::reloadActions()
113 {
114  clear();
115 
116  mActions = mLayer->actions()->actions( mActionScope );
117 
118  const auto constMActions = mActions;
119  for ( const QgsAction &action : constMActions )
120  {
121  if ( !mLayer->isEditable() && action.isEnabledOnlyWhenEditable() )
122  continue;
123 
124  if ( action.isEnabledOnlyWhenEditable() && ( mMode == QgsAttributeEditorContext::AddFeatureMode || mMode == QgsAttributeEditorContext::IdentifyMode ) )
125  continue;
126 
127  QgsAction act( action );
128  act.setExpressionContextScope( mExpressionContextScope );
129 
130  QAction *qAction = new QAction( action.icon(), action.name(), this );
131  qAction->setData( QVariant::fromValue<ActionData>( ActionData( act, mFeatureId, mLayer ) ) );
132  qAction->setIcon( action.icon() );
133 
134  // Only enable items on supported platforms
135  if ( !action.runable() )
136  {
137  qAction->setEnabled( false );
138  qAction->setToolTip( tr( "Not supported on your platform" ) );
139  }
140  else
141  {
142  qAction->setToolTip( action.command() );
143  }
144  connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
145  addAction( qAction );
146  }
147 
148  const QList<QgsMapLayerAction *> mapLayerActions = QgsGui::mapLayerActionRegistry()->mapLayerActions( mLayer, QgsMapLayerAction::SingleFeature );
149 
150  if ( !mapLayerActions.isEmpty() )
151  {
152  //add a separator between user defined and standard actions
153  addSeparator();
154 
155  for ( int i = 0; i < mapLayerActions.size(); ++i )
156  {
157  QgsMapLayerAction *qaction = mapLayerActions.at( i );
158 
160  continue;
161 
162  QAction *qAction = new QAction( qaction->icon(), qaction->text(), this );
163  qAction->setData( QVariant::fromValue<ActionData>( ActionData( qaction, mFeatureId, mLayer ) ) );
164  addAction( qAction );
165  connect( qAction, &QAction::triggered, this, &QgsActionMenu::triggerAction );
166  }
167  }
168 
169  emit reinit();
170 }
171 
172 void QgsActionMenu::layerWillBeDeleted()
173 {
174  // here we are just making sure that we are not going to have reloadActions() called again
175  // with a dangling pointer to a layer when actions get removed on QGIS exit
176  clear();
177  mLayer = nullptr;
178  disconnect( QgsGui::mapLayerActionRegistry(), &QgsMapLayerActionRegistry::changed, this, &QgsActionMenu::reloadActions );
179 }
180 
181 
183  : actionType( MapLayerAction )
184  , actionData( QVariant::fromValue<QgsMapLayerAction*>( action ) )
185  , featureId( featureId )
186  , mapLayer( mapLayer )
187 {}
188 
189 
191  : actionType( AttributeAction )
192  , actionData( QVariant::fromValue<QgsAction>( action ) )
193  , featureId( featureId )
194  , mapLayer( mapLayer )
195 {}
196 
197 
199 {
200  mExpressionContextScope = scope;
201  reloadActions();
202 }
203 
205 {
206  return mExpressionContextScope;
207 }
208 
209 QList<QgsAction> QgsActionMenu::menuActions()
210 {
211  return mActions;
212 }
QgsActionMenu::Invalid
@ Invalid
Invalid.
Definition: qgsactionmenu.h:44
QgsAction::run
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition: qgsaction.cpp:59
QgsMapLayerAction::triggerForFeature
virtual void triggerForFeature(QgsMapLayer *layer, const QgsFeature &feature)
Triggers the action with the specified layer and feature.
Definition: qgsmaplayeractionregistry.cpp:95
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:1052
QgsMapLayer::willBeDeleted
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsActionMenu::menuActions
QList< QgsAction > menuActions()
Returns menu actions.
Definition: qgsactionmenu.cpp:209
QgsMapLayerActionRegistry::changed
void changed()
Triggered when an action is added or removed from the registry.
QgsActionMenu::MapLayerAction
@ MapLayerAction
Standard actions (defined by core or plugins)
Definition: qgsactionmenu.h:45
QgsMapLayerAction
An action which can run on map layers The class can be used in two manners:
Definition: qgsmaplayeractionregistry.h:38
QgsMapLayer::editingStopped
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
QgsMapLayerAction::SingleFeature
@ SingleFeature
Definition: qgsmaplayeractionregistry.h:46
QgsActionMenu::setMode
void setMode(QgsAttributeEditorContext::Mode mode)
Change the mode of the actions.
Definition: qgsactionmenu.cpp:70
QgsExpressionContextScope::addVariable
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Definition: qgsexpressioncontext.cpp:97
QgsGui::mapLayerActionRegistry
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition: qgsgui.cpp:125
qgsgui.h
QgsAttributeEditorContext::AddFeatureMode
@ AddFeatureMode
Definition: qgsattributeeditorcontext.h:50
qgsfeatureiterator.h
QgsActionMenu::setExpressionContextScope
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope used to resolve underlying actions.
Definition: qgsactionmenu.cpp:198
QgsMapLayer::editingStarted
void editingStarted()
Emitted when editing on this layer has started.
QgsVectorLayer::isEditable
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
Definition: qgsvectorlayer.cpp:3728
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
QgsActionMenu::AttributeAction
@ AttributeAction
Custom actions (manually defined in layer properties)
Definition: qgsactionmenu.h:46
QgsAttributeEditorContext::Mode
Mode
modes
Definition: qgsattributeeditorcontext.h:47
QgsActionMenu::QgsActionMenu
QgsActionMenu(QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent=nullptr)
Constructs a new QgsActionMenu.
Definition: qgsactionmenu.cpp:23
qgsactionmanager.h
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QgsVectorLayer::readOnlyChanged
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
QgsActionManager::actions
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
Definition: qgsactionmanager.cpp:170
QgsMapLayerActionRegistry::mapLayerActions
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
Definition: qgsmaplayeractionregistry.cpp:125
QgsVectorLayer::actions
QgsActionManager * actions()
Returns all layer actions defined on this layer.
Definition: qgsvectorlayer.h:741
qgsmaplayeractionregistry.h
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsAction
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:34
qgsvectorlayer.h
qgsactionmenu.h
QgsActionMenu::ActionData::ActionData
ActionData()=default
Constructor for ActionData.
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsActionMenu::expressionContextScope
QgsExpressionContextScope expressionContextScope() const
Returns an expression context scope used to resolve underlying actions.
Definition: qgsactionmenu.cpp:204
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsActionMenu::reinit
void reinit()
QgsActionMenu::setFeature
void setFeature(const QgsFeature &feature)
Change the feature on which actions are performed.
Definition: qgsactionmenu.cpp:65
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsVectorLayer::createExpressionContext
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsvectorlayer.cpp:5203
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QgsAttributeEditorContext::IdentifyMode
@ IdentifyMode
Identify the feature.
Definition: qgsattributeeditorcontext.h:56
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:525
QgsMapLayerAction::isEnabledOnlyWhenEditable
bool isEnabledOnlyWhenEditable() const
Returns true if the action is only enabled for layers in editable mode.
Definition: qgsmaplayeractionregistry.cpp:105