Skip to content
Permalink
Browse files

[FEATURE] Add undo and redo on transaction groups (#4765)

* [FEATURE] adds undo/redo for transaction groups

[needs-docs] the undo/redo now works with transcation groups. Just check
that there is no restriction in the transaction groups doc concerning
undo.

related to #14799

The undo/redo is implemented using SAVEPOINT.

The QgsTransaction interface has been enlarged to allow savepoints
creation and management. The savepoint is destroyed on
rollbackToSavepoint to have the same behavior has the sql ROLLBACK TO
SAVEPPOINT.

To avoid the creation of a savepoint for each feature modified in bulk
editing (e.g. paste, field calculator) the logic is a bit complicated: the
savepoint is created on QgsVectorLayer::editCommandStarted and the first
actual undo command (QgsVectorLayerUndoPassthroughCommand) is
responsible for the re-creation of the savepoint in case of undo-redo.
Since the behavior must be different in case edition doesn't take place
inside an edit command, a member function has been added to
QgsVectorLayer to expose the mEditCommandActive state.

Another (commented) tricky bit is the modification of the database
structure on add/delete attributes. On undo, the attribute is removed
before the rollback to savepoint, i.e. there is a useless ALTER TABLE
issued to restore the structure just before restoring it with the
ROLLBACK TO SAVEPOINT. This is necessary to make the provider
aware of the change of structure. It could be nicer/cleaner to have a way
to reload providers metadata.

The editPaste function has also been modified to use addFeatures instead of
addFeature (plural/singular), this is at the expense of an additional "cpy"
of the clipboard in memory, but it should improve perf with postgis provider.

* fixup operator aliases
  • Loading branch information
vmora authored and m-kuhn committed Sep 15, 2017
1 parent a081905 commit f63c3024204bb0c70237e13df804856b785d728f
@@ -120,6 +120,7 @@
%Include qgsvectorlayerjoininfo.sip
%Include qgsvectorlayerlabeling.sip
%Include qgsvectorlayerundocommand.sip
%Include qgsvectorlayerundopassthroughcommand.sip
%Include qgsvectorlayerutils.sip
%Include qgsvectorsimplifymethod.sip
%Include qgsvirtuallayerdefinition.sip
@@ -110,6 +110,50 @@ class QgsTransaction : QObject /Abstract/
:rtype: bool
%End

QString createSavepoint( QString &error /Out/ );
%Docstring
creates a save point
returns empty string on error
returns the last created savepoint if it's not dirty
.. versionadded:: 3.0
:rtype: str
%End

QString createSavepoint( const QString &savePointId, QString &error /Out/ );
%Docstring
creates a save point
returns empty string on error
.. versionadded:: 3.0
:rtype: str
%End

bool rollbackToSavepoint( const QString &name, QString &error /Out/ );
%Docstring
rollback to save point, the save point is maintained and is "undertied"
.. versionadded:: 3.0
:rtype: bool
%End

void dirtyLastSavePoint();
%Docstring
dirty save point such that next call to createSavepoint will create a new one
.. versionadded:: 3.0
%End

QList< QString > savePoints() const;
%Docstring
returns savepoints
.. versionadded:: 3.0
:rtype: list of str
%End

bool lastSavePointIsDirty() const;
%Docstring
returns the last created savepoint
.. versionadded:: 3.0
:rtype: bool
%End

signals:

void afterRollback();
@@ -1804,6 +1804,14 @@ Returns the current blending mode for features
:rtype: bool
%End

bool isEditCommandActive() const;
%Docstring
Test if an edit command is active

.. versionadded:: 3.0
:rtype: bool
%End

signals:

void selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &deselected, const bool clearAndSelect );
@@ -289,6 +289,7 @@ Updates an index in an attribute map to a new value (for updates of changed attr




};

