QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
23 #include <QTimer>
24 
26  : QObject( parent )
27 {
28 
29 }
30 
32 {
34  return false;
35 
36  QString connString = QgsTransaction::connectionString( layer->source() );
37  if ( mConnString.isEmpty() )
38  {
39  mConnString = connString;
40  mProviderKey = layer->providerType();
41  }
42  else if ( mConnString != connString || mProviderKey != layer->providerType() )
43  {
44  return false;
45  }
46 
47  mLayers.insert( layer );
48 
49  connect( layer, &QgsVectorLayer::beforeEditingStarted, this, &QgsTransactionGroup::onEditingStarted );
50  connect( layer, &QgsVectorLayer::destroyed, this, &QgsTransactionGroup::onLayerDeleted );
51 
52  return true;
53 }
54 
55 QSet<QgsVectorLayer *> QgsTransactionGroup::layers() const
56 {
57  return mLayers;
58 }
59 
61 {
62  const auto constMLayers = mLayers;
63  for ( QgsVectorLayer *layer : constMLayers )
64  {
65  if ( layer->isModified() )
66  return true;
67  }
68  return false;
69 }
70 
71 void QgsTransactionGroup::onEditingStarted()
72 {
73  if ( mTransaction )
74  return;
75 
76  mTransaction.reset( QgsTransaction::create( mConnString, mProviderKey ) );
77  if ( !mTransaction )
78  return;
79 
80  QString errorMsg;
81  mTransaction->begin( errorMsg );
82 
83  const auto constMLayers = mLayers;
84  for ( QgsVectorLayer *layer : constMLayers )
85  {
86  mTransaction->addLayer( layer );
87  layer->startEditing();
88  connect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onCommitChanges );
89  connect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback );
90  }
91 }
92 
93 void QgsTransactionGroup::onLayerDeleted()
94 {
95  mLayers.remove( static_cast<QgsVectorLayer *>( sender() ) );
96 }
97 
98 void QgsTransactionGroup::onCommitChanges()
99 {
100  if ( mEditingStopping )
101  return;
102 
103  mEditingStopping = true;
104 
105  QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() );
106 
107  QString errMsg;
108  if ( mTransaction->commit( errMsg ) )
109  {
110  const auto constMLayers = mLayers;
111  for ( QgsVectorLayer *layer : constMLayers )
112  {
113  if ( layer != sender() )
114  layer->commitChanges();
115  }
116 
117  disableTransaction();
118  }
119  else
120  {
121  emit commitError( errMsg );
122  // Restart editing the calling layer in the next event loop cycle
123  QTimer::singleShot( 0, triggeringLayer, &QgsVectorLayer::startEditing );
124  }
125  mEditingStopping = false;
126 }
127 
128 void QgsTransactionGroup::onRollback()
129 {
130  if ( mEditingStopping )
131  return;
132 
133  mEditingStopping = true;
134 
135  QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() );
136 
137  QString errMsg;
138  if ( mTransaction->rollback( errMsg ) )
139  {
140  const auto constMLayers = mLayers;
141  for ( QgsVectorLayer *layer : constMLayers )
142  {
143  if ( layer != triggeringLayer )
144  layer->rollBack();
145  }
146  disableTransaction();
147  }
148  else
149  {
150  // Restart editing the calling layer in the next event loop cycle
151  QTimer::singleShot( 0, triggeringLayer, &QgsVectorLayer::startEditing );
152  }
153  mEditingStopping = false;
154 }
155 
156 void QgsTransactionGroup::disableTransaction()
157 {
158  mTransaction.reset();
159 
160  const auto constMLayers = mLayers;
161  for ( QgsVectorLayer *layer : constMLayers )
162  {
163  disconnect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onCommitChanges );
164  disconnect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback );
165  }
166 }
167 
169 {
170  return mProviderKey;
171 }
172 
174 {
175  return mLayers.isEmpty();
176 }
177 
179 {
180  return mConnString;
181 }
static QgsTransaction * create(const QString &connString, const QString &providerKey)
Create a transaction for the specified connection string connString and provider with providerKey...
void beforeRollBack()
Emitted before changes are rolled back.
QString providerType() const
Returns the provider type (provider key) for this layer.
bool startEditing()
Makes the layer editable.
QSet< QgsVectorLayer * > layers() const
Gets the set of layers currently managed by this transaction group.
void beforeCommitChanges()
Emitted before changes are committed to the data provider.
QString providerKey() const
Returns the provider key used by this transaction group.
void beforeEditingStarted()
Emitted before editing on this layer is started.
bool addLayer(QgsVectorLayer *layer)
Add a layer to this transaction group.
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if the provider of a given layer supports transactions.
QgsTransactionGroup(QObject *parent=nullptr)
Constructor for QgsTransactionGroup.
QString source() const
Returns the source for the layer.
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.
Represents a vector layer which manages a vector based data sets.
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.