Skip to content

Commit

Permalink
Add transaction groups
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Jan 15, 2016
1 parent 53527ca commit 9b51007
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 20 deletions.
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -19,6 +19,7 @@
%Include qgis.sip

%Include qgstransaction.sip
%Include qgstransactiongroup.sip
%Include qgsapplication.sip
%Include qgsattributeaction.sip
%Include qgsbrowsermodel.sip
Expand Down
5 changes: 5 additions & 0 deletions python/core/qgstransaction.sip
Expand Up @@ -59,6 +59,11 @@ class QgsTransaction : QObject /Abstract/
/** Executes sql */
virtual bool executeSql( const QString& sql, QString& error /Out/ ) = 0;

/**
* Checks if a the provider of a give layer supports transactions.
*/
static bool supportsTransaction( const QgsVectorLayer* layer );

signals:
/**
* Emitted after a rollback
Expand Down
56 changes: 56 additions & 0 deletions python/core/qgstransactiongroup.sip
@@ -0,0 +1,56 @@
/***************************************************************************
qgstransactiongroup.h - QgsTransactionGroup

---------------------
begin : 15.1.2016
copyright : (C) 2016 by Matthias Kuhn
email : mmatthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

class QgsTransactionGroup : QObject
{
%TypeHeaderCode
#include "qgstransactiongroup.h"
%End
public:
explicit QgsTransactionGroup( QObject *parent = 0 );

~QgsTransactionGroup();

/**
* Add a layer to this transaction group.
*
* Will return true if it is compatible and has been added.
*/
bool addLayer( QgsVectorLayer* layer );

/**
* Return the connection string used by this transaction group.
* Layers need be compatible when added.
*/
QString connString() const;

/**
* Return the provider key used by this transaction group.
* Layers need be compatible when added.
*/
QString providerKey() const;

/**
* Returns true if there are no layers in this transaction group.
*/
bool isEmpty() const;

signals:
/**
* Will be emitted whenever there is a commit error
*/
void commitError( const QString& msg );
};
24 changes: 12 additions & 12 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -1015,14 +1015,6 @@ class QgsVectorLayer : QgsMapLayer
*/
bool setReadOnly( bool readonly = true );

/**
* Make layer editable.
* This starts an edit session on this layer. Changes made in this edit session will not
* be made persistent until {@link commitChanges()} is called and can be reverted by calling
* {@link rollBack()}.
*/
bool startEditing();

/** Change feature's geometry */
bool changeGeometry( QgsFeatureId fid, QgsGeometry* geom );

Expand Down Expand Up @@ -1493,6 +1485,15 @@ class QgsVectorLayer : QgsMapLayer
/** Check if there is a join with a layer that will be removed */
void checkJoinLayerRemove( const QString& theLayerId );

/**
* Make layer editable.
* This starts an edit session on this layer. Changes made in this edit session will not
* be made persistent until {@link commitChanges()} is called and can be reverted by calling
* {@link rollBack()}.
*/
bool startEditing();


protected slots:
void invalidateSymbolCountedFlag();

Expand All @@ -1516,6 +1517,9 @@ class QgsVectorLayer : QgsMapLayer
/** Is emitted, when layer is checked for modifications. Use for last-minute additions */
void beforeModifiedCheck() const;

/** Is emitted, before editing on this layer is started */
void beforeEditingStarted();

/** Is emitted, when editing on this layer has started*/
void editingStarted();

Expand Down Expand Up @@ -1663,10 +1667,6 @@ class QgsVectorLayer : QgsMapLayer
*/
void writeCustomSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage ) const;

private slots:
void onRelationsLoaded();
void onJoinedFieldsChanged();
void onFeatureDeleted( QgsFeatureId fid );

