From a17ab8f03b29a784920fedeab7d29672f4010fd5 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Sep 2022 17:04:26 +0700 Subject: [PATCH] Add UI to select which insertion method should be used when adding new layers --- python/core/auto_additions/qgis.py | 9 + .../qgslayertreeregistrybridge.sip.in | 14 + python/core/auto_generated/qgis.sip.in | 8 + src/app/layers/qgsapplayerhandling.cpp | 13 +- src/app/options/qgsoptions.cpp | 6 + src/app/qgisapp.cpp | 2 + .../layertree/qgslayertreeregistrybridge.cpp | 27 +- .../layertree/qgslayertreeregistrybridge.h | 14 + src/core/layertree/qgslayertreeutils.cpp | 15 - src/core/qgis.h | 13 + src/ui/qgsoptionsbase.ui | 360 +++++++----------- 11 files changed, 237 insertions(+), 244 deletions(-) diff --git a/python/core/auto_additions/qgis.py b/python/core/auto_additions/qgis.py index e92106e0860..6d8d3cac1f4 100644 --- a/python/core/auto_additions/qgis.py +++ b/python/core/auto_additions/qgis.py @@ -2045,6 +2045,7 @@ Qgis.CoordinateDisplayType.__doc__ = 'Formats for displaying coordinates\n\n.. v # -- Qgis.CoordinateDisplayType.baseClass = Qgis # monkey patching scoped based enum +<<<<<<< HEAD Qgis.ScriptLanguage.Css.__doc__ = "CSS" Qgis.ScriptLanguage.QgisExpression.__doc__ = "QGIS expressions" Qgis.ScriptLanguage.Html.__doc__ = "HTML" @@ -2057,3 +2058,11 @@ Qgis.ScriptLanguage.Unknown.__doc__ = "Unknown/other language" Qgis.ScriptLanguage.__doc__ = 'Scripting languages.\n\n.. versionadded:: 3.30\n\n' + '* ``Css``: ' + Qgis.ScriptLanguage.Css.__doc__ + '\n' + '* ``QgisExpression``: ' + Qgis.ScriptLanguage.QgisExpression.__doc__ + '\n' + '* ``Html``: ' + Qgis.ScriptLanguage.Html.__doc__ + '\n' + '* ``JavaScript``: ' + Qgis.ScriptLanguage.JavaScript.__doc__ + '\n' + '* ``Json``: ' + Qgis.ScriptLanguage.Json.__doc__ + '\n' + '* ``Python``: ' + Qgis.ScriptLanguage.Python.__doc__ + '\n' + '* ``R``: ' + Qgis.ScriptLanguage.R.__doc__ + '\n' + '* ``Sql``: ' + Qgis.ScriptLanguage.Sql.__doc__ + '\n' + '* ``Unknown``: ' + Qgis.ScriptLanguage.Unknown.__doc__ # -- Qgis.ScriptLanguage.baseClass = Qgis +======= +Qgis.LayerTreeInsertionMethod.AboveInsertionPoint.__doc__ = "Layers are added in the tree above the insertion point" +Qgis.LayerTreeInsertionMethod.TopOfTree.__doc__ = "Layers are added at the top of the layer tree" +Qgis.LayerTreeInsertionMethod.OptimalInInsertionGroup.__doc__ = "Layers are added at optimal locations across the insertion point's group" +Qgis.LayerTreeInsertionMethod.__doc__ = 'Layer tree insertion methods\n\n.. versionadded:: 3.30\n\n' + '* ``AboveInsertionPoint``: ' + Qgis.LayerTreeInsertionMethod.AboveInsertionPoint.__doc__ + '\n' + '* ``TopOfTree``: ' + Qgis.LayerTreeInsertionMethod.TopOfTree.__doc__ + '\n' + '* ``OptimalInInsertionGroup``: ' + Qgis.LayerTreeInsertionMethod.OptimalInInsertionGroup.__doc__ +# -- +Qgis.LayerTreeInsertionMethod.baseClass = Qgis +>>>>>>> 4a95e2b0a8 (Add UI to select which insertion method should be used when adding new layers) diff --git a/python/core/auto_generated/layertree/qgslayertreeregistrybridge.sip.in b/python/core/auto_generated/layertree/qgslayertreeregistrybridge.sip.in index b167cdbe221..a95bff38684 100644 --- a/python/core/auto_generated/layertree/qgslayertreeregistrybridge.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreeregistrybridge.sip.in @@ -67,6 +67,20 @@ Set where the new layers should be inserted - can be used to follow current sele By default it is root group with zero index. .. versionadded:: 3.10 +%End + + void setLayerInsertionMethod( Qgis::LayerTreeInsertionMethod method ); +%Docstring +Sets the insertion ``method`` used to add layers to the tree + +.. versionadded:: 3.30 +%End + + Qgis::LayerTreeInsertionMethod layerInsertionMethod() const; +%Docstring +Returns the insertion method used to add layers to the tree + +.. versionadded:: 3.30 %End signals: diff --git a/python/core/auto_generated/qgis.sip.in b/python/core/auto_generated/qgis.sip.in index c2a1b6cf0ad..8cb96391861 100644 --- a/python/core/auto_generated/qgis.sip.in +++ b/python/core/auto_generated/qgis.sip.in @@ -1327,6 +1327,7 @@ The development version CustomCrs, }; +<<<<<<< HEAD enum class ScriptLanguage { Css, @@ -1338,6 +1339,13 @@ The development version R, Sql, Unknown, +======= + enum class LayerTreeInsertionMethod + { + AboveInsertionPoint, + TopOfTree, + OptimalInInsertionGroup, +>>>>>>> 4a95e2b0a8 (Add UI to select which insertion method should be used when adding new layers) }; static const double DEFAULT_SEARCH_RADIUS_MM; diff --git a/src/app/layers/qgsapplayerhandling.cpp b/src/app/layers/qgsapplayerhandling.cpp index 516eb708413..b160969005a 100644 --- a/src/app/layers/qgsapplayerhandling.cpp +++ b/src/app/layers/qgsapplayerhandling.cpp @@ -214,7 +214,18 @@ void QgsAppLayerHandling::addSortedLayersToLegend( QList &layers for ( QgsMapLayer *layer : layers ) { - parent->insertLayer( currentIndex, layer ); + switch ( QgsProject::instance()->layerTreeRegistryBridge()->layerInsertionMethod() ) + { + case Qgis::LayerTreeInsertionMethod::AboveInsertionPoint: + parent->insertLayer( currentIndex, layer ); + break; + case Qgis::LayerTreeInsertionMethod::TopOfTree: + QgsProject::instance()->layerTreeRoot()->insertLayer( 0, layer ); + break; + case Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup: + QgsLayerTreeUtils::insertLayerAtOptimalPlacement( parent, layer ); + break; + } } QgisApp::instance()->layerTreeView()->setCurrentLayer( layers.at( 0 ) ); } diff --git a/src/app/options/qgsoptions.cpp b/src/app/options/qgsoptions.cpp index b0b6d74af21..95c86c5ca0b 100644 --- a/src/app/options/qgsoptions.cpp +++ b/src/app/options/qgsoptions.cpp @@ -711,6 +711,11 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QListsetCurrentIndex( mSettings->value( QStringLiteral( "/qgis/legendDoubleClickAction" ), 0 ).toInt() ); + mLayerTreeInsertionMethod->addItem( tr( "Above currently currently selected layer" ), QVariant::fromValue( Qgis::LayerTreeInsertionMethod::AboveInsertionPoint ) ); + mLayerTreeInsertionMethod->addItem( tr( "Always on top of the layer tree" ), QVariant::fromValue( Qgis::LayerTreeInsertionMethod::TopOfTree ) ); + mLayerTreeInsertionMethod->addItem( tr( "Optimal index within current layer tree group" ), QVariant::fromValue( Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup ) ); + mLayerTreeInsertionMethod->setCurrentIndex( mLayerTreeInsertionMethod->findData( QVariant::fromValue( mSettings->enumValue( QStringLiteral( "/qgis/layerTreeInsertionMethod" ), Qgis::LayerTreeInsertionMethod::AboveInsertionPoint ) ) ) ); + // Legend symbol minimum / maximum values mLegendSymbolMinimumSizeSpinBox->setClearValue( 0.0, tr( "none" ) ); mLegendSymbolMaximumSizeSpinBox->setClearValue( 0.0, tr( "none" ) ); @@ -1586,6 +1591,7 @@ void QgsOptions::saveOptions() QgisApp::instance()->setMapTipsDelay( mMapTipsDelaySpinBox->value() ); mSettings->setValue( QStringLiteral( "/qgis/legendDoubleClickAction" ), cmbLegendDoubleClickAction->currentIndex() ); + mSettings->setEnumValue( QStringLiteral( "/qgis/layerTreeInsertionMethod" ), mLayerTreeInsertionMethod->currentData().value() ); // project mSettings->setValue( QStringLiteral( "/qgis/projOpenAtLaunch" ), mProjectOnLaunchCmbBx->currentIndex() ); diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index da60db550b8..9324db4860e 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -5577,6 +5577,7 @@ bool QgisApp::fileNew( bool promptToSaveFlag, bool forceBlank ) QgsProject *prj = QgsProject::instance(); prj->layerTreeRegistryBridge()->setNewLayersVisible( settings.value( QStringLiteral( "qgis/new_layers_visible" ), true ).toBool() ); + prj->layerTreeRegistryBridge()->setLayerInsertionMethod( settings.enumValue( QStringLiteral( "qgis/layerTreeInsertionMethod" ), Qgis::LayerTreeInsertionMethod::AboveInsertionPoint ) ); //set the canvas to the default project background color mOverviewCanvas->setBackgroundColor( prj->backgroundColor() ); @@ -12333,6 +12334,7 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString ¤tPage, in if ( optionsDialog->exec() ) { QgsProject::instance()->layerTreeRegistryBridge()->setNewLayersVisible( mySettings.value( QStringLiteral( "qgis/new_layers_visible" ), true ).toBool() ); + QgsProject::instance()->layerTreeRegistryBridge()->setLayerInsertionMethod( mySettings.enumValue( QStringLiteral( "qgis/layerTreeInsertionMethod" ), Qgis::LayerTreeInsertionMethod::AboveInsertionPoint ) ); setupLayerTreeViewFromSettings(); diff --git a/src/core/layertree/qgslayertreeregistrybridge.cpp b/src/core/layertree/qgslayertreeregistrybridge.cpp index e2536b4efd5..243baccc30b 100644 --- a/src/core/layertree/qgslayertreeregistrybridge.cpp +++ b/src/core/layertree/qgslayertreeregistrybridge.cpp @@ -16,7 +16,7 @@ #include "qgslayertreeregistrybridge.h" #include "qgslayertree.h" - +#include "qgslayertreeutils.h" #include "qgsproject.h" #include "qgslogger.h" @@ -55,7 +55,16 @@ void QgsLayerTreeRegistryBridge::layersAdded( const QList &layers QList nodes; for ( QgsMapLayer *layer : layers ) { - QgsLayerTreeLayer *nodeLayer = new QgsLayerTreeLayer( layer ); + QgsLayerTreeLayer *nodeLayer; + if ( mInsertionMethod == Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup ) + { + nodeLayer = QgsLayerTreeUtils::insertLayerAtOptimalPlacement( mInsertionPoint.group, layer ); + } + else + { + nodeLayer = new QgsLayerTreeLayer( layer ); + } + nodeLayer->setItemVisibilityChecked( mNewLayersVisible ); nodes << nodeLayer; @@ -69,8 +78,18 @@ void QgsLayerTreeRegistryBridge::layersAdded( const QList &layers } } - // add new layers to the right place - mInsertionPoint.group->insertChildNodes( mInsertionPoint.position, nodes ); + switch ( mInsertionMethod ) + { + case Qgis::LayerTreeInsertionMethod::AboveInsertionPoint: + mInsertionPoint.group->insertChildNodes( mInsertionPoint.position, nodes ); + break; + case Qgis::LayerTreeInsertionMethod::TopOfTree: + mRoot->insertChildNodes( 0, nodes ); + break; + case Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup: + default: + break; + } // tell other components that layers have been added - this signal is used in QGIS to auto-select the first layer emit addedLayersToLayerTree( layers ); diff --git a/src/core/layertree/qgslayertreeregistrybridge.h b/src/core/layertree/qgslayertreeregistrybridge.h index 121bb56fb35..635499360fa 100644 --- a/src/core/layertree/qgslayertreeregistrybridge.h +++ b/src/core/layertree/qgslayertreeregistrybridge.h @@ -21,6 +21,7 @@ #include "qgis_core.h" #include "qgis_sip.h" +#include "qgis.h" class QgsLayerTreeGroup; class QgsLayerTreeNode; @@ -84,6 +85,18 @@ class CORE_EXPORT QgsLayerTreeRegistryBridge : public QObject */ void setLayerInsertionPoint( const InsertionPoint &insertionPoint ); + /** + * Sets the insertion \a method used to add layers to the tree + * \since QGIS 3.30 + */ + void setLayerInsertionMethod( Qgis::LayerTreeInsertionMethod method ) { mInsertionMethod = method; } + + /** + * Returns the insertion method used to add layers to the tree + * \since QGIS 3.30 + */ + Qgis::LayerTreeInsertionMethod layerInsertionMethod() const { return mInsertionMethod; } + signals: /** @@ -110,6 +123,7 @@ class CORE_EXPORT QgsLayerTreeRegistryBridge : public QObject bool mNewLayersVisible; InsertionPoint mInsertionPoint; + Qgis::LayerTreeInsertionMethod mInsertionMethod = Qgis::LayerTreeInsertionMethod::AboveInsertionPoint; }; #endif // QGSLAYERTREEREGISTRYBRIDGE_H diff --git a/src/core/layertree/qgslayertreeutils.cpp b/src/core/layertree/qgslayertreeutils.cpp index d0fa49bdf2c..d98ab92347e 100644 --- a/src/core/layertree/qgslayertreeutils.cpp +++ b/src/core/layertree/qgslayertreeutils.cpp @@ -623,26 +623,14 @@ QgsLayerTreeLayer *QgsLayerTreeUtils::insertLayerAtOptimalPlacement( QgsLayerTre if ( vlayer->geometryType() == QgsWkbTypes::PointGeometry ) { index = 0; - vectorLineIndex++; - vectorPolygonIndex++; - pointCloudIndex++; - meshIndex++; - rasterIndex++; } else if ( vlayer->geometryType() == QgsWkbTypes::LineGeometry ) { index = vectorLineIndex; - vectorPolygonIndex++; - pointCloudIndex++; - meshIndex++; - rasterIndex++; } else if ( vlayer->geometryType() == QgsWkbTypes::PolygonGeometry ) { index = vectorPolygonIndex; - pointCloudIndex++; - meshIndex++; - rasterIndex++; } break; } @@ -650,15 +638,12 @@ QgsLayerTreeLayer *QgsLayerTreeUtils::insertLayerAtOptimalPlacement( QgsLayerTre case QgsMapLayerType::PointCloudLayer: { index = pointCloudIndex; - meshIndex++; - rasterIndex++; break; } case QgsMapLayerType::MeshLayer: { index = meshIndex; - rasterIndex++; break; } diff --git a/src/core/qgis.h b/src/core/qgis.h index 85a71587737..f7c3dc94d9a 100644 --- a/src/core/qgis.h +++ b/src/core/qgis.h @@ -2304,6 +2304,19 @@ class CORE_EXPORT Qgis }; Q_ENUM( ScriptLanguage ) + /** + * Layer tree insertion methods + * + * \since QGIS 3.30 + */ + enum class LayerTreeInsertionMethod : int + { + AboveInsertionPoint, //!< Layers are added in the tree above the insertion point + TopOfTree, //!< Layers are added at the top of the layer tree + OptimalInInsertionGroup, //!< Layers are added at optimal locations across the insertion point's group + }; + Q_ENUM( LayerTreeInsertionMethod ) + /** * Identify search radius in mm * \since QGIS 2.3 diff --git a/src/ui/qgsoptionsbase.ui b/src/ui/qgsoptionsbase.ui index 44a418ee504..91cb3c67276 100644 --- a/src/ui/qgsoptionsbase.ui +++ b/src/ui/qgsoptionsbase.ui @@ -2552,225 +2552,159 @@ Layer Legend - - - - - - - Double-click action in legend - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - Open layer properties - - - - - Open attribute table - - - - - Open layer styling dock - - - - - + + + + + Double-click action in legend + + - + + + + + Open layer properties + + + + + Open attribute table + + + + + Open layer styling dock + + + + + + + + Behavior used when adding new layers + + + + + + + + Show feature count for newly added layers - + Display classification attribute in layer titles - - - - - - WMS getLegendGraphic resolution - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 30 - 20 - - - - - - - + + + + WMS getLegendGraphic resolution + + + + + + - - + + - - + + dpi - - + + 0 - - + + 1000000 - - - - + + - - - - - - Minimum legend symbol size - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 30 - 20 - - - - - - - - - 0 - 0 - - - - - - - mm - - - 2 - - - 999.000000000000000 - - - 0.200000000000000 - - - 0.100000000000000 - - - true - - - - + + + + Minimum legend symbol size + + - - - - - - Maximum legend symbol size - - - - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 30 - 20 - - - - - - - - - 0 - 0 - - - - - - - mm - - - 2 - - - 999.000000000000000 - - - 0.200000000000000 - - - 20.000000000000000 - - - true - - - - + + + + + 0 + 0 + + + + + + + mm + + + 2 + + + 999.000000000000000 + + + 0.200000000000000 + + + 0.100000000000000 + + + true + + + + + + + Maximum legend symbol size + + + + + + + + 0 + 0 + + + + + + + mm + + + 2 + + + 999.000000000000000 + + + 0.200000000000000 + + + 20.000000000000000 + + + true + + @@ -2780,37 +2714,15 @@ Map Tips - - + + - - - 0 - 0 - - Delay (in milliseconds) - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 30 - 20 - - - - - +