QGIS API Documentation  2.14.11-Essen
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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'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.
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...