QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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"
21 #include "qgsvectordataprovider.h"
22 #include "qgslogger.h"
23 
24 #include <QTimer>
25 
27  : QObject( parent )
28 {
29 
30 }
31 
33 {
35  return false;
36 
37  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 
56 QSet<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 
72 void 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 );
88  layer->startEditing();
89  connect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onBeforeCommitChanges );
90  connect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback );
91  }
92 }
93 
94 void QgsTransactionGroup::onLayerDeleted()
95 {
96  mLayers.remove( static_cast<QgsVectorLayer *>( sender() ) );
97 }
98 
99 void 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 
141 void 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 
168 void 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 
180 void 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 }
QgsVectorLayer::beforeRollBack
void beforeRollBack()
Emitted before changes are rolled back.
QgsVectorLayer::beforeEditingStarted
void beforeEditingStarted()
Emitted before editing on this layer is started.
QgsVectorLayer::beforeCommitChanges
void beforeCommitChanges(bool stopEditing)
Emitted before changes are committed to the data provider.
QgsTransactionGroup::isEmpty
bool isEmpty() const
Returns true if there are no layers in this transaction group.
Definition: qgstransactiongroup.cpp:191
QgsVectorLayer::startEditing
Q_INVOKABLE bool startEditing()
Makes the layer editable.
Definition: qgsvectorlayer.cpp:1428
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsTransactionGroup::providerKey
QString providerKey() const
Returns the provider key used by this transaction group.
Definition: qgstransactiongroup.cpp:186
QgsMapLayer::providerType
QString providerType() const
Returns the provider type (provider key) for this layer.
Definition: qgsmaplayer.cpp:1617
QgsTransactionGroup::QgsTransactionGroup
QgsTransactionGroup(QObject *parent=nullptr)
Constructor for QgsTransactionGroup.
Definition: qgstransactiongroup.cpp:26
qgsdatasourceuri.h
QgsTransaction::supportsTransaction
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if the provider of a given layer supports transactions.
Definition: qgstransaction.cpp:189
qgstransactiongroup.h
qgsvectordataprovider.h
QgsTransactionGroup::connString
QString connString() const
Returns the connection string used by this transaction group.
Definition: qgstransactiongroup.cpp:196
qgsvectorlayer.h
QgsTransactionGroup::modified
bool modified() const
Returns true if any of the layers in this group reports a modification.
Definition: qgstransactiongroup.cpp:61
qgstransaction.h
QgsMapLayer::source
QString source() const
Returns the source for the layer.
Definition: qgsmaplayer.cpp:192
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsTransaction::create
static QgsTransaction * create(const QString &connString, const QString &providerKey)
Create a transaction for the specified connection string connString and provider with providerKey.
Definition: qgstransaction.cpp:27
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:86
QgsTransactionGroup::commitError
void commitError(const QString &msg)
Will be emitted whenever there is a commit error.
qgslogger.h
QgsTransactionGroup::layers
QSet< QgsVectorLayer * > layers() const
Gets the set of layers currently managed by this transaction group.
Definition: qgstransactiongroup.cpp:56
QgsTransactionGroup::addLayer
bool addLayer(QgsVectorLayer *layer)
Add a layer to this transaction group.
Definition: qgstransactiongroup.cpp:32