Commit
…es possible in the future). Funded by City of Uster
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/** | ||
* This class allows to include a set of layers in a database-side transaction, | ||
* provided the layer data providers support transactions and are compatible | ||
* with each other. | ||
* | ||
* Only layers which are not in edit mode can be included in a transaction, | ||
* and all layers need to be in read-only mode for a transaction to be committed | ||
* or rolled back. | ||
* | ||
* Layers cannot only be included in one transaction at a time. | ||
* | ||
* When editing layers which are part of a transaction group, all changes are | ||
* sent directly to the data provider (bypassing the undo/redo stack), and the | ||
* changes can either be committed or rolled back on the database side via the | ||
* QgsTransaction::commit and QgsTransaction::rollback methods. | ||
* | ||
* As long as the transaction is active, the state of all layer features reflects | ||
* the current state in the transaction. | ||
* | ||
* Edits on features can get rejected if another conflicting transaction is active. | ||
*/ | ||
class QgsTransaction /Abstract/ | ||
{ | ||
%TypeHeaderCode | ||
#include <qgstransaction.h> | ||
%End | ||
public: | ||
/** Creates a transaction for the specified connection string and provider */ | ||
static QgsTransaction* create( const QString& connString, const QString& providerKey ) /Factory/; | ||
|
||
/** Creates a transaction which includes the specified layers. Connection string | ||
* and data provider are taken from the first layer */ | ||
static QgsTransaction* create( const QStringList& layerIds ) /Factory/; | ||
|
||
virtual ~QgsTransaction(); | ||
|
||
/** Add layer to the transaction. The layer must not be in edit mode. The transaction must not be active. */ | ||
bool addLayer( const QString& layerId ); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
manisandro
Author
Member
|
||
|
||
/** Begin transaction */ | ||
bool begin( QString& errorMsg ); | ||
|
||
/** Commit transaction. All layers need to be in read-only mode. */ | ||
bool commit( QString& errorMsg ); | ||
|
||
/** Roll back transaction. All layers need to be in read-only mode. */ | ||
bool rollback( QString& errorMsg ); | ||
|
||
/** Executes sql */ | ||
virtual bool executeSql( const QString& sql, QString& error ) = 0; | ||
This comment has been minimized.
Sorry, something went wrong.
m-kuhn
Member
|
||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
/*************************************************************************** | ||
qgstransaction.cpp | ||
------------------ | ||
begin : May 5, 2014 | ||
copyright : (C) 2014 by Marco Hugentobler | ||
email : marco dot hugentobler at sourcepole dot 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. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include <QLibrary> | ||
|
||
#include "qgstransaction.h" | ||
#include "qgsdatasourceuri.h" | ||
#include "qgsmaplayerregistry.h" | ||
#include "qgsproviderregistry.h" | ||
#include "qgsvectordataprovider.h" | ||
#include "qgsvectorlayer.h" | ||
|
||
typedef QgsTransaction* createTransaction_t( const QString& connString ); | ||
|
||
QgsTransaction* QgsTransaction::create( const QString& connString, const QString& providerKey ) | ||
{ | ||
|
||
QLibrary* lib = QgsProviderRegistry::instance()->providerLibrary( providerKey ); | ||
if ( !lib ) | ||
{ | ||
return 0; | ||
} | ||
|
||
createTransaction_t* createTransaction = ( createTransaction_t* ) cast_to_fptr( lib->resolve( "createTransaction" ) ); | ||
if ( !createTransaction ) | ||
{ | ||
return 0; | ||
} | ||
|
||
QgsTransaction* ts = createTransaction( connString ); | ||
|
||
delete lib; | ||
|
||
return ts; | ||
} | ||
|
||
QgsTransaction* QgsTransaction::create( const QStringList& layerIds ) | ||
{ | ||
if ( layerIds.isEmpty() ) | ||
{ | ||
return 0; | ||
} | ||
|
||
QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerIds.first() ) ); | ||
if ( !layer ) | ||
{ | ||
return 0; | ||
} | ||
|
||
QString connStr = QgsDataSourceURI( layer->source() ).connectionInfo(); | ||
QString providerKey = layer->dataProvider()->name(); | ||
QgsTransaction* ts = QgsTransaction::create( connStr, providerKey ); | ||
if ( !ts ) | ||
{ | ||
return 0; | ||
} | ||
|
||
foreach ( const QString& layerId, layerIds ) | ||
{ | ||
if ( !ts->addLayer( layerId ) ) | ||
{ | ||
delete ts; | ||
return 0; | ||
} | ||
} | ||
return ts; | ||
} | ||
|
||
|
||
QgsTransaction::QgsTransaction( const QString& connString ) | ||
: mConnString( connString ), mTransactionActive( false ) | ||
{ | ||
} | ||
|
||
QgsTransaction::~QgsTransaction() | ||
{ | ||
setLayerTransactionIds( 0 ); | ||
} | ||
|
||
bool QgsTransaction::addLayer( const QString& layerId ) | ||
{ | ||
if ( mTransactionActive ) | ||
{ | ||
return false; | ||
} | ||
|
||
QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) ); | ||
if ( !layer ) | ||
{ | ||
return false; | ||
} | ||
|
||
if ( layer->isEditable() ) | ||
{ | ||
return false; | ||
} | ||
|
||
//test if provider supports transactions | ||
if ( !layer->dataProvider() || !layer->dataProvider()->capabilities() & QgsVectorDataProvider::TransactionSupport ) | ||
{ | ||
return false; | ||
} | ||
|
||
if ( layer->dataProvider()->transaction() != 0 ) | ||
{ | ||
return false; | ||
} | ||
|
||
//connection string not compatible | ||
if ( QgsDataSourceURI( layer->source() ).connectionInfo() != mConnString ) | ||
{ | ||
return false; | ||
} | ||
|
||
mLayers.insert( layerId ); | ||
return true; | ||
} | ||
|
||
bool QgsTransaction::begin( QString& errorMsg, int statementTimeout ) | ||
{ | ||
if ( mTransactionActive ) | ||
{ | ||
return false; | ||
} | ||
|
||
//Set all layers to direct edit mode | ||
if ( !beginTransaction( errorMsg, statementTimeout ) ) | ||
{ | ||
return false; | ||
} | ||
|
||
setLayerTransactionIds( this ); | ||
mTransactionActive = true; | ||
return true; | ||
} | ||
|
||
bool QgsTransaction::commit( QString& errorMsg ) | ||
{ | ||
if ( !mTransactionActive ) | ||
{ | ||
return false; | ||
} | ||
|
||
foreach ( const QString& layerid, mLayers ) | ||
{ | ||
QgsMapLayer* l = QgsMapLayerRegistry::instance()->mapLayer( layerid ); | ||
if ( !l || l->isEditable() ) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
if ( !commitTransaction( errorMsg ) ) | ||
{ | ||
return false; | ||
} | ||
|
||
setLayerTransactionIds( 0 ); | ||
mTransactionActive = false; | ||
return true; | ||
} | ||
|
||
bool QgsTransaction::rollback( QString& errorMsg ) | ||
{ | ||
if ( !mTransactionActive ) | ||
{ | ||
return false; | ||
} | ||
|
||
foreach ( const QString& layerid, mLayers ) | ||
{ | ||
QgsMapLayer* l = QgsMapLayerRegistry::instance()->mapLayer( layerid ); | ||
if ( !l || l->isEditable() ) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
if ( !rollbackTransaction( errorMsg ) ) | ||
{ | ||
return false; | ||
} | ||
|
||
setLayerTransactionIds( 0 ); | ||
mTransactionActive = false; | ||
return true; | ||
} | ||
|
||
void QgsTransaction::setLayerTransactionIds( QgsTransaction* transaction ) | ||
{ | ||
foreach ( const QString& layerid, mLayers ) | ||
{ | ||
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerid ) ); | ||
if ( vl && vl->dataProvider() ) | ||
{ | ||
vl->dataProvider()->setTransaction( transaction ); | ||
} | ||
} | ||
} |
@manisandro do you remember why the transaction must not be active when a layer is added?