QGIS API Documentation  2.14.0-Essen
qgstransaction.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstransaction.cpp
3  ------------------
4  begin : May 5, 2014
5  copyright : (C) 2014 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <QLibrary>
19 
20 #include "qgstransaction.h"
21 #include "qgsdatasourceuri.h"
22 #include "qgsmaplayerregistry.h"
23 #include "qgsproviderregistry.h"
24 #include "qgsvectordataprovider.h"
25 #include "qgsvectorlayer.h"
26 
27 typedef QgsTransaction* createTransaction_t( const QString& connString );
28 
29 QgsTransaction* QgsTransaction::create( const QString& connString, const QString& providerKey )
30 {
31 
33  if ( !lib )
34  return nullptr;
35 
36  createTransaction_t* createTransaction = reinterpret_cast< createTransaction_t* >( cast_to_fptr( lib->resolve( "createTransaction" ) ) );
37  if ( !createTransaction )
38  return nullptr;
39 
40  QgsTransaction* ts = createTransaction( connString );
41 
42  delete lib;
43 
44  return ts;
45 }
46 
48 {
49  if ( layerIds.isEmpty() )
50  return nullptr;
51 
52  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerIds.first() ) );
53  if ( !layer )
54  return nullptr;
55 
56  QString connStr = QgsDataSourceURI( layer->source() ).connectionInfo( false );
57  QString providerKey = layer->dataProvider()->name();
58  QgsTransaction* ts = QgsTransaction::create( connStr, providerKey );
59  if ( !ts )
60  return nullptr;
61 
62  Q_FOREACH ( const QString& layerId, layerIds )
63  {
64  if ( !ts->addLayer( layerId ) )
65  {
66  delete ts;
67  return nullptr;
68  }
69  }
70  return ts;
71 }
72 
73 
75  : mConnString( connString ), mTransactionActive( false )
76 {
77 }
78 
80 {
81  setLayerTransactionIds( nullptr );
82 }
83 
84 bool QgsTransaction::addLayer( const QString& layerId )
85 {
86  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
87  return addLayer( layer );
88 }
89 
91 {
92  if ( !layer )
93  return false;
94 
95  if ( layer->isEditable() )
96  return false;
97 
98  //test if provider supports transactions
99  if ( !layer->dataProvider() || ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::TransactionSupport ) == 0 )
100  return false;
101 
102  if ( layer->dataProvider()->transaction() )
103  return false;
104 
105  //connection string not compatible
106  if ( QgsDataSourceURI( layer->source() ).connectionInfo( false ) != mConnString )
107  {
108  QgsDebugMsg( QString( "Couldn't start transaction because connection string for layer %1 : '%2' does not match '%3'" ).arg(
109  layer->id(), QgsDataSourceURI( layer->source() ).connectionInfo( false ), mConnString ) );
110  return false;
111  }
112 
113  connect( this, SIGNAL( afterRollback() ), layer->dataProvider(), SIGNAL( dataChanged() ) );
114  connect( QgsMapLayerRegistry::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ), this, SLOT( onLayersDeleted( QStringList ) ) );
115  mLayers.insert( layer );
116 
117  if ( mTransactionActive )
118  layer->dataProvider()->setTransaction( this );
119 
120  return true;
121 }
122 
123 bool QgsTransaction::begin( QString& errorMsg, int statementTimeout )
124 {
125  if ( mTransactionActive )
126  return false;
127 
128  //Set all layers to direct edit mode
129  if ( !beginTransaction( errorMsg, statementTimeout ) )
130  return false;
131 
132  setLayerTransactionIds( this );
133  mTransactionActive = true;
134  return true;
135 }
136 
138 {
139  if ( !mTransactionActive )
140  return false;
141 
142  if ( !commitTransaction( errorMsg ) )
143  return false;
144 
145  setLayerTransactionIds( nullptr );
146  mTransactionActive = false;
147  return true;
148 }
149 
151 {
152  if ( !mTransactionActive )
153  return false;
154 
155  if ( !rollbackTransaction( errorMsg ) )
156  return false;
157 
158  setLayerTransactionIds( nullptr );
159  mTransactionActive = false;
160 
161  emit afterRollback();
162 
163  return true;
164 }
165 
167 {
169  if ( !lib )
170  return false;
171 
172  return lib->resolve( "createTransaction" );
173 }
174 
175 void QgsTransaction::onLayersDeleted( const QStringList& layerids )
176 {
177  Q_FOREACH ( const QString& layerid, layerids )
178  Q_FOREACH ( QgsVectorLayer* l, mLayers )
179  if ( l->id() == layerid )
180  mLayers.remove( l );
181 }
182 
183 void QgsTransaction::setLayerTransactionIds( QgsTransaction* transaction )
184 {
185  Q_FOREACH ( QgsVectorLayer* vl, mLayers )
186  {
187  if ( vl->dataProvider() )
188  {
189  vl->dataProvider()->setTransaction( transaction );
190  }
191  }
192 }
static QgsTransaction * create(const QString &connString, const QString &providerKey)
Creates a transaction for the specified connection string and provider.
static QgsProviderRegistry * instance(const QString &pluginPath=QString::null)
Means of accessing canonical single instance.
virtual ~QgsTransaction()
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
QgsTransaction * createTransaction_t(const QString &connString)
QString source() const
Returns the source for the layer.
const_iterator insert(const T &value)
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
bool commit(QString &errorMsg)
Commit transaction.
virtual QString name() const =0
Return a provider name.
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
bool addLayer(const QString &layerId)
Add layer to the transaction.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
bool isEmpty() const
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if a the provider of a give layer supports transactions.
T & first()
void afterRollback()
Emitted after a rollback.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
QLibrary * providerLibrary(const QString &providerKey) const
QString providerType() const
Return the provider type for this layer.
QgsTransaction(const QString &connString)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
bool remove(const T &value)
void * resolve(const char *symbol)
This class allows including a set of layers in a database-side transaction, provided the layer data p...
bool rollback(QString &errorMsg)
Roll back transaction.
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:258
QgsVectorDataProvider * dataProvider()
Returns the data provider.
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.
bool begin(QString &errorMsg, int statementTimeout=20)
Begin transaction The statement timeout, in seconds, specifies how long an sql statement is allowed t...