Skip to content

Commit 9b51007

Browse files
committed
Add transaction groups
1 parent 53527ca commit 9b51007

11 files changed

+339
-20
lines changed

python/core/core.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
%Include qgis.sip
2020

2121
%Include qgstransaction.sip
22+
%Include qgstransactiongroup.sip
2223
%Include qgsapplication.sip
2324
%Include qgsattributeaction.sip
2425
%Include qgsbrowsermodel.sip

python/core/qgstransaction.sip

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ class QgsTransaction : QObject /Abstract/
5959
/** Executes sql */
6060
virtual bool executeSql( const QString& sql, QString& error /Out/ ) = 0;
6161

62+
/**
63+
* Checks if a the provider of a give layer supports transactions.
64+
*/
65+
static bool supportsTransaction( const QgsVectorLayer* layer );
66+
6267
signals:
6368
/**
6469
* Emitted after a rollback

python/core/qgstransactiongroup.sip

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/***************************************************************************
2+
qgstransactiongroup.h - QgsTransactionGroup
3+
4+
---------------------
5+
begin : 15.1.2016
6+
copyright : (C) 2016 by Matthias Kuhn
7+
email : mmatthias@opengis.ch
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+
class QgsTransactionGroup : QObject
18+
{
19+
%TypeHeaderCode
20+
#include "qgstransactiongroup.h"
21+
%End
22+
public:
23+
explicit QgsTransactionGroup( QObject *parent = 0 );
24+
25+
~QgsTransactionGroup();
26+
27+
/**
28+
* Add a layer to this transaction group.
29+
*
30+
* Will return true if it is compatible and has been added.
31+
*/
32+
bool addLayer( QgsVectorLayer* layer );
33+
34+
/**
35+
* Return the connection string used by this transaction group.
36+
* Layers need be compatible when added.
37+
*/
38+
QString connString() const;
39+
40+
/**
41+
* Return the provider key used by this transaction group.
42+
* Layers need be compatible when added.
43+
*/
44+
QString providerKey() const;
45+
46+
/**
47+
* Returns true if there are no layers in this transaction group.
48+
*/
49+
bool isEmpty() const;
50+
51+
signals:
52+
/**
53+
* Will be emitted whenever there is a commit error
54+
*/
55+
void commitError( const QString& msg );
56+
};

python/core/qgsvectorlayer.sip

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,14 +1015,6 @@ class QgsVectorLayer : QgsMapLayer
10151015
*/
10161016
bool setReadOnly( bool readonly = true );
10171017

1018-
/**
1019-
* Make layer editable.
1020-
* This starts an edit session on this layer. Changes made in this edit session will not
1021-
* be made persistent until {@link commitChanges()} is called and can be reverted by calling
1022-
* {@link rollBack()}.
1023-
*/
1024-
bool startEditing();
1025-
10261018
/** Change feature's geometry */
10271019
bool changeGeometry( QgsFeatureId fid, QgsGeometry* geom );
10281020

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

1488+
/**
1489+
* Make layer editable.
1490+
* This starts an edit session on this layer. Changes made in this edit session will not
1491+
* be made persistent until {@link commitChanges()} is called and can be reverted by calling
1492+
* {@link rollBack()}.
1493+
*/
1494+
bool startEditing();
1495+
1496+
14961497
protected slots:
14971498
void invalidateSymbolCountedFlag();
14981499

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

1520+
/** Is emitted, before editing on this layer is started */
1521+
void beforeEditingStarted();
1522+
15191523
/** Is emitted, when editing on this layer has started*/
15201524
void editingStarted();
15211525

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

1666-
private slots:
1667-
void onRelationsLoaded();
1668-
void onJoinedFieldsChanged();
1669-
void onFeatureDeleted( QgsFeatureId fid );
16701670

16711671
protected:
16721672
/** Set the extent */