/************************************************************************
@@ -221,7 +221,6 @@ class QgsVectorLayerUndoCommandRenameAttribute : QgsVectorLayerUndoCommand

};


/************************************************************************
* This file has been generated automatically from *
* *
@@ -0,0 +1,255 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsvectorlayerundopassthroughcommand.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/






class QgsVectorLayerUndoPassthroughCommand : QgsVectorLayerUndoCommand
{
%Docstring
Undo command for vector layer in transaction group mode.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommand( QgsVectorLayerEditBuffer *buffer, const QString &text );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommand
\param buffer associated edit buffer
\param text text associated with command
%End

bool hasError() const;
%Docstring
Returns error status
:rtype: bool
%End

protected:

bool rollBackToSavePoint();
%Docstring
Rollback command, release savepoint or set error status
save point must be set prior to call
error satus should be false prior to call
:rtype: bool
%End

bool setSavePoint();
%Docstring
Set the command savepoint or set error status
error satus should be false prior to call
:rtype: bool
%End

void setError();
%Docstring
Set error flag and append "failed" to text
%End

};


class QgsVectorLayerUndoPassthroughCommandAddFeatures : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for adding a feature to a vector layer in transaction group mode.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandAddFeatures( QgsVectorLayerEditBuffer *buffer /Transfer/, QgsFeatureList &features );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommandAddFeatures
\param buffer associated edit buffer
\param features features to add to layer
%End

virtual void undo();
virtual void redo();

QgsFeatureList features() const;
%Docstring
List of features (added feaures can be modified by default values from database)
:rtype: QgsFeatureList
%End

};



class QgsVectorLayerUndoPassthroughCommandDeleteFeatures : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for deleting features from a vector layer in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandDeleteFeatures( QgsVectorLayerEditBuffer *buffer /Transfer/, const QgsFeatureIds &fids );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommandDeleteFeatures
\param buffer associated edit buffer
\param fids feature IDs of features to delete from layer
%End

virtual void undo();
virtual void redo();

};


class QgsVectorLayerUndoPassthroughCommandChangeGeometry : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for changing feature geometry from a vector layer in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandChangeGeometry( QgsVectorLayerEditBuffer *buffer /Transfer/, const QgsFeatureId &fid, const QgsGeometry &geom );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommandChangeGeometry
\param buffer associated edit buffer
\param fid feature ID of feature to change
\param geom new geometru
%End

virtual void undo();
virtual void redo();

};


class QgsVectorLayerUndoPassthroughCommandChangeAttribute: QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for changing attr value from a vector layer in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandChangeAttribute( QgsVectorLayerEditBuffer *buffer /Transfer/, QgsFeatureId fid, int field, const QVariant &newValue );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommandChangeAttribute
\param buffer associated edit buffer
\param fid feature ID of feature
\param field
\param newValue
%End

virtual void undo();
virtual void redo();

};


class QgsVectorLayerUndoPassthroughCommandAddAttribute : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for adding attri to a vector layer in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandAddAttribute( QgsVectorLayerEditBuffer *buffer /Transfer/, const QgsField &field );
%Docstring
Constructor for QgsVectorLayerUndoPassthroughCommandAddAttribute
\param buffer associated edit buffer
\param field
%End

virtual void undo();
virtual void redo();

};


class QgsVectorLayerUndoPassthroughCommandDeleteAttribute : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for deleting attri of a vector layer in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandDeleteAttribute( QgsVectorLayerEditBuffer *buffer /Transfer/, int attr );
%Docstring
Constructor for QgsVectorLayerUndoCommandDeleteAttribute
\param buffer associated edit buffer
\param attr
%End

virtual void undo();
virtual void redo();

};


class QgsVectorLayerUndoPassthroughCommandRenameAttribute : QgsVectorLayerUndoPassthroughCommand
{
%Docstring
Undo command for deleting attri of a vector layer in transaction group.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsvectorlayerundopassthroughcommand.h"
%End
public:

QgsVectorLayerUndoPassthroughCommandRenameAttribute( QgsVectorLayerEditBuffer *buffer /Transfer/, int attr, const QString &newName );
%Docstring
Constructor for QgsVectorLayerUndoCommandRenameAttribute
\param buffer associated edit buffer
\param attr
\param newName
%End

virtual void undo();
virtual void redo();

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsvectorlayerundopassthroughcommand.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
@@ -7862,8 +7862,8 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )

QgsExpressionContext context = pasteVectorLayer->createExpressionContext();

QgsFeatureIds newIds;

QgsFeatureList newFeatures;
QgsFeatureList::const_iterator featureIt = features.constBegin();
while ( featureIt != features.constEnd() )
{
@@ -7907,13 +7907,18 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )

// now create new feature using pasted feature as a template. This automatically handles default
// values and field constraints
QgsFeature newFeature = QgsVectorLayerUtils::createFeature( pasteVectorLayer, geom, dstAttr, &context );
pasteVectorLayer->addFeature( newFeature );
newIds << newFeature.id();

newFeatures << QgsVectorLayerUtils::createFeature( pasteVectorLayer, geom, dstAttr, &context );
++featureIt;
}

pasteVectorLayer->addFeatures( newFeatures );
QgsFeatureIds newIds;
for ( const QgsFeature &f : qgsAsConst( newFeatures ) )
{
newIds << f.id();
}


pasteVectorLayer->selectByIds( newIds );
pasteVectorLayer->endEditCommand();
pasteVectorLayer->updateExtents();
@@ -301,6 +301,7 @@ SET(QGIS_CORE_SRCS
qgsvectorlayerrenderer.cpp
qgsvectorlayertools.cpp
qgsvectorlayerundocommand.cpp
qgsvectorlayerundopassthroughcommand.cpp
qgsvectorlayerutils.cpp
qgsvectorsimplifymethod.cpp
qgsvirtuallayerdefinition.cpp
@@ -906,6 +907,7 @@ SET(QGIS_CORE_HDRS
qgsvectorlayerlabeling.h
qgsvectorlayerrenderer.h
qgsvectorlayerundocommand.h
qgsvectorlayerundopassthroughcommand.h
qgsvectorlayerutils.h
qgsvectorsimplifymethod.h
qgsvirtuallayerdefinition.h

0 comments on commit f63c302

Please sign in to comment.
You can’t perform that action at this time.