QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsaction.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsaction.cpp - QgsAction
3 
4  ---------------------
5  begin : 18.4.2016
6  copyright : (C) 2016 by Matthias Kuhn
7  email : [email protected]
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsaction.h"
18 
19 #include <QDesktopServices>
20 #include <QFileInfo>
21 #include <QUrl>
22 
23 #include "qgspythonrunner.h"
24 #include "qgsrunprocess.h"
25 #include "qgsexpressioncontext.h"
26 #include "qgsvectorlayer.h"
27 #include "qgslogger.h"
29 
30 bool QgsAction::runable() const
31 {
32  return mType == Generic ||
33  mType == GenericPython ||
34  mType == OpenUrl ||
35 #if defined(Q_OS_WIN)
36  mType == Windows
37 #elif defined(Q_OS_MAC)
38  mType == Mac
39 #else
40  mType == Unix
41 #endif
42  ;
43 }
44 
45 void QgsAction::run( QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext ) const
46 {
47  QgsExpressionContext actionContext( expressionContext );
48 
49  actionContext << QgsExpressionContextUtils::layerScope( layer );
50  actionContext.setFeature( feature );
51 
52  run( actionContext );
53 }
54 
55 void QgsAction::run( const QgsExpressionContext &expressionContext ) const
56 {
57  if ( !isValid() )
58  {
59  QgsDebugMsg( QStringLiteral( "Invalid action cannot be run" ) );
60  return;
61  }
62 
63  QgsExpressionContextScope *scope = new QgsExpressionContextScope( mExpressionContextScope );
64  QgsExpressionContext context( expressionContext );
65  context << scope;
66 
67  QString expandedAction = QgsExpression::replaceExpressionText( mCommand, &context );
68 
69  if ( mType == QgsAction::OpenUrl )
70  {
71  QFileInfo finfo( expandedAction );
72  if ( finfo.exists() && finfo.isFile() )
73  QDesktopServices::openUrl( QUrl::fromLocalFile( expandedAction ) );
74  else
75  QDesktopServices::openUrl( QUrl( expandedAction, QUrl::TolerantMode ) );
76  }
77  else if ( mType == QgsAction::GenericPython )
78  {
79  // TODO: capture output from QgsPythonRunner (like QgsRunProcess does)
80  QgsPythonRunner::run( expandedAction );
81  }
82  else
83  {
84  // The QgsRunProcess instance created by this static function
85  // deletes itself when no longer needed.
86  QgsRunProcess::create( expandedAction, mCaptureOutput );
87  }
88 }
89 
90 QSet<QString> QgsAction::actionScopes() const
91 {
92  return mActionScopes;
93 }
94 
95 void QgsAction::setActionScopes( const QSet<QString> &actionScopes )
96 {
97  mActionScopes = actionScopes;
98 }
99 
100 void QgsAction::readXml( const QDomNode &actionNode )
101 {
102  QDomElement actionElement = actionNode.toElement();
103  QDomNodeList actionScopeNodes = actionElement.elementsByTagName( QStringLiteral( "actionScope" ) );
104 
105  if ( actionScopeNodes.isEmpty() )
106  {
107  mActionScopes
108  << QStringLiteral( "Canvas" )
109  << QStringLiteral( "Field" )
110  << QStringLiteral( "Feature" );
111  }
112  else
113  {
114  for ( int j = 0; j < actionScopeNodes.length(); ++j )
115  {
116  QDomElement actionScopeElem = actionScopeNodes.item( j ).toElement();
117  mActionScopes << actionScopeElem.attribute( QStringLiteral( "id" ) );
118  }
119  }
120 
121  mType = static_cast< QgsAction::ActionType >( actionElement.attributeNode( QStringLiteral( "type" ) ).value().toInt() );
122  mDescription = actionElement.attributeNode( QStringLiteral( "name" ) ).value();
123  mCommand = actionElement.attributeNode( QStringLiteral( "action" ) ).value();
124  mIcon = actionElement.attributeNode( QStringLiteral( "icon" ) ).value();
125  mCaptureOutput = actionElement.attributeNode( QStringLiteral( "capture" ) ).value().toInt() != 0;
126  mShortTitle = actionElement.attributeNode( QStringLiteral( "shortTitle" ) ).value();
127  mNotificationMessage = actionElement.attributeNode( QStringLiteral( "notificationMessage" ) ).value();
128  mIsEnabledOnlyWhenEditable = actionElement.attributeNode( QStringLiteral( "isEnabledOnlyWhenEditable" ) ).value().toInt() != 0;
129  mId = QUuid( actionElement.attributeNode( QStringLiteral( "id" ) ).value() );
130  if ( mId.isNull() )
131  mId = QUuid::createUuid();
132 }
133 
134 void QgsAction::writeXml( QDomNode &actionsNode ) const
135 {
136  QDomElement actionSetting = actionsNode.ownerDocument().createElement( QStringLiteral( "actionsetting" ) );
137  actionSetting.setAttribute( QStringLiteral( "type" ), mType );
138  actionSetting.setAttribute( QStringLiteral( "name" ), mDescription );
139  actionSetting.setAttribute( QStringLiteral( "shortTitle" ), mShortTitle );
140  actionSetting.setAttribute( QStringLiteral( "icon" ), mIcon );
141  actionSetting.setAttribute( QStringLiteral( "action" ), mCommand );
142  actionSetting.setAttribute( QStringLiteral( "capture" ), mCaptureOutput );
143  actionSetting.setAttribute( QStringLiteral( "notificationMessage" ), mNotificationMessage );
144  actionSetting.setAttribute( QStringLiteral( "isEnabledOnlyWhenEditable" ), mIsEnabledOnlyWhenEditable );
145  actionSetting.setAttribute( QStringLiteral( "id" ), mId.toString() );
146 
147  const auto constMActionScopes = mActionScopes;
148  for ( const QString &scope : constMActionScopes )
149  {
150  QDomElement actionScopeElem = actionsNode.ownerDocument().createElement( QStringLiteral( "actionScope" ) );
151  actionScopeElem.setAttribute( QStringLiteral( "id" ), scope );
152  actionSetting.appendChild( actionScopeElem );
153  }
154 
155  actionsNode.appendChild( actionSetting );
156 }
157 
159 {
160  mExpressionContextScope = scope;
161 }
162 
164 {
165  return mExpressionContextScope;
166 };
QSet< QString > actionScopes() const
The action scopes define where an action will be available.
Definition: qgsaction.cpp:90
void readXml(const QDomNode &actionNode)
Reads an XML definition from actionNode into this object.
Definition: qgsaction.cpp:100
void run(QgsVectorLayer *layer, const QgsFeature &feature, const QgsExpressionContext &expressionContext) const
Run this action.
Definition: qgsaction.cpp:45
bool runable() const
Checks if the action is runable on the current platform.
Definition: qgsaction.cpp:30
bool isValid() const
Returns true if this action was a default constructed one.
Definition: qgsaction.h:140
void setExpressionContextScope(const QgsExpressionContextScope &scope)
Sets an expression context scope to use for running the action.
Definition: qgsaction.cpp:158
void writeXml(QDomNode &actionsNode) const
Appends an XML definition for this action as a new child node to actionsNode.
Definition: qgsaction.cpp:134
QgsExpressionContextScope expressionContextScope() const
Returns an expression context scope used for running the action.
Definition: qgsaction.cpp:163
void setActionScopes(const QSet< QString > &actionScopes)
The action scopes define where an action will be available.
Definition: qgsaction.cpp:95
@ GenericPython
Definition: qgsaction.h:40
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
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.
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
static bool run(const QString &command, const QString &messageOnError=QString())
Execute a Python statement.
static QgsRunProcess * create(const QString &action, bool capture)
Definition: qgsrunprocess.h:59
Represents a vector layer which manages a vector based data sets.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38