protected:
/** Set the extent */
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -190,6 +190,7 @@ SET(QGIS_CORE_SRCS
qgstolerance.cpp
qgstracer.cpp
qgstransaction.cpp
qgstransactiongroup.cpp
qgsvectordataprovider.cpp
qgsvectorfilewriter.cpp
qgsvectorlayer.cpp
Expand Down Expand Up @@ -459,6 +460,7 @@ SET(QGIS_CORE_MOC_HDRS
qgssnappingutils.h
qgstracer.h
qgstransaction.h
qgstransactiongroup.h
qgsvectordataprovider.h
qgsvectorlayercache.h
qgsvectorlayereditbuffer.h
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgstransaction.cpp
Expand Up @@ -163,6 +163,15 @@ bool QgsTransaction::rollback( QString& errorMsg )
return true;
}

bool QgsTransaction::supportsTransaction( const QgsVectorLayer* layer )
{
QLibrary* lib = QgsProviderRegistry::instance()->providerLibrary( layer->providerType() );
if ( !lib )
return false;

return lib->resolve( "createTransaction" );
}

void QgsTransaction::onLayersDeleted( const QStringList& layerids )
{
Q_FOREACH ( const QString& layerid, layerids )
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgstransaction.h
Expand Up @@ -85,6 +85,11 @@ class CORE_EXPORT QgsTransaction : public QObject
/** Executes sql */
virtual bool executeSql( const QString& sql, QString& error ) = 0;

/**
* Checks if a the provider of a give layer supports transactions.
*/
static bool supportsTransaction( const QgsVectorLayer* layer );

signals:
/**
* Emitted after a rollback
Expand Down
154 changes: 154 additions & 0 deletions src/core/qgstransactiongroup.cpp
@@ -0,0 +1,154 @@
/***************************************************************************
qgstransactiongroup.cpp - QgsTransactionGroup
---------------------
begin : 15.1.2016
copyright : (C) 2016 by mku
email : [your-email-here]
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgstransactiongroup.h"

#include "qgstransaction.h"
#include "qgsvectorlayer.h"
#include "qgsdatasourceuri.h"
#include "qgsvectordataprovider.h"

#include <QTimer>

QgsTransactionGroup::QgsTransactionGroup( QObject *parent )
: QObject( parent )
, mEditingStarting( false )
, mEditingStopping( false )
, mTransaction( nullptr )
{

}

QgsTransactionGroup::~QgsTransactionGroup()
{
delete mTransaction;
}

bool QgsTransactionGroup::addLayer( QgsVectorLayer* layer )
{
if ( !QgsTransaction::supportsTransaction( layer ) )
return false;

QString connString = QgsDataSourceURI( layer->source() ).connectionInfo();

if ( mConnString.isEmpty() )
{
mConnString = connString;
mProviderKey = layer->providerType();
}
else if ( mConnString != connString || mProviderKey != layer->providerType() )
{
return false;
}

mLayers.insert( layer );

connect( layer, SIGNAL( beforeEditingStarted() ), this, SLOT( onEditingStarted() ) );
connect( layer, SIGNAL( layerDeleted() ), this, SLOT( onLayerDeleted() ) );

return true;
}

void QgsTransactionGroup::onEditingStarted()
{
if ( mTransaction )
return;

mTransaction = QgsTransaction::create( mConnString, mProviderKey );

QString errorMsg;
mTransaction->begin( errorMsg );

Q_FOREACH ( QgsVectorLayer* layer, mLayers )
{
mTransaction->addLayer( layer );
layer->startEditing();
connect( layer, SIGNAL( beforeCommitChanges() ), this, SLOT( onCommitChanges() ) );
connect( layer, SIGNAL( beforeRollBack() ), this, SLOT( onRollback() ) );
}
}

void QgsTransactionGroup::onLayerDeleted()
{
mLayers.remove( qobject_cast<QgsVectorLayer*>( sender() ) );
}

void QgsTransactionGroup::onCommitChanges()
{
if ( mEditingStopping )
return;

mEditingStopping = true;

QgsVectorLayer* triggeringLayer = qobject_cast<QgsVectorLayer*>( sender() );

QString errMsg;
if ( mTransaction->commit( errMsg ) )
{
Q_FOREACH ( QgsVectorLayer* layer, mLayers )
{
if ( layer != sender() )
layer->commitChanges();
}
}
else
{
emit commitError( errMsg );
// Restart editing the calling layer in the next event loop cycle
QTimer::singleShot( 0, triggeringLayer, SLOT( startEditing() ) );
}
mEditingStopping = false;
}

void QgsTransactionGroup::onRollback()
{
if ( mEditingStopping )
return;

mEditingStopping = true;

QgsVectorLayer* triggeringLayer = qobject_cast<QgsVectorLayer*>( sender() );

QString errMsg;
if ( mTransaction->rollback( errMsg ) )
{
Q_FOREACH ( QgsVectorLayer* layer, mLayers )
{
if ( layer != triggeringLayer )
layer->rollBack();
}
}
else
{
// Restart editing the calling layer in the next event loop cycle
QTimer::singleShot( 0, triggeringLayer, SLOT( startEditing() ) );
}
mEditingStopping = false;
}

QString QgsTransactionGroup::providerKey() const
{
return mProviderKey;
}

bool QgsTransactionGroup::isEmpty() const
{
return mLayers.isEmpty();
}

QString QgsTransactionGroup::connString() const
{
return mConnString;
}

0 comments on commit 9b51007

Please sign in to comment.