Branch data Line data Source code
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 : : #include "qgslogger.h" 23 : : 24 : : #include <QTimer> 25 : : 26 : 0 : QgsTransactionGroup::QgsTransactionGroup( QObject *parent ) 27 : 0 : : QObject( parent ) 28 : 0 : { 29 : : 30 : 0 : } 31 : : 32 : 0 : bool QgsTransactionGroup::addLayer( QgsVectorLayer *layer ) 33 : : { 34 : 0 : if ( !QgsTransaction::supportsTransaction( layer ) ) 35 : 0 : return false; 36 : : 37 : 0 : QString connString = QgsTransaction::connectionString( layer->source() ); 38 : 0 : if ( mConnString.isEmpty() ) 39 : : { 40 : 0 : mConnString = connString; 41 : 0 : mProviderKey = layer->providerType(); 42 : 0 : } 43 : 0 : else if ( mConnString != connString || mProviderKey != layer->providerType() ) 44 : : { 45 : 0 : return false; 46 : : } 47 : : 48 : 0 : mLayers.insert( layer ); 49 : : 50 : 0 : connect( layer, &QgsVectorLayer::beforeEditingStarted, this, &QgsTransactionGroup::onEditingStarted ); 51 : 0 : connect( layer, &QgsVectorLayer::destroyed, this, &QgsTransactionGroup::onLayerDeleted ); 52 : : 53 : 0 : return true; 54 : 0 : } 55 : : 56 : 0 : QSet<QgsVectorLayer *> QgsTransactionGroup::layers() const 57 : : { 58 : 0 : return mLayers; 59 : : } 60 : : 61 : 0 : bool QgsTransactionGroup::modified() const 62 : : { 63 : 0 : const auto constMLayers = mLayers; 64 : 0 : for ( QgsVectorLayer *layer : constMLayers ) 65 : : { 66 : 0 : if ( layer->isModified() ) 67 : 0 : return true; 68 : : } 69 : 0 : return false; 70 : 0 : } 71 : : 72 : 0 : void QgsTransactionGroup::onEditingStarted() 73 : : { 74 : 0 : if ( mTransaction ) 75 : 0 : return; 76 : : 77 : 0 : mTransaction.reset( QgsTransaction::create( mConnString, mProviderKey ) ); 78 : 0 : if ( !mTransaction ) 79 : 0 : return; 80 : : 81 : 0 : QString errorMsg; 82 : 0 : mTransaction->begin( errorMsg ); 83 : : 84 : 0 : const auto constMLayers = mLayers; 85 : 0 : for ( QgsVectorLayer *layer : constMLayers ) 86 : : { 87 : 0 : mTransaction->addLayer( layer ); 88 : 0 : layer->startEditing(); 89 : 0 : connect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onBeforeCommitChanges ); 90 : 0 : connect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback ); 91 : : } 92 : 0 : } 93 : : 94 : 0 : void QgsTransactionGroup::onLayerDeleted() 95 : : { 96 : 0 : mLayers.remove( static_cast<QgsVectorLayer *>( sender() ) ); 97 : 0 : } 98 : : 99 : 0 : void QgsTransactionGroup::onBeforeCommitChanges( bool stopEditing ) 100 : : { 101 : 0 : if ( mEditingStopping ) 102 : 0 : return; 103 : : 104 : 0 : mEditingStopping = true; 105 : : 106 : 0 : const QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() ); 107 : : 108 : 0 : QString errMsg; 109 : 0 : if ( mTransaction->commit( errMsg ) ) 110 : : { 111 : 0 : const auto constMLayers = mLayers; 112 : 0 : for ( QgsVectorLayer *layer : constMLayers ) 113 : : { 114 : 0 : if ( layer != triggeringLayer ) 115 : : { 116 : 0 : layer->commitChanges( stopEditing ); 117 : 0 : } 118 : : } 119 : : 120 : 0 : if ( stopEditing ) 121 : : { 122 : 0 : disableTransaction(); 123 : 0 : } 124 : : else 125 : : { 126 : 0 : if ( ! mTransaction->begin( errMsg ) ) 127 : : { 128 : 0 : QgsDebugMsg( QStringLiteral( "Could not restart a transaction for %1: %2" ).arg( triggeringLayer->name() ).arg( errMsg ) ); 129 : 0 : } 130 : : } 131 : : 132 : 0 : } 133 : : else 134 : : { 135 : 0 : emit commitError( errMsg ); 136 : 0 : restartTransaction( triggeringLayer ); 137 : : } 138 : 0 : mEditingStopping = false; 139 : 0 : } 140 : : 141 : 0 : void QgsTransactionGroup::onRollback() 142 : : { 143 : 0 : if ( mEditingStopping ) 144 : 0 : return; 145 : : 146 : 0 : mEditingStopping = true; 147 : : 148 : 0 : QgsVectorLayer *triggeringLayer = qobject_cast<QgsVectorLayer *>( sender() ); 149 : : 150 : 0 : QString errMsg; 151 : 0 : if ( mTransaction->rollback( errMsg ) ) 152 : : { 153 : 0 : const auto constMLayers = mLayers; 154 : 0 : for ( QgsVectorLayer *layer : constMLayers ) 155 : : { 156 : 0 : if ( layer != triggeringLayer ) 157 : 0 : layer->rollBack(); 158 : : } 159 : 0 : disableTransaction(); 160 : 0 : } 161 : : else 162 : : { 163 : 0 : restartTransaction( triggeringLayer ); 164 : : } 165 : 0 : mEditingStopping = false; 166 : 0 : } 167 : : 168 : 0 : void QgsTransactionGroup::disableTransaction() 169 : : { 170 : 0 : mTransaction.reset(); 171 : : 172 : 0 : const auto constMLayers = mLayers; 173 : 0 : for ( QgsVectorLayer *layer : constMLayers ) 174 : : { 175 : 0 : disconnect( layer, &QgsVectorLayer::beforeCommitChanges, this, &QgsTransactionGroup::onBeforeCommitChanges ); 176 : 0 : disconnect( layer, &QgsVectorLayer::beforeRollBack, this, &QgsTransactionGroup::onRollback ); 177 : : } 178 : 0 : } 179 : : 180 : 0 : void QgsTransactionGroup::restartTransaction( const QgsVectorLayer *layer ) 181 : : { 182 : : // Restart editing the calling layer in the next event loop cycle 183 : 0 : QTimer::singleShot( 0, layer, &QgsVectorLayer::startEditing ); 184 : 0 : } 185 : : 186 : 0 : QString QgsTransactionGroup::providerKey() const 187 : : { 188 : 0 : return mProviderKey; 189 : : } 190 : : 191 : 0 : bool QgsTransactionGroup::isEmpty() const 192 : : { 193 : 0 : return mLayers.isEmpty(); 194 : : } 195 : : 196 : 0 : QString QgsTransactionGroup::connString() const 197 : : { 198 : 0 : return mConnString; 199 : : }