From c52b2d3ce4516e07324c55668bfcd089ea8ff1e8 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 18 Apr 2022 13:05:24 +1000 Subject: [PATCH] Show a layer tree next to elevation profile plots This: - Allows users to turn on or off the visibility of layers from the profile plot on a plot-by-plot basis (previously the layer visibility was taken straight from the main canvas layer visibility) - Allows users to rearrange the drawing order of layers in the plot - Allows a shortcut to the layer elevation properties settings by double clicking layers - Provides a "legend" for the features visible on the plot --- .../layertree/qgslayertreemodel.sip.in | 2 + src/app/CMakeLists.txt | 2 + .../qgselevationprofilelayertreemodel.cpp | 208 ++++++++++++++++++ .../qgselevationprofilelayertreemodel.h | 82 +++++++ .../qgselevationprofilelayertreeview.cpp | 62 ++++++ .../qgselevationprofilelayertreeview.h | 63 ++++++ .../elevation/qgselevationprofilewidget.cpp | 73 +++++- src/app/elevation/qgselevationprofilewidget.h | 10 +- .../mesh/qgsmeshelevationpropertieswidget.cpp | 1 + ...qgspointcloudelevationpropertieswidget.cpp | 1 + .../qgsrasterelevationpropertieswidget.cpp | 1 + .../qgsvectorelevationpropertieswidget.cpp | 1 + src/core/layertree/qgslayertreemodel.h | 10 +- .../vector/qgsvectorlayerprofilegenerator.cpp | 3 + 14 files changed, 505 insertions(+), 14 deletions(-) create mode 100644 src/app/elevation/qgselevationprofilelayertreemodel.cpp create mode 100644 src/app/elevation/qgselevationprofilelayertreemodel.h create mode 100644 src/app/elevation/qgselevationprofilelayertreeview.cpp create mode 100644 src/app/elevation/qgselevationprofilelayertreeview.h diff --git a/python/core/auto_generated/layertree/qgslayertreemodel.sip.in b/python/core/auto_generated/layertree/qgslayertreemodel.sip.in index 272b80e00d3..ddfbd2a4583 100644 --- a/python/core/auto_generated/layertree/qgslayertreemodel.sip.in +++ b/python/core/auto_generated/layertree/qgslayertreemodel.sip.in @@ -424,6 +424,8 @@ Filter nodes from :py:class:`QgsMapLayerLegend` according to the current filteri + + }; QFlags operator|(QgsLayerTreeModel::Flag f1, QFlags f2); diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 69a493ba4a3..afb2228fbac 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -175,6 +175,8 @@ set(QGIS_APP_SRCS elevation/qgselevationprofileexportsettingswidget.cpp elevation/qgselevationprofileimageexportdialog.cpp + elevation/qgselevationprofilelayertreemodel.cpp + elevation/qgselevationprofilelayertreeview.cpp elevation/qgselevationprofilepdfexportdialog.cpp elevation/qgselevationprofilewidget.cpp elevation/qgsmaptoolprofilecurve.cpp diff --git a/src/app/elevation/qgselevationprofilelayertreemodel.cpp b/src/app/elevation/qgselevationprofilelayertreemodel.cpp new file mode 100644 index 00000000000..fd6ec9e85b3 --- /dev/null +++ b/src/app/elevation/qgselevationprofilelayertreemodel.cpp @@ -0,0 +1,208 @@ +/*************************************************************************** + qgselevationprofilelayertreemodel.cpp + ----------------- + begin : April 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson at gmail dot com +***************************************************************************/ + + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgselevationprofilelayertreemodel.h" +#include "qgslayertreenode.h" +#include "qgslayertree.h" +#include "qgssymbollayerutils.h" +#include "qgsvectorlayerelevationproperties.h" +#include "qgsmeshlayerelevationproperties.h" +#include "qgsrasterlayerelevationproperties.h" +#include "qgsvectorlayer.h" +#include "qgssinglesymbolrenderer.h" +#include "qgsmarkersymbol.h" +#include "qgsfillsymbol.h" + +QgsElevationProfileLayerTreeModel::QgsElevationProfileLayerTreeModel( QgsLayerTree *rootNode, QObject *parent ) + : QgsLayerTreeModel( rootNode, parent ) +{ + setFlag( QgsLayerTreeModel::AllowNodeReorder ); + setFlag( QgsLayerTreeModel::AllowNodeChangeVisibility ); + setFlag( QgsLayerTreeModel::ShowLegendAsTree ); + setFlag( QgsLayerTreeModel::AllowLegendChangeState, false ); +} + +QVariant QgsElevationProfileLayerTreeModel::data( const QModelIndex &index, int role ) const +{ + switch ( role ) + { + case Qt::DecorationRole: + { + QgsLayerTreeNode *node = index2node( index ); + + if ( node && node->nodeType() == QgsLayerTreeNode::NodeLayer ) + { + if ( QgsMapLayer *layer = QgsLayerTree::toLayer( node )->layer() ) + { + std::unique_ptr context( createTemporaryRenderContext() ); + + const int iconSize = scaleIconSize( 16 ); + std::unique_ptr< QgsSymbol > symbol; + switch ( layer->type() ) + { + case QgsMapLayerType::VectorLayer: + { + QgsVectorLayerElevationProperties *elevationProperties = qgis::down_cast< QgsVectorLayerElevationProperties * >( layer->elevationProperties() ); + QgsVectorLayer *vLayer = qobject_cast< QgsVectorLayer * >( layer ); + + if ( ( vLayer->geometryType() == QgsWkbTypes::PointGeometry && !elevationProperties->extrusionEnabled() ) + || ( vLayer->geometryType() == QgsWkbTypes::LineGeometry && !elevationProperties->extrusionEnabled() ) + ) + { + if ( QgsMarkerSymbol *markerSymbol = elevationProperties->profileMarkerSymbol() ) + { + symbol.reset( markerSymbol->clone() ); + } + } + + if ( !symbol && vLayer->geometryType() == QgsWkbTypes::PolygonGeometry && elevationProperties->extrusionEnabled() ) + { + if ( QgsFillSymbol *fillSymbol = elevationProperties->profileFillSymbol() ) + { + symbol.reset( fillSymbol->clone() ); + } + } + + if ( !symbol ) + { + if ( QgsLineSymbol *lineSymbol = elevationProperties->profileLineSymbol() ) + { + symbol.reset( lineSymbol->clone() ); + } + } + + if ( qgis::down_cast< QgsVectorLayerElevationProperties * >( layer->elevationProperties() )->respectLayerSymbology() ) + { + if ( QgsSingleSymbolRenderer *renderer = dynamic_cast< QgsSingleSymbolRenderer * >( qobject_cast< QgsVectorLayer * >( layer )->renderer() ) ) + { + symbol->setColor( renderer->symbol()->color() ); + symbol->setOpacity( renderer->symbol()->opacity() ); + } + else + { + // just use default layer icon + return QgsLayerTreeModel::data( index, role ); + } + } + break; + } + + case QgsMapLayerType::RasterLayer: + if ( QgsLineSymbol *lineSymbol = qgis::down_cast< QgsRasterLayerElevationProperties * >( layer->elevationProperties() )->profileLineSymbol() ) + { + symbol.reset( lineSymbol->clone() ); + } + break; + + case QgsMapLayerType::MeshLayer: + if ( QgsLineSymbol *lineSymbol = qgis::down_cast< QgsMeshLayerElevationProperties * >( layer->elevationProperties() )->profileLineSymbol() ) + { + symbol.reset( lineSymbol->clone() ); + } + break; + + case QgsMapLayerType::PluginLayer: + case QgsMapLayerType::VectorTileLayer: + case QgsMapLayerType::AnnotationLayer: + case QgsMapLayerType::PointCloudLayer: + case QgsMapLayerType::GroupLayer: + break; + } + if ( !symbol ) + break; + + const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol.get(), QSize( iconSize, iconSize ), 0, context.get() ); + return QIcon( pix ); + } + } + break; + } + default: + break; + } + return QgsLayerTreeModel::data( index, role ); +} + + +// +// QgsElevationProfileLayerTreeProxyModel +// + +QgsElevationProfileLayerTreeProxyModel::QgsElevationProfileLayerTreeProxyModel( QgsElevationProfileLayerTreeModel *model, QObject *parent ) + : QSortFilterProxyModel( parent ) + , mModel( model ) +{ + setSourceModel( mModel ); + setDynamicSortFilter( true ); +} + +bool QgsElevationProfileLayerTreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const +{ + const QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent ); + if ( QgsLayerTreeNode *node = mModel->index2node( sourceIndex ) ) + { + switch ( node->nodeType() ) + { + case QgsLayerTreeNode::NodeLayer: + { + if ( QgsLayerTreeLayer *layerTreeLayer = QgsLayerTree::toLayer( node ) ) + { + if ( QgsMapLayer *layer = layerTreeLayer->layer() ) + { + // hide layers which don't have elevation + if ( !layer->elevationProperties() || !layer->elevationProperties()->hasElevation() ) + return false; + } + } + break; + } + + case QgsLayerTreeNode::NodeGroup: + break; + } + return true; + } + else if ( QgsLayerTreeModelLegendNode *legendNode = mModel->index2legendNode( sourceIndex ) ) + { + // we only show legend nodes for vector layers where the profile symbol is set to follow the layer's symbology + // (and the layer's renderer isn't a single symbol renderer) + if ( QgsLayerTreeLayer *layerTreeLayer = QgsLayerTree::toLayer( legendNode->layerNode() ) ) + { + if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( layerTreeLayer->layer() ) ) + { + if ( !qgis::down_cast< QgsVectorLayerElevationProperties * >( layer->elevationProperties() )->respectLayerSymbology() ) + { + return false; + } + else if ( dynamic_cast< QgsSingleSymbolRenderer * >( qobject_cast< QgsVectorLayer * >( layer )->renderer() ) ) + { + return false; + } + else + { + return true; + } + } + } + return false; + } + else + { + return false; + } +} diff --git a/src/app/elevation/qgselevationprofilelayertreemodel.h b/src/app/elevation/qgselevationprofilelayertreemodel.h new file mode 100644 index 00000000000..be3f987ef78 --- /dev/null +++ b/src/app/elevation/qgselevationprofilelayertreemodel.h @@ -0,0 +1,82 @@ +/*************************************************************************** + qgselevationprofilelayertreemodel.h + --------------- + begin : April 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson at gmail dot com +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSELEVATIONPROFILELAYERTREEMODEL_H +#define QGSELEVATIONPROFILELAYERTREEMODEL_H + +#include "qgsconfig.h" +#include "qgslayertreemodel.h" + +#include + +/** + * \ingroup app + * \brief A layer tree model subclass for elevation profiles. + * + * \since QGIS 3.26 + */ +class QgsElevationProfileLayerTreeModel : public QgsLayerTreeModel +{ + + Q_OBJECT + + public: + + /** + * Construct a new tree model with given layer tree (root node must not be NULLPTR). + * The root node is not transferred by the model. + */ + explicit QgsElevationProfileLayerTreeModel( QgsLayerTree *rootNode, QObject *parent = nullptr ); + + QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override; + + private: + +#ifdef SIP_RUN + QgsElevationProfileLayerTreeModel( const QgsElevationProfileLayerTreeModel &other ); +#endif +}; + +/** + * \ingroup gui + * \brief A proxy model for elevation profiles. + * + * \since QGIS 3.26 + */ +class QgsElevationProfileLayerTreeProxyModel : public QSortFilterProxyModel +{ + + Q_OBJECT + + public: + + /** + * Constructor for QgsElevationProfileLayerTreeProxyModel. + */ + explicit QgsElevationProfileLayerTreeProxyModel( QgsElevationProfileLayerTreeModel *model, QObject *parent = nullptr ); + + protected: + + bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const override; + + private: + + QgsElevationProfileLayerTreeModel *mModel = nullptr; + +}; + +#endif // QGSELEVATIONPROFILELAYERTREEMODEL_H diff --git a/src/app/elevation/qgselevationprofilelayertreeview.cpp b/src/app/elevation/qgselevationprofilelayertreeview.cpp new file mode 100644 index 00000000000..1247b06e1f3 --- /dev/null +++ b/src/app/elevation/qgselevationprofilelayertreeview.cpp @@ -0,0 +1,62 @@ +/*************************************************************************** + qgselevationprofilelayertreeview.cpp + ----------------- + begin : April 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson at gmail dot com +***************************************************************************/ + + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgselevationprofilelayertreeview.h" +#include "qgselevationprofilelayertreemodel.h" +#include "qgslayertreenode.h" +#include "qgslayertree.h" + +#include + +QgsElevationProfileLayerTreeView::QgsElevationProfileLayerTreeView( QgsLayerTree *rootNode, QWidget *parent ) + : QTreeView( parent ) + , mLayerTree( rootNode ) +{ + mModel = new QgsElevationProfileLayerTreeModel( rootNode, this ); + mProxyModel = new QgsElevationProfileLayerTreeProxyModel( mModel, this ); + + setHeaderHidden( true ); + + setDragEnabled( true ); + setAcceptDrops( true ); + setDropIndicatorShown( true ); + setExpandsOnDoubleClick( false ); + + // Ensure legend graphics are scrollable + header()->setStretchLastSection( false ); + header()->setSectionResizeMode( QHeaderView::ResizeToContents ); + + // If vertically scrolling by item, legend graphics can get clipped + setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); + + setDefaultDropAction( Qt::MoveAction ); + + setModel( mProxyModel ); +} + +QgsMapLayer *QgsElevationProfileLayerTreeView::indexToLayer( const QModelIndex &index ) +{ + if ( QgsLayerTreeNode *node = mModel->index2node( mProxyModel->mapToSource( index ) ) ) + { + if ( QgsLayerTreeLayer *layerTreeLayerNode = mLayerTree->toLayer( node ) ) + { + return layerTreeLayerNode->layer(); + } + } + return nullptr; +} diff --git a/src/app/elevation/qgselevationprofilelayertreeview.h b/src/app/elevation/qgselevationprofilelayertreeview.h new file mode 100644 index 00000000000..1d8a9596a38 --- /dev/null +++ b/src/app/elevation/qgselevationprofilelayertreeview.h @@ -0,0 +1,63 @@ +/*************************************************************************** + qgselevationprofilelayertreeview.h + --------------- + begin : April 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson at gmail dot com +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSELEVATIONPROFILELAYERTREEVIEW_H +#define QGSELEVATIONPROFILELAYERTREEVIEW_H + +#include "qgsconfig.h" + +#include + +class QgsLayerTree; +class QgsElevationProfileLayerTreeModel; +class QgsElevationProfileLayerTreeProxyModel; +class QgsMapLayer; + +/** + * \ingroup app + * \brief A layer tree view for elevation profiles. + * + * \since QGIS 3.26 + */ +class QgsElevationProfileLayerTreeView : public QTreeView +{ + + Q_OBJECT + + public: + + /** + * Construct a new tree view with given layer tree (root node must not be NULLPTR). + * The root node is not transferred by the view. + */ + explicit QgsElevationProfileLayerTreeView( QgsLayerTree *rootNode, QWidget *parent = nullptr ); + + /** + * Converts a view \a index to a map layer. + */ + QgsMapLayer *indexToLayer( const QModelIndex &index ); + + private: + + QgsElevationProfileLayerTreeModel *mModel = nullptr; + QgsElevationProfileLayerTreeProxyModel *mProxyModel = nullptr; + QgsLayerTree *mLayerTree = nullptr; + +}; + + +#endif // QGSELEVATIONPROFILELAYERTREEVIEW_H diff --git a/src/app/elevation/qgselevationprofilewidget.cpp b/src/app/elevation/qgselevationprofilewidget.cpp index 6533669b8da..741d72f73e1 100644 --- a/src/app/elevation/qgselevationprofilewidget.cpp +++ b/src/app/elevation/qgselevationprofilewidget.cpp @@ -40,15 +40,21 @@ #include "qgsfillsymbollayer.h" #include "qgsmarkersymbol.h" #include "qgsmarkersymbollayer.h" +#include "qgslayertree.h" +#include "qgslayertreeregistrybridge.h" +#include "qgselevationprofilelayertreeview.h" #include #include #include #include +#include QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name ) : QWidget( nullptr ) , mCanvasName( name ) + , mLayerTree( new QgsLayerTree() ) + , mLayerTreeBridge( new QgsLayerTreeRegistryBridge( mLayerTree.get(), QgsProject::instance(), this ) ) { setObjectName( QStringLiteral( "ElevationProfile" ) ); @@ -58,6 +64,9 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name ) QToolBar *toolBar = new QToolBar( this ); toolBar->setIconSize( QgisApp::instance()->iconSize( true ) ); + connect( mLayerTree.get(), &QgsLayerTree::layerOrderChanged, this, &QgsElevationProfileWidget::updateCanvasLayers ); + connect( mLayerTree.get(), &QgsLayerTreeGroup::visibilityChanged, this, &QgsElevationProfileWidget::updateCanvasLayers ); + mCanvas = new QgsElevationProfileCanvas( this ); mCanvas->setProject( QgsProject::instance() ); connect( mCanvas, &QgsElevationProfileCanvas::activeJobCountChanged, this, &QgsElevationProfileWidget::onTotalPendingJobsCountChanged ); @@ -66,6 +75,16 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name ) mPanTool = new QgsPlotToolPan( mCanvas ); mCanvas->setTool( mPanTool ); + mLayerTreeView = new QgsElevationProfileLayerTreeView( mLayerTree.get() ); + + connect( mLayerTreeView, &QAbstractItemView::doubleClicked, this, [ = ]( const QModelIndex & index ) + { + if ( QgsMapLayer *layer = mLayerTreeView->indexToLayer( index ) ) + { + QgisApp::instance()->showLayerProperties( layer, QStringLiteral( "mOptsPage_Elevation" ) ); + } + } ); + mZoomTool = new QgsPlotToolZoom( mCanvas ); mXAxisZoomTool = new QgsPlotToolXAxisZoom( mCanvas ); @@ -187,15 +206,29 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name ) layout->setContentsMargins( 0, 0, 0, 0 ); layout->setSpacing( 0 ); layout->addLayout( topLayout ); - layout->addWidget( mCanvas ); + QSplitter *splitter = new QSplitter( Qt::Horizontal ); + splitter->addWidget( mLayerTreeView ) ; + splitter->addWidget( mCanvas ); + layout->addWidget( splitter ); + splitter->setCollapsible( 0, false ); + splitter->setCollapsible( 1, false ); + splitter->setSizes( { QFontMetrics( font() ).horizontalAdvance( '0' ) * 10, splitter->width() } ); + QgsSettings settings; + splitter->restoreState( settings.value( QStringLiteral( "Windows/ElevationProfile/SplitState" ) ).toByteArray() ); + + connect( splitter, &QSplitter::splitterMoved, this, [splitter] + { + QgsSettings settings; + settings.setValue( QStringLiteral( "Windows/ElevationProfile/SplitState" ), splitter->saveState() ); + } ); setLayout( layout ); mDockableWidgetHelper = new QgsDockableWidgetHelper( true, mCanvasName, this, QgisApp::instance(), Qt::BottomDockWidgetArea, QStringList(), true ); QToolButton *toggleButton = mDockableWidgetHelper->createDockUndockToolButton(); toggleButton->setToolTip( tr( "Dock Elevation Profile View" ) ); toolBar->addWidget( toggleButton ); - connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, [ = ]() + connect( mDockableWidgetHelper, &QgsDockableWidgetHelper::closed, this, [ = ]() { close(); } ); @@ -205,6 +238,11 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name ) mSetCurveTimer->setSingleShot( true ); mSetCurveTimer->stop(); connect( mSetCurveTimer, &QTimer::timeout, this, &QgsElevationProfileWidget::updatePlot ); + + // initially populate layer tree with project layers + populateInitialLayers(); + + updateCanvasLayers(); } QgsElevationProfileWidget::~QgsElevationProfileWidget() @@ -262,10 +300,6 @@ void QgsElevationProfileWidget::setMainCanvas( QgsMapCanvas *canvas ) mMapPointRubberBand->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) ); mMapPointRubberBand->setColor( QColor( 0, 0, 0 ) ); mMapPointRubberBand->hide(); - - // only do this from map tool! - connect( mMainCanvas, &QgsMapCanvas::layersChanged, this, &QgsElevationProfileWidget::onMainCanvasLayersChanged ); - onMainCanvasLayersChanged(); } void QgsElevationProfileWidget::cancelJobs() @@ -273,16 +307,14 @@ void QgsElevationProfileWidget::cancelJobs() mCanvas->cancelJobs(); } -void QgsElevationProfileWidget::onMainCanvasLayersChanged() +void QgsElevationProfileWidget::populateInitialLayers() { - // possibly not right -- do we always want to sync the profile layers to canvas layers? - - QList< QgsMapLayer * > layers = mMainCanvas->layers( true ); + const QVector< QgsMapLayer * > layers = QgsProject::instance()->layers< QgsMapLayer * >(); // sort layers so that types which are more likely to obscure others are rendered below // e.g. vector features should be drawn above raster DEMS, or the DEM line may completely obscure // the vector feature - layers = QgsMapLayerUtils::sortLayersByType( layers, + QList< QgsMapLayer * > sortedLayers = QgsMapLayerUtils::sortLayersByType( QList< QgsMapLayer * >( layers.begin(), layers.end() ), { QgsMapLayerType::RasterLayer, QgsMapLayerType::MeshLayer, @@ -290,6 +322,25 @@ void QgsElevationProfileWidget::onMainCanvasLayersChanged() QgsMapLayerType::PointCloudLayer } ); + std::reverse( sortedLayers.begin(), sortedLayers.end() ); + for ( QgsMapLayer *layer : std::as_const( sortedLayers ) ) + { + mLayerTree->addLayer( layer ); + } +} + +void QgsElevationProfileWidget::updateCanvasLayers() +{ + QList layers; + const QList< QgsMapLayer * > layerOrder = mLayerTree->layerOrder(); + layers.reserve( layerOrder.size() ); + for ( QgsMapLayer *layer : layerOrder ) + { + if ( mLayerTree->findLayer( layer )->isVisible() ) + layers << layer; + } + + std::reverse( layers.begin(), layers.end() ); mCanvas->setLayers( layers ); scheduleUpdate(); } diff --git a/src/app/elevation/qgselevationprofilewidget.h b/src/app/elevation/qgselevationprofilewidget.h index 592b5f5c9f6..7d32ba8b283 100644 --- a/src/app/elevation/qgselevationprofilewidget.h +++ b/src/app/elevation/qgselevationprofilewidget.h @@ -40,6 +40,9 @@ class QgsPlotToolZoom; class QgsPlotToolXAxisZoom; class QgsDoubleSpinBox; class QgsElevationProfileWidgetSettingsAction; +class QgsElevationProfileLayerTreeView; +class QgsLayerTree; +class QgsLayerTreeRegistryBridge; class QgsElevationProfileWidget : public QWidget { @@ -67,7 +70,8 @@ class QgsElevationProfileWidget : public QWidget void toggleDockModeRequested( bool docked ); private slots: - void onMainCanvasLayersChanged(); + void populateInitialLayers(); + void updateCanvasLayers(); void onTotalPendingJobsCountChanged( int count ); void setProfileCurve( const QgsGeometry &curve ); void onCanvasPointHovered( const QgsPointXY &point ); @@ -106,6 +110,10 @@ class QgsElevationProfileWidget : public QWidget QgsPlotToolZoom *mZoomTool = nullptr; QgsElevationProfileWidgetSettingsAction *mSettingsAction = nullptr; + + std::unique_ptr< QgsLayerTree > mLayerTree; + QgsLayerTreeRegistryBridge *mLayerTreeBridge = nullptr; + QgsElevationProfileLayerTreeView *mLayerTreeView = nullptr; }; diff --git a/src/app/mesh/qgsmeshelevationpropertieswidget.cpp b/src/app/mesh/qgsmeshelevationpropertieswidget.cpp index d54865868a4..a2050e0d308 100644 --- a/src/app/mesh/qgsmeshelevationpropertieswidget.cpp +++ b/src/app/mesh/qgsmeshelevationpropertieswidget.cpp @@ -25,6 +25,7 @@ QgsMeshElevationPropertiesWidget::QgsMeshElevationPropertiesWidget( QgsMeshLayer : QgsMapLayerConfigWidget( layer, canvas, parent ) { setupUi( this ); + setObjectName( QStringLiteral( "mOptsPage_Elevation" ) ); mOffsetZSpinBox->setClearValue( 0 ); mScaleZSpinBox->setClearValue( 1 ); diff --git a/src/app/pointcloud/qgspointcloudelevationpropertieswidget.cpp b/src/app/pointcloud/qgspointcloudelevationpropertieswidget.cpp index 4cd45b888c5..b6be7cc0755 100644 --- a/src/app/pointcloud/qgspointcloudelevationpropertieswidget.cpp +++ b/src/app/pointcloud/qgspointcloudelevationpropertieswidget.cpp @@ -25,6 +25,7 @@ QgsPointCloudElevationPropertiesWidget::QgsPointCloudElevationPropertiesWidget( : QgsMapLayerConfigWidget( layer, canvas, parent ) { setupUi( this ); + setObjectName( QStringLiteral( "mOptsPage_Elevation" ) ); mOffsetZSpinBox->setClearValue( 0 ); mScaleZSpinBox->setClearValue( 1 ); diff --git a/src/app/raster/qgsrasterelevationpropertieswidget.cpp b/src/app/raster/qgsrasterelevationpropertieswidget.cpp index c864ace8e82..9df8d1e6d60 100644 --- a/src/app/raster/qgsrasterelevationpropertieswidget.cpp +++ b/src/app/raster/qgsrasterelevationpropertieswidget.cpp @@ -25,6 +25,7 @@ QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRaste : QgsMapLayerConfigWidget( layer, canvas, parent ) { setupUi( this ); + setObjectName( QStringLiteral( "mOptsPage_Elevation" ) ); mOffsetZSpinBox->setClearValue( 0 ); mScaleZSpinBox->setClearValue( 1 ); diff --git a/src/app/vector/qgsvectorelevationpropertieswidget.cpp b/src/app/vector/qgsvectorelevationpropertieswidget.cpp index eac141606c8..b610e234c0b 100644 --- a/src/app/vector/qgsvectorelevationpropertieswidget.cpp +++ b/src/app/vector/qgsvectorelevationpropertieswidget.cpp @@ -28,6 +28,7 @@ QgsVectorElevationPropertiesWidget::QgsVectorElevationPropertiesWidget( QgsVecto : QgsMapLayerConfigWidget( layer, canvas, parent ) { setupUi( this ); + setObjectName( QStringLiteral( "mOptsPage_Elevation" ) ); mOffsetZSpinBox->setClearValue( 0 ); mScaleZSpinBox->setClearValue( 1 ); diff --git a/src/core/layertree/qgslayertreemodel.h b/src/core/layertree/qgslayertreemodel.h index 18048c2e170..c0976337f81 100644 --- a/src/core/layertree/qgslayertreemodel.h +++ b/src/core/layertree/qgslayertreemodel.h @@ -370,6 +370,14 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel void legendInvalidateMapBasedData(); protected: + + /** + * Returns a temporary render context. + * + * \note Note available in Python bindings. + */ + QgsRenderContext *createTemporaryRenderContext() const SIP_SKIP; + //! Pointer to the root node of the layer tree. Not owned by the model QgsLayerTree *mRootNode = nullptr; //! Sets of flags for the model @@ -471,8 +479,6 @@ class CORE_EXPORT QgsLayerTreeModel : public QAbstractItemModel private: - //! Returns a temporary render context - QgsRenderContext *createTemporaryRenderContext() const; }; diff --git a/src/core/vector/qgsvectorlayerprofilegenerator.cpp b/src/core/vector/qgsvectorlayerprofilegenerator.cpp index fbf861d86f6..e7a8d0b6685 100644 --- a/src/core/vector/qgsvectorlayerprofilegenerator.cpp +++ b/src/core/vector/qgsvectorlayerprofilegenerator.cpp @@ -353,8 +353,11 @@ void QgsVectorLayerProfileResults::renderResults( QgsProfileRenderContext &conte continue; markerSymbol->setColor( rendererSymbol->color() ); + markerSymbol->setOpacity( rendererSymbol->opacity() ); lineSymbol->setColor( rendererSymbol->color() ); + lineSymbol->setOpacity( rendererSymbol->opacity() ); fillSymbol->setColor( rendererSymbol->color() ); + fillSymbol->setOpacity( rendererSymbol->opacity() ); markerSymbol->startRender( context.renderContext() ); lineSymbol->startRender( context.renderContext() );