QGIS API Documentation  3.13.0-Master (740be229cb)
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  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  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  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 
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 }
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
void setFeature(const QgsFeature &feature)
Change the feature on which actions are performed.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
Single variable definition for use within a QgsExpressionContextScope.
Base class for all map layer types.
Definition: qgsmaplayer.h:80
void triggerForFeature(QgsMapLayer *layer, const QgsFeature &feature)
Triggers the action with the specified layer and feature.
bool isEnabledOnlyWhenEditable() const
Returns true if the action is only enabled for layers in editable mode.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QgsExpressionContextScope expressionContextScope() const
Returns an expression context scope used to resolve underlying actions.
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
void readOnlyChanged()
Emitted when the read only state of this layer is changed.
QgsActionMenu(QgsVectorLayer *layer, const QgsFeature &feature, const QString &actionScope, QWidget *parent=nullptr)
Constructs a new QgsActionMenu.
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Standard actions (defined by core or plugins)
Definition: qgsactionmenu.h:45
void setMode(QgsAttributeEditorContext::Mode mode)
Change the mode of the actions.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition: qgsaction.cpp:45
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:35
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void changed()
Triggered when an action is added or removed from the registry.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void editingStarted()
Emitted when editing on this layer has started.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Custom actions (manually defined in layer properties)
Definition: qgsactionmenu.h:46
QList< QgsMapLayerAction * > mapLayerActions(QgsMapLayer *layer, QgsMapLayerAction::Targets targets=QgsMapLayerAction::AllActions)
Returns the map layer actions which can run on the specified layer.
ActionData()=default
Constructor for ActionData.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsActionMenu::ActionType actionType
Definition: qgsactionmenu.h:59
QList< QgsAction > menuActions()
Returns menu actions.
bool nextFeature(QgsFeature &f)
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope used to resolve underlying actions.
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope to use for running the action.
Definition: qgsaction.cpp:158
Represents a vector layer which manages a vector based data sets.
static QgsMapLayerActionRegistry * mapLayerActionRegistry()
Returns the global map layer action registry, used for registering map layer actions.
Definition: qgsgui.cpp:93
An action which can run on map layers.