From a6eb7b62811cb80dc2ccf3810dc168086d5d3380 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Thu, 3 Nov 2016 22:48:19 +0100 Subject: [PATCH] Convert action ids to uuid --- python/core/qgsaction.sip | 46 +++++++++- python/core/qgsactionmanager.sip | 23 +++-- python/core/qgsapplication.sip | 2 +- python/gui/attributetable/qgsdualview.sip | 2 +- src/app/qgsfeatureaction.cpp | 2 +- src/app/qgsfeatureaction.h | 5 +- src/core/qgsaction.cpp | 53 ++++++++++++ src/core/qgsaction.h | 30 +++++-- src/core/qgsactionmanager.cpp | 85 +++++-------------- src/core/qgsactionmanager.h | 20 ++--- src/core/qgsapplication.h | 2 +- src/core/qgsvectorlayer.cpp | 2 +- .../attributetable/qgsattributetablemodel.cpp | 2 +- .../attributetable/qgsattributetablemodel.h | 2 +- src/gui/attributetable/qgsdualview.h | 9 +- tests/src/python/test_qgsactionmanager.py | 49 +++++------ 16 files changed, 201 insertions(+), 133 deletions(-) diff --git a/python/core/qgsaction.sip b/python/core/qgsaction.sip index 88aa56c21551..2ae1d0544424 100644 --- a/python/core/qgsaction.sip +++ b/python/core/qgsaction.sip @@ -33,6 +33,32 @@ class QgsAction OpenUrl, }; + /** + * Default constructor + */ + QgsAction(); + + /** + * Create a new QgsAction + * + * @param type The type of this action + * @param description A human readable description string + * @param command The action text. Its interpretation depends on the type + * @param capture If this is set to true, the output will be captured when an action is run + */ + QgsAction( ActionType type, const QString& description, const QString& command, bool capture = false ); + + /** + * Create a new QgsAction + * + * @param type The type of this action + * @param description A human readable description string + * @param action The action text. Its interpretation depends on the type + * @param icon Path to an icon for this action + * @param capture If this is set to true, the output will be captured when an action is run + * @param shortTitle A short string used to label user interface elements like buttons + * @param actionScopes A set of scopes in which this action will be available + */ QgsAction( ActionType type, const QString& description, const QString& action, const QString& icon, bool capture, const QString& shortTitle = QString(), const QSet& actionScopes = QSet() ); //! The name of the action. This may be a longer description. @@ -46,14 +72,14 @@ class QgsAction * * @note Added in QGIS 3.0 */ - QString id() const { return mShortTitle; } + QUuid id() const; /** * Returns true if this action was a default constructed one. * * @note Added in QGIS 3.0 */ - bool isValid() const { return !mShortTitle.isNull(); } + bool isValid() const; //! The path to the icon QString iconPath() const; @@ -105,4 +131,20 @@ class QgsAction * @note Added in QGIS 3.0 */ void setActionScopes( const QSet& actionScopes ); + + /** + * Reads an XML definition from actionNode + * into this object. + * + * @note Added in QGIS 3.0 + */ + void readXml( const QDomNode& actionNode ); + + /** + * Appends an XML definition for this action as a new + * child node to actionsNode. + * + * @note Added in QGIS 3.0 + */ + void writeXml(QDomNode& actionsNode ) const; }; diff --git a/python/core/qgsactionmanager.sip b/python/core/qgsactionmanager.sip index d3003ad66ed5..81b70794ae85 100644 --- a/python/core/qgsactionmanager.sip +++ b/python/core/qgsactionmanager.sip @@ -44,7 +44,7 @@ class QgsActionManager * any stdout from the process will be captured and displayed in a * dialog box. */ - void addAction( QgsAction::ActionType type, const QString& name, const QString& action, bool capture = false ); + QUuid addAction(QgsAction::ActionType type, const QString& name, const QString& command, bool capture = false ); /** Add an action with the given name and action details. * Will happily have duplicate names and actions. If @@ -52,7 +52,7 @@ class QgsActionManager * any stdout from the process will be captured and displayed in a * dialog box. */ - void addAction( QgsAction::ActionType type, const QString& name, const QString& action, const QString& icon, bool capture = false ); + QUuid addAction(QgsAction::ActionType type, const QString& name, const QString& command, const QString& icon, bool capture = false ); /** * Add a new action to this list. @@ -63,9 +63,7 @@ class QgsActionManager * field to be used if the action has a $currfield placeholder. * @note available in python bindings as doActionFeature */ - void doAction( const QString& actionId, - const QgsFeature &feat, - int defaultValueIndex = 0 ) /PyName=doActionFeature/; + void doAction(const QUuid& actionId, const QgsFeature& feature, int defaultValueIndex = 0 ) /PyName=doActionFeature/; /** Does the action using the expression engine to replace any embedded expressions * in the action definition. @@ -73,21 +71,22 @@ class QgsActionManager * @param feature feature to run action for * @param context expression context to evalute expressions under */ - void doAction( const QString& actionId, - const QgsFeature& feature, - const QgsExpressionContext& context ); + void doAction( const QUuid& actionId, const QgsFeature& feature, const QgsExpressionContext& context ); //! Removes all actions void clearActions(); - //! List all actions + /** + * Return a list of actions that are available in the given action scope. + * If no action scope is provided, all actions will be returned. + */ QList listActions( const QString& actionScope = QString() ) const; //! Return the layer QgsVectorLayer* layer() const; //! Writes the actions out in XML format - bool writeXml( QDomNode& layer_node, QDomDocument& doc ) const; + bool writeXml( QDomNode& layer_node ) const; //! Reads the actions in in XML format bool readXml( const QDomNode& layer_node ); @@ -97,7 +96,7 @@ class QgsActionManager * * @note Added in QGIS 3.0 */ - QgsAction action( const QString& id ); + QgsAction action( const QUuid& id ); /** * Each scope can have a default action. This will be saved in the project @@ -105,7 +104,7 @@ class QgsActionManager * * @note Added in QGIS 3.0 */ - void setDefaultAction( const QString& actionScope, const QString& actionId ); + void setDefaultAction( const QString& actionScope, const QUuid& actionId ); /** * Each scope can have a default action. This will be saved in the project diff --git a/python/core/qgsapplication.sip b/python/core/qgsapplication.sip index 59aeeaafa55f..ce464b8117f0 100644 --- a/python/core/qgsapplication.sip +++ b/python/core/qgsapplication.sip @@ -381,7 +381,7 @@ static void qtgui_UpdatePyArgv(PyObject *argvlist, int argc, char **argv) /** * Returns the action scope registry. * - * @Note Added in QGIS 3.0 + * @note Added in QGIS 3.0 */ static QgsActionScopeRegistry* actionScopeRegistry(); diff --git a/python/gui/attributetable/qgsdualview.sip b/python/gui/attributetable/qgsdualview.sip index 40c533f02041..966c5a1f794c 100644 --- a/python/gui/attributetable/qgsdualview.sip +++ b/python/gui/attributetable/qgsdualview.sip @@ -229,7 +229,7 @@ class QgsAttributeTableAction : QAction %End public: - QgsAttributeTableAction( const QString &name, QgsDualView *dualView, const QString& action, const QModelIndex &fieldIdx ); + QgsAttributeTableAction( const QString& name, QgsDualView* dualView, const QUuid& action, const QModelIndex& fieldIdx ); public slots: void execute(); diff --git a/src/app/qgsfeatureaction.cpp b/src/app/qgsfeatureaction.cpp index 8012c2e79b1e..332bfd994296 100644 --- a/src/app/qgsfeatureaction.cpp +++ b/src/app/qgsfeatureaction.cpp @@ -32,7 +32,7 @@ #include #include -QgsFeatureAction::QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *layer, const QString& actionId, int defaultAttr, QObject *parent ) +QgsFeatureAction::QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *layer, const QUuid& actionId, int defaultAttr, QObject *parent ) : QAction( name, parent ) , mLayer( layer ) , mFeature( &f ) diff --git a/src/app/qgsfeatureaction.h b/src/app/qgsfeatureaction.h index 9b46923c110f..6f9688ad3bb4 100644 --- a/src/app/qgsfeatureaction.h +++ b/src/app/qgsfeatureaction.h @@ -22,6 +22,7 @@ #include #include #include +#include class QgsIdentifyResultsDialog; class QgsVectorLayer; @@ -33,7 +34,7 @@ class APP_EXPORT QgsFeatureAction : public QAction Q_OBJECT public: - QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *vl, const QString& actionId = QString(), int defaultAttr = -1, QObject *parent = nullptr ); + QgsFeatureAction( const QString &name, QgsFeature &f, QgsVectorLayer *vl, const QUuid& actionId = QString(), int defaultAttr = -1, QObject *parent = nullptr ); public slots: void execute(); @@ -59,7 +60,7 @@ class APP_EXPORT QgsFeatureAction : public QAction QgsVectorLayer* mLayer; QgsFeature* mFeature; - QString mActionId; + QUuid mActionId; int mIdx; bool mFeatureSaved; diff --git a/src/core/qgsaction.cpp b/src/core/qgsaction.cpp index 7116fb92d4ca..6def7a2252ea 100644 --- a/src/core/qgsaction.cpp +++ b/src/core/qgsaction.cpp @@ -91,3 +91,56 @@ void QgsAction::setActionScopes( const QSet& actionScopes ) { mActionScopes = actionScopes; } + +void QgsAction::readXml( const QDomNode& actionNode ) +{ + QDomElement actionElement = actionNode.toElement(); + QDomNodeList actionScopeNodes = actionElement.elementsByTagName( "actionScope" ); + + if ( actionScopeNodes.isEmpty() ) + { + mActionScopes + << QStringLiteral( "Canvas" ) + << QStringLiteral( "Field" ) + << QStringLiteral( "Feature" ); + } + else + { + for ( int j = 0; j < actionScopeNodes.length(); ++j ) + { + QDomElement actionScopeElem = actionScopeNodes.item( j ).toElement(); + mActionScopes << actionScopeElem.attribute( "id" ); + } + } + + mType = static_cast< QgsAction::ActionType >( actionElement.attributeNode( QStringLiteral( "type" ) ).value().toInt() ); + mDescription = actionElement.attributeNode( QStringLiteral( "name" ) ).value(); + mCommand = actionElement.attributeNode( QStringLiteral( "action" ) ).value(); + mIcon = actionElement.attributeNode( QStringLiteral( "icon" ) ).value(); + mCaptureOutput = actionElement.attributeNode( QStringLiteral( "capture" ) ).value().toInt() != 0; + mShortTitle = actionElement.attributeNode( QStringLiteral( "shortTitle" ) ).value(); + mId = QUuid( actionElement.attributeNode( QStringLiteral( "id" ) ).value() ); + if ( mId.isNull() ) + mId = QUuid::createUuid(); +} + +void QgsAction::writeXml( QDomNode& actionsNode ) const +{ + QDomElement actionSetting = actionsNode.ownerDocument().createElement( QStringLiteral( "actionsetting" ) ); + actionSetting.setAttribute( QStringLiteral( "type" ), mType ); + actionSetting.setAttribute( QStringLiteral( "name" ), mDescription ); + actionSetting.setAttribute( QStringLiteral( "shortTitle" ), mShortTitle ); + actionSetting.setAttribute( QStringLiteral( "icon" ), mIcon ); + actionSetting.setAttribute( QStringLiteral( "action" ), mCommand ); + actionSetting.setAttribute( QStringLiteral( "capture" ), mCaptureOutput ); + actionSetting.setAttribute( QStringLiteral( "id" ), mId.toString() ); + + Q_FOREACH ( const QString& scope, mActionScopes ) + { + QDomElement actionScopeElem = actionsNode.ownerDocument().createElement( "actionScope" ); + actionScopeElem.setAttribute( "id", scope ); + actionSetting.appendChild( actionScopeElem ); + } + + actionsNode.appendChild( actionSetting ); +} diff --git a/src/core/qgsaction.h b/src/core/qgsaction.h index 106be56aeb3f..b170160c026a 100644 --- a/src/core/qgsaction.h +++ b/src/core/qgsaction.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "qgsexpressioncontext.h" @@ -53,14 +54,15 @@ class CORE_EXPORT QgsAction * * @param type The type of this action * @param description A human readable description string - * @param action The action text. Its interpretation depends on the type + * @param command The action text. Its interpretation depends on the type * @param capture If this is set to true, the output will be captured when an action is run */ - QgsAction( ActionType type, const QString& description, const QString& action, bool capture ) + QgsAction( ActionType type, const QString& description, const QString& command, bool capture = false ) : mType( type ) , mDescription( description ) - , mCommand( action ) + , mCommand( command ) , mCaptureOutput( capture ) + , mId( QUuid::createUuid() ) {} /** @@ -82,6 +84,7 @@ class CORE_EXPORT QgsAction , mCommand( action ) , mCaptureOutput( capture ) , mActionScopes( actionScopes ) + , mId( QUuid::createUuid() ) {} //! The name of the action. This may be a longer description. @@ -95,14 +98,14 @@ class CORE_EXPORT QgsAction * * @note Added in QGIS 3.0 */ - QString id() const { return mShortTitle; } + QUuid id() const { return mId; } /** * Returns true if this action was a default constructed one. * * @note Added in QGIS 3.0 */ - bool isValid() const { return !mShortTitle.isNull(); } + bool isValid() const { return !mId.isNull(); } //! The path to the icon QString iconPath() const { return mIcon; } @@ -161,6 +164,22 @@ class CORE_EXPORT QgsAction */ void setActionScopes( const QSet& actionScopes ); + /** + * Reads an XML definition from actionNode + * into this object. + * + * @note Added in QGIS 3.0 + */ + void readXml( const QDomNode& actionNode ); + + /** + * Appends an XML definition for this action as a new + * child node to actionsNode. + * + * @note Added in QGIS 3.0 + */ + void writeXml( QDomNode& actionsNode ) const; + private: ActionType mType; QString mDescription; @@ -170,6 +189,7 @@ class CORE_EXPORT QgsAction bool mCaptureOutput; QSet mActionScopes; mutable QSharedPointer mAction; + QUuid mId; }; Q_DECLARE_METATYPE( QgsAction ) diff --git a/src/core/qgsactionmanager.cpp b/src/core/qgsactionmanager.cpp index ae0ffee2782f..8363e085abe2 100644 --- a/src/core/qgsactionmanager.cpp +++ b/src/core/qgsactionmanager.cpp @@ -40,24 +40,26 @@ #include -void QgsActionManager::addAction( QgsAction::ActionType type, const QString& name, const QString& action, bool capture ) +QUuid QgsActionManager::addAction( QgsAction::ActionType type, const QString& name, const QString& command, bool capture ) { - addAction( QgsAction( type, name, action, capture ) ); + QgsAction action( type, name, command, capture ); + addAction( action ); + return action.id(); } -void QgsActionManager::addAction( QgsAction::ActionType type, const QString& name, const QString& action, const QString& icon, bool capture ) +QUuid QgsActionManager::addAction( QgsAction::ActionType type, const QString& name, const QString& command, const QString& icon, bool capture ) { - addAction( QgsAction( type, name, action, icon, capture ) ); + QgsAction action( type, name, command, icon, capture ); + addAction( action ); + return action.id(); } void QgsActionManager::addAction( const QgsAction& action ) { - static int actionId = 0; - - mActions.insert( ++actionId, action ); + mActions.append( action ); } -void QgsActionManager::doAction( const QString& actionId, const QgsFeature& feature, int defaultValueIndex ) +void QgsActionManager::doAction( const QUuid& actionId, const QgsFeature& feature, int defaultValueIndex ) { QgsExpressionContext context = createExpressionContext(); QgsExpressionContextScope* actionScope = new QgsExpressionContextScope(); @@ -69,7 +71,7 @@ void QgsActionManager::doAction( const QString& actionId, const QgsFeature& feat doAction( actionId, feature, context ); } -void QgsActionManager::doAction( const QString& actionId, const QgsFeature& feat, const QgsExpressionContext& context ) +void QgsActionManager::doAction( const QUuid& actionId, const QgsFeature& feat, const QgsExpressionContext& context ) { QgsAction act = action( actionId ); @@ -147,12 +149,12 @@ QgsExpressionContext QgsActionManager::createExpressionContext() const return context; } -bool QgsActionManager::writeXml( QDomNode& layer_node, QDomDocument& doc ) const +bool QgsActionManager::writeXml( QDomNode& layer_node ) const { - QDomElement aActions = doc.createElement( QStringLiteral( "attributeactions" ) ); - for ( QVariantMap::const_iterator defaultAction = mDefaultActions.constBegin(); defaultAction != mDefaultActions.constEnd(); ++ defaultAction ) + QDomElement aActions = layer_node.ownerDocument().createElement( QStringLiteral( "attributeactions" ) ); + for ( QMap::const_iterator defaultAction = mDefaultActions.constBegin(); defaultAction != mDefaultActions.constEnd(); ++ defaultAction ) { - QDomElement defaultActionElement = doc.createElement( QStringLiteral( "defaultAction" ) ); + QDomElement defaultActionElement = layer_node.ownerDocument().createElement( QStringLiteral( "defaultAction" ) ); defaultActionElement.setAttribute( QStringLiteral( "key" ), defaultAction.key() ); defaultActionElement.setAttribute( QStringLiteral( "value" ), defaultAction.value().toString() ); aActions.appendChild( defaultActionElement ); @@ -160,21 +162,7 @@ bool QgsActionManager::writeXml( QDomNode& layer_node, QDomDocument& doc ) const Q_FOREACH ( const QgsAction& action, mActions ) { - QDomElement actionSetting = doc.createElement( QStringLiteral( "actionsetting" ) ); - actionSetting.setAttribute( QStringLiteral( "type" ), action.type() ); - actionSetting.setAttribute( QStringLiteral( "name" ), action.name() ); - actionSetting.setAttribute( QStringLiteral( "shortTitle" ), action.shortTitle() ); - actionSetting.setAttribute( QStringLiteral( "icon" ), action.iconPath() ); - actionSetting.setAttribute( QStringLiteral( "action" ), action.command() ); - actionSetting.setAttribute( QStringLiteral( "capture" ), action.capture() ); - - Q_FOREACH ( const QString& scope, action.actionScopes() ) - { - QDomElement actionScopeElem = doc.createElement( "actionScope" ); - actionScopeElem.setAttribute( "id", scope ); - actionSetting.appendChild( actionScopeElem ); - } - aActions.appendChild( actionSetting ); + action.writeXml( aActions ); } layer_node.appendChild( aActions ); @@ -192,38 +180,9 @@ bool QgsActionManager::readXml( const QDomNode& layer_node ) QDomNodeList actionsettings = aaNode.toElement().elementsByTagName( QStringLiteral( "actionsetting" ) ); for ( int i = 0; i < actionsettings.size(); ++i ) { - QDomElement setting = actionsettings.item( i ).toElement(); - - QDomNodeList actionScopeNodes = setting.elementsByTagName( "actionScope" ); - QSet actionScopes; - - if ( actionScopeNodes.isEmpty() ) - { - actionScopes - << QStringLiteral( "Canvas" ) - << QStringLiteral( "FieldSpecific" ) - << QStringLiteral( "AttributeTableRow" ) - << QStringLiteral( "FeatureForm" ); - } - else - { - for ( int j = 0; j < actionScopeNodes.length(); ++j ) - { - QDomElement actionScopeElem = actionScopeNodes.item( j ).toElement(); - actionScopes << actionScopeElem.attribute( "id" ); - } - } - - mActions.append( - QgsAction( static_cast< QgsAction::ActionType >( setting.attributeNode( QStringLiteral( "type" ) ).value().toInt() ), - setting.attributeNode( QStringLiteral( "name" ) ).value(), - setting.attributeNode( QStringLiteral( "action" ) ).value(), - setting.attributeNode( QStringLiteral( "icon" ) ).value(), - setting.attributeNode( QStringLiteral( "capture" ) ).value().toInt() != 0, - setting.attributeNode( QStringLiteral( "shortTitle" ) ).value(), - actionScopes - ) - ); + QgsAction action; + action.readXml( actionsettings.item( i ) ); + mActions.append( action ); } QDomNodeList defaultActionNodes = aaNode.toElement().elementsByTagName( "defaultAction" ); @@ -237,7 +196,7 @@ bool QgsActionManager::readXml( const QDomNode& layer_node ) return true; } -QgsAction QgsActionManager::action( const QString& id ) +QgsAction QgsActionManager::action( const QUuid& id ) { Q_FOREACH ( const QgsAction& action, mActions ) { @@ -248,12 +207,12 @@ QgsAction QgsActionManager::action( const QString& id ) return QgsAction(); } -void QgsActionManager::setDefaultAction( const QString& actionScope, const QString& actionId ) +void QgsActionManager::setDefaultAction( const QString& actionScope, const QUuid& actionId ) { mDefaultActions[ actionScope ] = actionId; } QgsAction QgsActionManager::defaultAction( const QString& actionScope ) { - return action( mDefaultActions.value( actionScope ).toString() ); + return action( mDefaultActions.value( actionScope ) ); } diff --git a/src/core/qgsactionmanager.h b/src/core/qgsactionmanager.h index 96f6e31601a6..a8bb4cb3f162 100644 --- a/src/core/qgsactionmanager.h +++ b/src/core/qgsactionmanager.h @@ -59,7 +59,7 @@ class CORE_EXPORT QgsActionManager * any stdout from the process will be captured and displayed in a * dialog box. */ - void addAction( QgsAction::ActionType type, const QString& name, const QString& action, bool capture = false ); + QUuid addAction( QgsAction::ActionType type, const QString& name, const QString& command, bool capture = false ); /** Add an action with the given name and action details. * Will happily have duplicate names and actions. If @@ -67,7 +67,7 @@ class CORE_EXPORT QgsActionManager * any stdout from the process will be captured and displayed in a * dialog box. */ - void addAction( QgsAction::ActionType type, const QString& name, const QString& action, const QString& icon, bool capture = false ); + QUuid addAction( QgsAction::ActionType type, const QString& name, const QString& command, const QString& icon, bool capture = false ); /** * Add a new action to this list. @@ -78,9 +78,7 @@ class CORE_EXPORT QgsActionManager * field to be used if the action has a $currfield placeholder. * @note available in python bindings as doActionFeature */ - void doAction( const QString& actionId, - const QgsFeature &feature, - int defaultValueIndex = 0 ); + void doAction( const QUuid& actionId, const QgsFeature &feature, int defaultValueIndex = 0 ); /** Does the action using the expression engine to replace any embedded expressions * in the action definition. @@ -88,9 +86,7 @@ class CORE_EXPORT QgsActionManager * @param feature feature to run action for * @param context expression context to evalute expressions under */ - void doAction( const QString& actionId, - const QgsFeature& feature, - const QgsExpressionContext& context ); + void doAction( const QUuid& actionId, const QgsFeature& feature, const QgsExpressionContext& context ); //! Removes all actions void clearActions(); @@ -105,7 +101,7 @@ class CORE_EXPORT QgsActionManager QgsVectorLayer* layer() const { return mLayer; } //! Writes the actions out in XML format - bool writeXml( QDomNode& layer_node, QDomDocument& doc ) const; + bool writeXml( QDomNode& layer_node ) const; //! Reads the actions in in XML format bool readXml( const QDomNode& layer_node ); @@ -115,7 +111,7 @@ class CORE_EXPORT QgsActionManager * * @note Added in QGIS 3.0 */ - QgsAction action( const QString& id ); + QgsAction action( const QUuid& id ); /** * Each scope can have a default action. This will be saved in the project @@ -123,7 +119,7 @@ class CORE_EXPORT QgsActionManager * * @note Added in QGIS 3.0 */ - void setDefaultAction( const QString& actionScope, const QString& actionId ); + void setDefaultAction( const QString& actionScope, const QUuid& actionId ); /** * Each scope can have a default action. This will be saved in the project @@ -140,7 +136,7 @@ class CORE_EXPORT QgsActionManager void runAction( const QgsAction &action ); - QVariantMap mDefaultActions; + QMap mDefaultActions; QgsExpressionContext createExpressionContext() const; }; diff --git a/src/core/qgsapplication.h b/src/core/qgsapplication.h index 994376025e72..152f1b42d120 100644 --- a/src/core/qgsapplication.h +++ b/src/core/qgsapplication.h @@ -377,7 +377,7 @@ class CORE_EXPORT QgsApplication : public QApplication /** * Returns the action scope registry. * - * @Note Added in QGIS 3.0 + * @note Added in QGIS 3.0 */ static QgsActionScopeRegistry* actionScopeRegistry(); diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 80d9cf91b5c7..2bdb2d76f5d7 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -2005,7 +2005,7 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& node.appendChild( excludeWFSElem ); // add attribute actions - mActions->writeXml( node, doc ); + mActions->writeXml( node ); mAttributeTableConfig.writeXml( node ); mEditFormConfig.writeXml( node ); mConditionalStyles->writeXml( node, doc ); diff --git a/src/gui/attributetable/qgsattributetablemodel.cpp b/src/gui/attributetable/qgsattributetablemodel.cpp index 2a75d2897f80..5d13259cd9b9 100644 --- a/src/gui/attributetable/qgsattributetablemodel.cpp +++ b/src/gui/attributetable/qgsattributetablemodel.cpp @@ -737,7 +737,7 @@ void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelInde } -void QgsAttributeTableModel::executeAction( const QString& action, const QModelIndex &idx ) const +void QgsAttributeTableModel::executeAction( const QUuid& action, const QModelIndex &idx ) const { QgsFeature f = feature( idx ); layer()->actions()->doAction( action, f, fieldIdx( idx.column() ) ); diff --git a/src/gui/attributetable/qgsattributetablemodel.h b/src/gui/attributetable/qgsattributetablemodel.h index 1e465199f8ee..8fd267616cf7 100644 --- a/src/gui/attributetable/qgsattributetablemodel.h +++ b/src/gui/attributetable/qgsattributetablemodel.h @@ -171,7 +171,7 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel /** * Execute an action */ - void executeAction( const QString& action, const QModelIndex &idx ) const; + void executeAction( const QUuid& action, const QModelIndex &idx ) const; /** * Execute a QgsMapLayerAction diff --git a/src/gui/attributetable/qgsdualview.h b/src/gui/attributetable/qgsdualview.h index e00fcf63077e..abb7524fdf23 100644 --- a/src/gui/attributetable/qgsdualview.h +++ b/src/gui/attributetable/qgsdualview.h @@ -353,7 +353,12 @@ class GUI_EXPORT QgsAttributeTableAction : public QAction Q_OBJECT public: - QgsAttributeTableAction( const QString &name, QgsDualView *dualView, const QString& action, const QModelIndex &fieldIdx ) + /** + * Create a new attribute table action. + * + * @note Added in QGIS 3.0 + */ + QgsAttributeTableAction( const QString& name, QgsDualView* dualView, const QUuid& action, const QModelIndex& fieldIdx ) : QAction( name, dualView ) , mDualView( dualView ) , mAction( action ) @@ -366,7 +371,7 @@ class GUI_EXPORT QgsAttributeTableAction : public QAction private: QgsDualView* mDualView; - QString mAction; + QUuid mAction; QModelIndex mFieldIdx; }; diff --git a/tests/src/python/test_qgsactionmanager.py b/tests/src/python/test_qgsactionmanager.py index d6d29b3289ce..94cd19c36fe2 100644 --- a/tests/src/python/test_qgsactionmanager.py +++ b/tests/src/python/test_qgsactionmanager.py @@ -45,7 +45,7 @@ def __init__(self, methodName): self.manager = QgsActionManager(self.layer) # make a little script to aid in recording action outputs - # this is just a little python file which writes out it's arguments to a text file + # this is just a little python file which writes out its arguments to a text file self.run_script_file = os.path.join(QDir.tempPath(), 'run_action.py') with open(self.run_script_file, 'w') as s: s.write('import sys\n') @@ -70,36 +70,29 @@ def testAddAction(self): """ Test adding actions """ # should be empty to start with - self.assertEqual(self.manager.size(), 0) self.assertEqual(self.manager.listActions(), []) # add an action - self.manager.addAction(QgsAction.GenericPython, 'test_action', 'i=1') - self.assertEqual(self.manager.size(), 1) + action1 = QgsAction(QgsAction.GenericPython, 'Test Action', 'i=1') + self.manager.addAction(action1) + self.assertEqual(len(self.manager.listActions()), 1) self.assertEqual(self.manager.listActions()[0].type(), QgsAction.GenericPython) - self.assertEqual(self.manager.listActions()[0].name(), 'test_action') - self.assertEqual(self.manager.listActions()[0].action(), 'i=1') - self.assertEqual(self.manager.at(0).name(), 'test_action') - self.assertEqual(self.manager[0].name(), 'test_action') + self.assertEqual(self.manager.listActions()[0].name(), 'Test Action') + self.assertEqual(self.manager.listActions()[0].command(), 'i=1') # add another action - self.manager.addAction(QgsAction.Windows, 'test_action2', 'i=2') - self.assertEqual(self.manager.size(), 2) - self.assertEqual(self.manager.listActions()[1].type(), QgsAction.Windows) - self.assertEqual(self.manager.listActions()[1].name(), 'test_action2') - self.assertEqual(self.manager.listActions()[1].action(), 'i=2') - self.assertEqual(self.manager.at(1).name(), 'test_action2') - self.assertEqual(self.manager[1].name(), 'test_action2') - - # add a predefined action - action = QgsAction(QgsAction.Unix, 'test_action3', 'i=3', False) - self.manager.addAction(action) - self.assertEqual(self.manager.size(), 3) - self.assertEqual(self.manager.listActions()[2].type(), QgsAction.Unix) - self.assertEqual(self.manager.listActions()[2].name(), 'test_action3') - self.assertEqual(self.manager.listActions()[2].action(), 'i=3') - self.assertEqual(self.manager.at(2).name(), 'test_action3') - self.assertEqual(self.manager[2].name(), 'test_action3') + action2 = QgsAction(QgsAction.Windows, 'Test Action2', 'i=2') + self.manager.addAction(action2) + self.assertEqual(len(self.manager.listActions()), 2) + self.assertEqual(self.manager.action(action2.id()).type(), QgsAction.Windows) + self.assertEqual(self.manager.action(action2.id()).name(), 'Test Action2') + self.assertEqual(self.manager.action(action2.id()).command(), 'i=2') + + id3 = self.manager.addAction(QgsAction.Generic, 'Test Action3', 'i=3') + self.assertEqual(len(self.manager.listActions()), 3) + self.assertEqual(self.manager.action(id3).type(), QgsAction.Generic) + self.assertEqual(self.manager.action(id3).name(), 'Test Action3') + self.assertEqual(self.manager.action(id3).command(), 'i=3') def testRemoveActions(self): """ test removing actions """ @@ -113,9 +106,9 @@ def testRemoveActions(self): self.assertEqual(self.manager.listActions(), []) # add some actions - self.manager.addAction(QgsAction.GenericPython, 'test_action', 'i=1') - self.manager.addAction(QgsAction.GenericPython, 'test_action2', 'i=2') - self.manager.addAction(QgsAction.GenericPython, 'test_action3', 'i=3') + id1 = self.manager.addAction(QgsAction.GenericPython, 'test_action', 'i=1') + id2 = self.manager.addAction(QgsAction.GenericPython, 'test_action2', 'i=2') + id3 = self.manager.addAction(QgsAction.GenericPython, 'test_action3', 'i=3') # remove non-existant action self.manager.removeAction(5)