diff --git a/python/core/auto_additions/qgis.py b/python/core/auto_additions/qgis.py index 451bc00e02e..c9416c79ea7 100644 --- a/python/core/auto_additions/qgis.py +++ b/python/core/auto_additions/qgis.py @@ -1328,6 +1328,13 @@ Qgis.FieldDomainType.__doc__ = 'Types of field domain\n\n.. versionadded:: 3.26\ # -- Qgis.FieldDomainType.baseClass = Qgis # monkey patching scoped based enum +Qgis.TransactionMode.None.__doc__ = "" +Qgis.TransactionMode.AutomaticGroups.__doc__ = "" +Qgis.TransactionMode.BufferedGroups.__doc__ = "" +Qgis.TransactionMode.__doc__ = 'BufferedGroups = 2, /*!< Buffered transactional editing means that all editable layers in the\nbuffered transaction group are toggled synchronously and all edits are\nsaved in a local edit buffer. Saving changes is executed within a single\ntransaction on all layers (per provider). *\n\n' + '* ``None``: ' + Qgis.TransactionMode.None.__doc__ + '\n' + '* ``AutomaticGroups``: ' + Qgis.TransactionMode.AutomaticGroups.__doc__ + '\n' + '* ``BufferedGroups``: ' + Qgis.TransactionMode.BufferedGroups.__doc__ +# -- +Qgis.TransactionMode.baseClass = Qgis +# monkey patching scoped based enum Qgis.AltitudeClamping.Absolute.__doc__ = "Elevation is taken directly from feature and is independent of terrain height (final elevation = feature elevation)" Qgis.AltitudeClamping.Relative.__doc__ = "Elevation is relative to terrain height (final elevation = terrain elevation + feature elevation)" Qgis.AltitudeClamping.Terrain.__doc__ = "Elevation is clamped to terrain (final elevation = terrain elevation)" diff --git a/python/core/auto_generated/project/qgsproject.sip.in b/python/core/auto_generated/project/qgsproject.sip.in index 5e3cbfb6257..8b731132a33 100644 --- a/python/core/auto_generated/project/qgsproject.sip.in +++ b/python/core/auto_generated/project/qgsproject.sip.in @@ -847,16 +847,19 @@ Gets the list of layers which currently should not be taken into account on map use :py:func:`QgsMapLayer.setFlags()` instead %End - bool autoTransaction() const; + bool autoTransaction() const /Deprecated/; %Docstring Transactional editing means that on supported datasources (postgres databases) the edit state of all tables that originate from the same database are synchronized and executed in a server side transaction. .. versionadded:: 2.16 + +.. deprecated:: + QGIS 3.24 use transactionMode instead %End - void setAutoTransaction( bool autoTransaction ); + void setAutoTransaction( bool autoTransaction ) /Deprecated/; %Docstring Transactional editing means that on supported datasources (postgres databases) the edit state of all tables that originate from the same database are synchronized and executed in a server side @@ -865,6 +868,29 @@ transaction. Make sure that this is only called when all layers are not in edit mode. .. versionadded:: 2.16 + +.. deprecated:: + QGIS 3.24 use setTransactionMode instead +%End + + Qgis::TransactionMode transactionMode() const; +%Docstring +Returns the transaction mode + +.. seealso:: Qgis.TransactionMode + +.. versionadded:: 3.24 +%End + + void setTransactionMode( Qgis::TransactionMode transactionMode ); +%Docstring +Set transaction mode + +Make sure that this is only called when all layers are not in edit mode. + +.. seealso:: Qgis.TransactionMode + +.. versionadded:: 3.24 %End diff --git a/python/core/auto_generated/qgis.sip.in b/python/core/auto_generated/qgis.sip.in index 0190912aa66..3f5b8734346 100644 --- a/python/core/auto_generated/qgis.sip.in +++ b/python/core/auto_generated/qgis.sip.in @@ -856,6 +856,13 @@ The development version Glob, }; + enum class TransactionMode + { + None, + AutomaticGroups, + BufferedGroups, + }; + enum class AltitudeClamping { Absolute, diff --git a/src/app/qgsprojectproperties.cpp b/src/app/qgsprojectproperties.cpp index 8ded5d9a644..861b2b3f5d9 100644 --- a/src/app/qgsprojectproperties.cpp +++ b/src/app/qgsprojectproperties.cpp @@ -168,6 +168,13 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa mAreaUnitsCombo->addItem( tr( "Square Degrees" ), QgsUnitTypes::AreaSquareDegrees ); mAreaUnitsCombo->addItem( tr( "Map Units" ), QgsUnitTypes::AreaUnknownUnit ); + mTransactionModeComboBox->addItem( tr( "Local edit buffer" ), static_cast< int >( Qgis::TransactionMode::None ) ); + mTransactionModeComboBox->setItemData( mTransactionModeComboBox->count() - 1, tr( "Edits are buffered locally and sent to the provider when togglinglayer editing mode." ), Qt::ToolTipRole ); + mTransactionModeComboBox->addItem( tr( "Automatic transaction groups" ), static_cast< int >( Qgis::TransactionMode::AutomaticGroups ) ); + mTransactionModeComboBox->setItemData( mTransactionModeComboBox->count() - 1, tr( "Automatic transactional editing means that on supported datasources (postgres databases) the edit state of all tables that originate from the same database are synchronized and executed in a server side transaction." ), Qt::ToolTipRole ); + mTransactionModeComboBox->addItem( tr( "Buffered transaction groups" ), static_cast< int >( Qgis::TransactionMode::None ) ); + mTransactionModeComboBox->setItemData( mTransactionModeComboBox->count() - 1, tr( "Buffered transactional editing means that all editable layers in the buffered transaction group are toggled synchronously and all edits are saved in a local edit buffer. Saving changes is executed within a single transaction on all layers (per provider)." ), Qt::ToolTipRole ); + projectionSelector->setShowNoProjection( true ); connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsProjectProperties::apply ); @@ -242,8 +249,8 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa { if ( layer->isEditable() ) { - mAutoTransaction->setEnabled( false ); - mAutoTransaction->setToolTip( tr( "Layers are in edit mode. Stop edit mode on all layers to toggle transactional editing." ) ); + mTransactionModeComboBox->setEnabled( false ); + mTransactionModeComboBox->setToolTip( tr( "Layers are in edit mode. Stop edit mode on all layers to toggle transactional editing." ) ); } } @@ -258,7 +265,6 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa mStartDateTimeEdit->setDateTime( range.begin() ); mEndDateTimeEdit->setDateTime( range.end() ); - mAutoTransaction->setChecked( QgsProject::instance()->autoTransaction() ); title( QgsProject::instance()->title() ); mProjectFileLineEdit->setText( QDir::toNativeSeparators( !QgsProject::instance()->fileName().isEmpty() ? QgsProject::instance()->fileName() : QgsProject::instance()->originalPath() ) ); mProjectHomeLineEdit->setShowClearButton( true ); @@ -958,7 +964,7 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa } mRelationManagerDlg->setLayers( vectorLayers ); - mAutoTransaction->setChecked( QgsProject::instance()->autoTransaction() ); + mTransactionModeComboBox->setCurrentIndex( mTransactionModeComboBox->findData( static_cast( QgsProject::instance()->transactionMode() ) ) ); mEvaluateDefaultValues->setChecked( QgsProject::instance()->evaluateDefaultValues() ); mTrustProjectCheckBox->setChecked( QgsProject::instance()->trustLayerMetadata() ); @@ -1091,7 +1097,7 @@ void QgsProjectProperties::apply() QgsProject::instance()->setPresetHomePath( QDir::fromNativeSeparators( mProjectHomeLineEdit->text() ) ); // DB-related options - QgsProject::instance()->setAutoTransaction( mAutoTransaction->isChecked() ); + QgsProject::instance()->setTransactionMode( mTransactionModeComboBox->currentData().value() ); QgsProject::instance()->setEvaluateDefaultValues( mEvaluateDefaultValues->isChecked() ); QgsProject::instance()->setTrustLayerMetadata( mTrustProjectCheckBox->isChecked() ); diff --git a/src/core/project/qgsproject.cpp b/src/core/project/qgsproject.cpp index 5cada49cf95..f785344ca92 100644 --- a/src/core/project/qgsproject.cpp +++ b/src/core/project/qgsproject.cpp @@ -820,7 +820,7 @@ void QgsProject::clear() mSaveVersion = QgsProjectVersion(); mHomePath.clear(); mCachedHomePath.clear(); - mAutoTransaction = false; + mTransactionMode = Qgis::TransactionMode::None; mEvaluateDefaultValues = false; mDirty = false; mTrustLayerMetadata = false; @@ -1586,11 +1586,20 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags } emit metadataChanged(); - element = doc->documentElement().firstChildElement( QStringLiteral( "autotransaction" ) ); - if ( ! element.isNull() ) + // Transaction mode + element = doc->documentElement().firstChildElement( QStringLiteral( "transaction-mode" ) ); + if ( !element.isNull() ) { - if ( element.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 ) - mAutoTransaction = true; + mTransactionMode = static_cast( element.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() ); + } + else + { + // maybe older project => try read autotransaction + element = doc->documentElement().firstChildElement( QStringLiteral( "autotransaction" ) ); + if ( ! element.isNull() ) + { + mTransactionMode = static_cast( element.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() ); + } } element = doc->documentElement().firstChildElement( QStringLiteral( "evaluateDefaultValues" ) ); @@ -2068,7 +2077,7 @@ void QgsProject::onMapLayersAdded( const QList &layers ) QgsVectorLayer *vlayer = qobject_cast( layer ); if ( vlayer ) { - if ( autoTransaction() ) + if ( transactionMode() == Qgis::TransactionMode::AutomaticGroups ) { if ( QgsTransaction::supportsTransaction( vlayer ) ) { @@ -2310,8 +2319,8 @@ bool QgsProject::writeProjectFile( const QString &filename ) QDomElement titleNode = doc->createElement( QStringLiteral( "title" ) ); qgisNode.appendChild( titleNode ); - QDomElement transactionNode = doc->createElement( QStringLiteral( "autotransaction" ) ); - transactionNode.setAttribute( QStringLiteral( "active" ), mAutoTransaction ? 1 : 0 ); + QDomElement transactionNode = doc->createElement( QStringLiteral( "transaction-mode" ) ); + transactionNode.setAttribute( QStringLiteral( "active" ), QString::number( static_cast( mTransactionMode ) ) ); qgisNode.appendChild( transactionNode ); QDomElement evaluateDefaultValuesNode = doc->createElement( QStringLiteral( "evaluateDefaultValues" ) ); @@ -3302,20 +3311,47 @@ QStringList QgsProject::nonIdentifiableLayers() const bool QgsProject::autoTransaction() const { - return mAutoTransaction; + return mTransactionMode == Qgis::TransactionMode::AutomaticGroups; } void QgsProject::setAutoTransaction( bool autoTransaction ) { - if ( autoTransaction != mAutoTransaction ) - { - mAutoTransaction = autoTransaction; + if ( autoTransaction + && mTransactionMode == Qgis::TransactionMode::AutomaticGroups ) + return; - if ( autoTransaction ) - onMapLayersAdded( mapLayers().values() ); - else - cleanTransactionGroups( true ); + if ( ! autoTransaction + && mTransactionMode == Qgis::TransactionMode::None ) + return; + + if ( autoTransaction ) + { + mTransactionMode = Qgis::TransactionMode::AutomaticGroups; + onMapLayersAdded( mapLayers().values() ); } + else + { + mTransactionMode = Qgis::TransactionMode::None; + cleanTransactionGroups( true ); + } +} + +Qgis::TransactionMode QgsProject::transactionMode() const +{ + return mTransactionMode; +} + +void QgsProject::setTransactionMode( Qgis::TransactionMode transactionMode ) +{ + if ( transactionMode == mTransactionMode ) + return; + + mTransactionMode = transactionMode; + + if ( mTransactionMode == Qgis::TransactionMode::AutomaticGroups ) + onMapLayersAdded( mapLayers().values() ); + else + cleanTransactionGroups( true ); } QMap, QgsTransactionGroup *> QgsProject::transactionGroups() diff --git a/src/core/project/qgsproject.h b/src/core/project/qgsproject.h index 309f8c6bf52..8c4d2cbd014 100644 --- a/src/core/project/qgsproject.h +++ b/src/core/project/qgsproject.h @@ -890,8 +890,9 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera * transaction. * * \since QGIS 2.16 + * \deprecated QGIS 3.24 use transactionMode instead */ - bool autoTransaction() const; + Q_DECL_DEPRECATED bool autoTransaction() const SIP_DEPRECATED; /** * Transactional editing means that on supported datasources (postgres databases) the edit state of @@ -901,8 +902,27 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera * Make sure that this is only called when all layers are not in edit mode. * * \since QGIS 2.16 + * \deprecated QGIS 3.24 use setTransactionMode instead */ - void setAutoTransaction( bool autoTransaction ); + Q_DECL_DEPRECATED void setAutoTransaction( bool autoTransaction ) SIP_DEPRECATED; + + /** + * Returns the transaction mode + * + * \see Qgis::TransactionMode + * \since QGIS 3.24 + */ + Qgis::TransactionMode transactionMode() const; + + /** + * Set transaction mode + * + * Make sure that this is only called when all layers are not in edit mode. + * + * \see Qgis::TransactionMode + * \since QGIS 3.24 + */ + void setTransactionMode( Qgis::TransactionMode transactionMode ); /** * Map of transaction groups @@ -2107,7 +2127,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera QColor mSelectionColor; mutable QgsProjectPropertyKey mProperties; // property hierarchy, TODO: this shouldn't be mutable - bool mAutoTransaction = false; // transaction grouped editing + Qgis::TransactionMode mTransactionMode = Qgis::TransactionMode::None; // transaction grouped editing bool mEvaluateDefaultValues = false; // evaluate default values immediately QgsCoordinateReferenceSystem mCrs; bool mDirty = false; // project has been modified since it has been read or saved diff --git a/src/core/qgis.h b/src/core/qgis.h index 8394891059d..6ea26804cec 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -1410,6 +1410,26 @@ class CORE_EXPORT Qgis }; Q_ENUM( FieldDomainType ) + /* + * Transaction mode. + * + * \since QGIS 3.24 + */ + enum class TransactionMode : int + { + None = 0, /*!< Edits are buffered locally and sent to the provider when toggling + * layer editing mode. */ + AutomaticGroups = 1, /*!< Automatic transactional editing means that on supported datasources + * (postgres databases) the edit state of all tables that originate from + * the same database are synchronized and executed in a server side + * transaction. */ + BufferedGroups = 2, /*!< Buffered transactional editing means that all editable layers in the + * buffered transaction group are toggled synchronously and all edits are + * saved in a local edit buffer. Saving changes is executed within a single + * transaction on all layers (per provider). */ + }; + Q_ENUM( TransactionMode ) + /** * Altitude clamping. * diff --git a/src/ui/qgsprojectpropertiesbase.ui b/src/ui/qgsprojectpropertiesbase.ui index 4fab6f59dcc..a53c8e443eb 100644 --- a/src/ui/qgsprojectpropertiesbase.ui +++ b/src/ui/qgsprojectpropertiesbase.ui @@ -1472,18 +1472,8 @@ - - - - - When enabled, layers from the same database connection will be put into a transaction group. Their edit state will be synchronized and changes to these layers will be sent to the provider immediately. Only supported for postgres, GPKG, spatialite and oracle. - - - Automatically create transaction groups where possible - - - - + + When enabled, default values will be evaluated as early as possible. This will fill default values in the add feature form already and not only create them on commit. Only supported for postgres, GPKG, spatialite and oracle. @@ -1493,7 +1483,14 @@ - + + + + Transaction mode + + + + Speed up project loading by skipping data checks in PostgreSQL layers. Useful in QGIS server context or project with huge database views or materialized views. @@ -1503,7 +1500,10 @@ - + + + + @@ -1570,6 +1570,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -3344,7 +3357,6 @@ mButtonPasteColors mButtonImportColors mButtonExportColors - mAutoTransaction mEvaluateDefaultValues mTrustProjectCheckBox mLayerCapabilitiesTree