QGIS API Documentation  2.14.0-Essen
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  , mEditingStarting( false )
28  , mEditingStopping( false )
29 {
30 
31 }
32 
34 {
35 }
36 
38 {
40  return false;
41 
42  QString connString = QgsDataSourceURI( layer->source() ).connectionInfo();
43 
44  if ( mConnString.isEmpty() )
45  {
46  mConnString = connString;
47  mProviderKey = layer->providerType();
48  }
49  else if ( mConnString != connString || mProviderKey != layer->providerType() )
50  {
51  return false;
52  }
53 
54  mLayers.insert( layer );
55 
56  connect( layer, SIGNAL( beforeEditingStarted() ), this, SLOT( onEditingStarted() ) );
57  connect( layer, SIGNAL( layerDeleted() ), this, SLOT( onLayerDeleted() ) );
58 
59  return true;
60 }
61 
63 {
64  return mLayers;
65 }
66 
68 {
69  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
70  {
71  if ( layer->isModified() )
72  return true;
73  }
74  return false;
75 }
76 
77 void QgsTransactionGroup::onEditingStarted()
78 {
79  if ( !mTransaction.isNull() )
80  return;
81 
82  mTransaction.reset( QgsTransaction::create( mConnString, mProviderKey ) );
83 
84  QString errorMsg;
85  mTransaction->begin( errorMsg );
86 
87  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
88  {
89  mTransaction->addLayer( layer );
90  layer->startEditing();
91  connect( layer, SIGNAL( beforeCommitChanges() ), this, SLOT( onCommitChanges() ) );
92  connect( layer, SIGNAL( beforeRollBack() ), this, SLOT( onRollback() ) );
93  }
94 }
95 
96 void QgsTransactionGroup::onLayerDeleted()
97 {
98  mLayers.remove( qobject_cast<QgsVectorLayer*>( sender() ) );
99 }
100 
101 void QgsTransactionGroup::onCommitChanges()
102 {
103  if ( mEditingStopping )
104  return;
105 
106  mEditingStopping = true;
107 
108  QgsVectorLayer* triggeringLayer = qobject_cast<QgsVectorLayer*>( sender() );
109 
110  QString errMsg;
111  if ( mTransaction->commit( errMsg ) )
112  {
113  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
114  {
115  if ( layer != sender() )
116  layer->commitChanges();
117  }
118 
119  disableTransaction();
120  }
121  else
122  {
123  emit commitError( errMsg );
124  // Restart editing the calling layer in the next event loop cycle
125  QTimer::singleShot( 0, triggeringLayer, SLOT( startEditing() ) );
126  }
127  mEditingStopping = false;
128 }
129 
130 void QgsTransactionGroup::onRollback()
131 {
132  if ( mEditingStopping )
133  return;
134 
135  mEditingStopping = true;
136 
137  QgsVectorLayer* triggeringLayer = qobject_cast<QgsVectorLayer*>( sender() );
138 
139  QString errMsg;
140  if ( mTransaction->rollback( errMsg ) )
141  {
142  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
143  {
144  if ( layer != triggeringLayer )
145  layer->rollBack();
146  }
147  disableTransaction();
148  }
149  else
150  {
151  // Restart editing the calling layer in the next event loop cycle
152  QTimer::singleShot( 0, triggeringLayer, SLOT( startEditing() ) );
153  }
154  mEditingStopping = false;
155 }
156 
157 void QgsTransactionGroup::disableTransaction()
158 {
159  mTransaction.reset();
160 
161  Q_FOREACH ( QgsVectorLayer* layer, mLayers )
162  {
163  disconnect( layer, SIGNAL( beforeCommitChanges() ), this, SLOT( onCommitChanges() ) );
164  disconnect( layer, SIGNAL( beforeRollBack() ), this, SLOT( onRollback() ) );
165  }
166 }
167 
169 {
170  return mProviderKey;
171 }
172 
174 {
175  return mLayers.isEmpty();
176 }
177 
179 {
180  return mConnString;
181 }
QSet< QgsVectorLayer * > layers() const
Get the set of layers currently managed by this transaction group.
static QgsTransaction * create(const QString &connString, const QString &providerKey)
Creates a transaction for the specified connection string and provider.
QObject * sender() const
bool commitChanges()
Attempts to commit any changes to disk.
bool startEditing()
Make layer editable.
QString source() const
Returns the source for the layer.
QString connString() const
Return the connection string used by this transaction group.
const_iterator insert(const T &value)
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void reset(T *other)
bool isEmpty() const
Returns true if there are no layers in this transaction group.
bool rollBack(bool deleteBuffer=true)
Stop editing and discard the edits.
bool isEmpty() const
bool addLayer(QgsVectorLayer *layer)
Add a layer to this transaction group.
QString providerKey() const
Return the provider key used by this transaction group.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if a the provider of a give layer supports transactions.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
bool isNull() const
QString providerType() const
Return the provider type for this layer.
QgsTransactionGroup(QObject *parent=0)
bool remove(const T &value)
bool modified() const
Returns true if any of the layers in this group reports a modification.
bool isEmpty() const
void commitError(const QString &msg)
Will be emitted whenever there is a commit error.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Represents a vector layer which manages a vector based data sets.