QGIS API Documentation 3.29.0-Master (ade4f0cf0f)
qgstransactiongroup.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgstransactiongroup.cpp - QgsTransactionGroup
3 ---------------------------------------------
4
5 begin : 15.1.2016
6 Copyright : (C) 2016 Matthias Kuhn
7 Email : matthias at opengis dot 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#include "qgstransactiongroup.h"
17
18#include "qgstransaction.h"
19#include "qgsvectorlayer.h"
20#include "qgsdatasourceuri.h"
22#include "qgslogger.h"
23
24#include <QTimer>
25
27 : QObject( parent )
28{
29
30}
31
33{
35 return false;
36
37 const QString connString = QgsTransaction::connectionString( layer->source() );
38 if ( mConnString.isEmpty() )
39 {
40 mConnString = connString;
41 mProviderKey = layer->providerType();
42 }
43 else if ( mConnString != connString || mProviderKey != layer->providerType() )
44 {
45 return false;
46 }
47
48 mLayers.insert( layer );
49
50 connect( layer, &QgsVectorLayer::beforeEditingStarted, this, &QgsTransactionGroup::onEditingStarted );
51 connect( layer, &QgsVectorLayer::destroyed, this, &QgsTransactionGroup::onLayerDeleted );
52
53 return true;
54}
55
56QSet<QgsVectorLayer *> QgsTransactionGroup::layers() const
57{
58 return mLayers;
59}
60
62{
63 const auto constMLayers = mLayers;
64 for ( QgsVectorLayer *layer : constMLayers )
65 {
66 if ( layer->isModified() )
67 return true;
68 }
69 return false;
70}
71
72void QgsTransactionGroup::onEditingStarted()
73{
74 if ( mTransaction )
75 return;
76
77 mTransaction.reset( QgsTransaction::create( mConnString, mProviderKey ) );
78 if ( !mTransaction )
79 return;
80
81 QString errorMsg;
82 mTransaction->begin( errorMsg );
83
84 const auto constMLayers = mLayers;
85 for ( QgsVectorLayer *layer : constMLayers )
86 {
87 mTransaction->addLayer( layer, true );
88 layer->startEditing();
89 connect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onBeforeCommitChanges );
90 connect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback );
91 }
92}
93
94void QgsTransactionGroup::onLayerDeleted()
95{
96 mLayers.remove( static_cast<QgsVectorLayer *>( sender() ) );
97}
98
99void QgsTransactionGroup::onBeforeCommitChanges( bool stopEditing )
100{
101 if ( mEditingStopping )
102 return;
103
104 mEditingStopping = true;
105
106 const QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() );
107
108 QString errMsg;
109 if ( mTransaction->commit( errMsg ) )
110 {
111 const auto constMLayers = mLayers;
112 for ( QgsVectorLayer *layer : constMLayers )
113 {
114 if ( layer != triggeringLayer )
115 {
116 layer->commitChanges( stopEditing );
117 }
118 }
119
120 if ( stopEditing )
121 {
122 disableTransaction();
123 }
124 else
125 {
126 if ( ! mTransaction->begin( errMsg ) )
127 {
128 QgsDebugMsg( QStringLiteral( "Could not restart a transaction for %1: %2" ).arg( triggeringLayer->name() ).arg( errMsg ) );
129 }
130 }
131
132 }
133 else
134 {
135 emit commitError( errMsg );
136 restartTransaction( triggeringLayer );
137 }
138 mEditingStopping = false;
139}
140
141void QgsTransactionGroup::onRollback()
142{
143 if ( mEditingStopping )
144 return;
145
146 mEditingStopping = true;
147
148 QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() );
149
150 QString errMsg;
151 if ( mTransaction->rollback( errMsg ) )
152 {
153 const auto constMLayers = mLayers;
154 for ( QgsVectorLayer *layer : constMLayers )
155 {
156 if ( layer != triggeringLayer )
157 layer->rollBack();
158 }
159 disableTransaction();
160 }
161 else
162 {
163 restartTransaction( triggeringLayer );
164 }
165 mEditingStopping = false;
166}
167
168void QgsTransactionGroup::disableTransaction()
169{
170 mTransaction.reset();
171
172 const auto constMLayers = mLayers;
173 for ( QgsVectorLayer *layer : constMLayers )
174 {
175 disconnect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onBeforeCommitChanges );
176 disconnect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback );
177 }
178}
179
180void QgsTransactionGroup::restartTransaction( const QgsVectorLayer *layer )
181{
182 // Restart editing the calling layer in the next event loop cycle
183 QTimer::singleShot( 0, layer, &QgsVectorLayer::startEditing );
184}
185
187{
188 return mProviderKey;
189}
190
192{
193 return mLayers.isEmpty();
194}
195
197{
198 return mConnString;
199}
QString name
Definition: qgsmaplayer.h:76
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
QString connString() const
Returns the connection string used by this transaction group.
bool modified() const
Returns true if any of the layers in this group reports a modification.
QgsTransactionGroup(QObject *parent=nullptr)
Constructor for QgsTransactionGroup.
bool isEmpty() const
Returns true if there are no layers in this transaction group.
void commitError(const QString &msg)
Will be emitted whenever there is a commit error.
QString providerKey() const
Returns the provider key used by this transaction group.
bool addLayer(QgsVectorLayer *layer)
Add a layer to this transaction group.
QSet< QgsVectorLayer * > layers() const
Gets the set of layers currently managed by this transaction group.
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if the provider of a given layer supports transactions.
QString connectionString() const
Returns the connection string of the transaction.
static QgsTransaction * create(const QString &connString, const QString &providerKey)
Create a transaction for the specified connection string connString and provider with providerKey.
Represents a vector layer which manages a vector based data sets.
void beforeCommitChanges(bool stopEditing)
Emitted before changes are committed to the data provider.
Q_INVOKABLE bool startEditing()
Makes the layer editable.
void beforeEditingStarted()
Emitted before editing on this layer is started.
void beforeRollBack()
Emitted before changes are rolled back.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38