src/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ SET(QGIS_CORE_SRCS
190190
qgstolerance.cpp
191191
qgstracer.cpp
192192
qgstransaction.cpp
193+
qgstransactiongroup.cpp
193194
qgsvectordataprovider.cpp
194195
qgsvectorfilewriter.cpp
195196
qgsvectorlayer.cpp
@@ -459,6 +460,7 @@ SET(QGIS_CORE_MOC_HDRS
459460
qgssnappingutils.h
460461
qgstracer.h
461462
qgstransaction.h
463+
qgstransactiongroup.h
462464
qgsvectordataprovider.h
463465
qgsvectorlayercache.h
464466
qgsvectorlayereditbuffer.h

src/core/qgstransaction.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ bool QgsTransaction::rollback( QString& errorMsg )
163163
return true;
164164
}
165165

166+
bool QgsTransaction::supportsTransaction( const QgsVectorLayer* layer )
167+
{
168+
QLibrary* lib = QgsProviderRegistry::instance()->providerLibrary( layer->providerType() );
169+
if ( !lib )
170+
return false;
171+
172+
return lib->resolve( "createTransaction" );
173+
}
174+
166175
void QgsTransaction::onLayersDeleted( const QStringList& layerids )
167176
{
168177
Q_FOREACH ( const QString& layerid, layerids )

src/core/qgstransaction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ class CORE_EXPORT QgsTransaction : public QObject
8585
/** Executes sql */
8686
virtual bool executeSql( const QString& sql, QString& error ) = 0;
8787

88+
/**
89+
* Checks if a the provider of a give layer supports transactions.
90+
*/
91+
static bool supportsTransaction( const QgsVectorLayer* layer );
92+
8893
signals:
8994
/**
9095
* Emitted after a rollback

src/core/qgstransactiongroup.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/***************************************************************************
2+
qgstransactiongroup.cpp - QgsTransactionGroup
3+
4+
---------------------
5+
begin : 15.1.2016
6+
copyright : (C) 2016 by mku
7+
email : [your-email-here]
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+
#include "qgstransactiongroup.h"
17+
18+
#include "qgstransaction.h"
19+
#include "qgsvectorlayer.h"
20+
#include "qgsdatasourceuri.h"
21+
#include "qgsvectordataprovider.h"
22+
23+
#include <QTimer>
24+
25+
QgsTransactionGroup::QgsTransactionGroup( QObject *parent )
26+
: QObject( parent )
27+
, mEditingStarting( false )
28+
, mEditingStopping( false )
29+
, mTransaction( nullptr )
30+
{
31+
32+
}
33+
34+
QgsTransactionGroup::~QgsTransactionGroup()
35+
{
36+
delete mTransaction;
37+
}
38+
39+
bool QgsTransactionGroup::addLayer( QgsVectorLayer* layer )
40+
{
41+
if ( !QgsTransaction::supportsTransaction( layer ) )
42+
return false;
43+
44+
QString connString = QgsDataSourceURI( layer->source() ).connectionInfo();
45+
46+
if ( mConnString.isEmpty() )
47+
{
48+
mConnString = connString;
49+
mProviderKey = layer->providerType();
50+
}
51+
else if ( mConnString != connString || mProviderKey != layer->providerType() )
52+
{
53+
return false;
54+
}
55+
56+
mLayers.insert( layer );
57+
58+
connect( layer, SIGNAL( beforeEditingStarted() ), this, SLOT( onEditingStarted() ) );
59+
connect( layer, SIGNAL( layerDeleted() ), this, SLOT( onLayerDeleted() ) );
60+
61+
return true;
62+
}
63+
64+
void QgsTransactionGroup::onEditingStarted()
65+
{
66+
if ( mTransaction )
67+
return;
68+
69+
mTransaction = QgsTransaction::create( mConnString, mProviderKey );
70+
71+
QString errorMsg;
72+
mTransaction->begin( errorMsg );
73+
74+
Q_FOREACH ( QgsVectorLayer* layer, mLayers )
75+
{
76+
mTransaction->addLayer( layer );
77+
layer->startEditing();
78+
connect( layer, SIGNAL( beforeCommitChanges() ), this, SLOT( onCommitChanges() ) );
79+
connect( layer, SIGNAL( beforeRollBack() ), this, SLOT( onRollback() ) );
80+
}
81+
}
82+
83+
void QgsTransactionGroup::onLayerDeleted()
84+
{
85+
mLayers.remove( qobject_cast<QgsVectorLayer*>( sender() ) );
86+
}
87+
88+
void QgsTransactionGroup::onCommitChanges()
89+
{
90+
if ( mEditingStopping )
91+
return;
92+
93+
mEditingStopping = true;
94+
95+
QgsVectorLayer* triggeringLayer = qobject_cast<QgsVectorLayer*>( sender() );
96+
97+
QString errMsg;
98+
if ( mTransaction->commit( errMsg ) )
99+
{
100+
Q_FOREACH ( QgsVectorLayer* layer, mLayers )
101+
{
102+
if ( layer != sender() )
103+
layer->commitChanges();
104+
}
105+
}
106+
else
107+
{
108+
emit commitError( errMsg );
109+
// Restart editing the calling layer in the next event loop cycle
110+
QTimer::singleShot( 0, triggeringLayer, SLOT( startEditing() ) );
111+
}
112+
mEditingStopping = false;
113+
}
114+
115+
void QgsTransactionGroup::onRollback()
116+
{
117+
if ( mEditingStopping )
118+
return;
119+
120+
mEditingStopping = true;
121+
122+
QgsVectorLayer* triggeringLayer = qobject_cast<QgsVectorLayer*>( sender() );
123+
124+
QString errMsg;
125+
if ( mTransaction->rollback( errMsg ) )
126+
{
127+
Q_FOREACH ( QgsVectorLayer* layer, mLayers )
128+
{
129+
if ( layer != triggeringLayer )
130+
layer->rollBack();
131+
}
132+
}
133+
else
134+
{
135+
// Restart editing the calling layer in the next event loop cycle
136+
QTimer::singleShot( 0, triggeringLayer, SLOT( startEditing() ) );
137+
}
138+
mEditingStopping = false;
139+
}
140+
141+
QString QgsTransactionGroup::providerKey() const
142+
{
143+
return mProviderKey;
144+
}
145+
146+
bool QgsTransactionGroup::isEmpty() const
147+
{
148+
return mLayers.isEmpty();
149+
}
150+
151+
QString QgsTransactionGroup::connString() const
152+
{
153+
return mConnString;
154+
}

0 commit comments

Comments
 (0)