QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 )
76  , mTransactionActive( false )
77 {
78 }
79 
81 {
82  setLayerTransactionIds( nullptr );
83 }
84 
85 bool QgsTransaction::addLayer( const QString& layerId )
86 {
87  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerId ) );
88  return addLayer( layer );
89 }
90 
92 {
93  if ( !layer )
94  return false;
95 
96  if ( layer->isEditable() )
97  return false;
98 
99  //test if provider supports transactions
100  if ( !layer->dataProvider() || ( layer->dataProvider()->capabilities() & QgsVectorDataProvider::TransactionSupport ) == 0 )
101  return false;
102 
103  if ( layer->dataProvider()->transaction() )
104  return false;
105 
106  //connection string not compatible
107  if ( QgsDataSourceURI( layer->source() ).connectionInfo( false ) != mConnString )
108  {
109  QgsDebugMsg( QString( "Couldn't start transaction because connection string for layer %1 : '%2' does not match '%3'" ).arg(
110  layer->id(), QgsDataSourceURI( layer->source() ).connectionInfo( false ), mConnString ) );
111  return false;
112  }
113 
114  connect( this, SIGNAL( afterRollback() ), layer->dataProvider(), SIGNAL( dataChanged() ) );
115  connect( QgsMapLayerRegistry::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ), this, SLOT( onLayersDeleted( QStringList ) ) );
116  mLayers.insert( layer );
117 
118  if ( mTransactionActive )
119  layer->dataProvider()->setTransaction( this );
120 
121  return true;
122 }
123 
124 bool QgsTransaction::begin( QString& errorMsg, int statementTimeout )
125 {
126  if ( mTransactionActive )
127  return false;
128 
129  //Set all layers to direct edit mode
130  if ( !beginTransaction( errorMsg, statementTimeout ) )
131  return false;
132 
133  setLayerTransactionIds( this );
134  mTransactionActive = true;
135  return true;
136 }
137 
139 {
140  if ( !mTransactionActive )
141  return false;
142 
143  if ( !commitTransaction( errorMsg ) )
144  return false;
145 
146  setLayerTransactionIds( nullptr );
147  mTransactionActive = false;
148  return true;
149 }
150 
152 {
153  if ( !mTransactionActive )
154  return false;
155 
156  if ( !rollbackTransaction( errorMsg ) )
157  return false;
158 
159  setLayerTransactionIds( nullptr );
160  mTransactionActive = false;
161 
162  emit afterRollback();
163 
164  return true;
165 }
166 
168 {
170  if ( !lib )
171  return false;
172 
173  return lib->resolve( "createTransaction" );
174 }
175 
176 void QgsTransaction::onLayersDeleted( const QStringList& layerids )
177 {
178  Q_FOREACH ( const QString& layerid, layerids )
179  Q_FOREACH ( QgsVectorLayer* l, mLayers )
180  if ( l->id() == layerid )
181  mLayers.remove( l );
182 }
183 
184 void QgsTransaction::setLayerTransactionIds( QgsTransaction* transaction )
185 {
186  Q_FOREACH ( QgsVectorLayer* vl, mLayers )
187  {
188  if ( vl->dataProvider() )
189  {
190  vl->dataProvider()->setTransaction( transaction );
191  }
192  }
193 }
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
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
QLibrary * providerLibrary(const QString &providerKey) const
QgsTransaction * createTransaction_t(const QString &connString)
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.
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
bool addLayer(const QString &layerId)
Add layer to the transaction.
bool isEmpty() const
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if a the provider of a give layer supports transactions.
T & first()
virtual int capabilities() const
Returns a bitmask containing the supported capabilities Note, some capabilities may change depending ...
void afterRollback()
Emitted after a rollback.
Class for storing the component parts of a PostgreSQL/RDBMS datasource URI.
virtual QgsTransaction * transaction() const
Returns the transaction this data provider is included in, if any.
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)
QString source() const
Returns the source for the layer.
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:272
QgsVectorDataProvider * dataProvider()
Returns the data provider.
QString providerType() const
Return the provider type for this layer.
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...