mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-15 00:02:52 -04:00
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
This commit is contained in:
parent
7fa773e49e
commit
c52b2d3ce4
@ -424,6 +424,8 @@ Filter nodes from :py:class:`QgsMapLayerLegend` according to the current filteri
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
QFlags<QgsLayerTreeModel::Flag> operator|(QgsLayerTreeModel::Flag f1, QFlags<QgsLayerTreeModel::Flag> f2);
|
||||
|
@ -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
|
||||
|
208
src/app/elevation/qgselevationprofilelayertreemodel.cpp
Normal file
208
src/app/elevation/qgselevationprofilelayertreemodel.cpp
Normal file
@ -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<QgsRenderContext> 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;
|
||||
}
|
||||
}
|
82
src/app/elevation/qgselevationprofilelayertreemodel.h
Normal file
82
src/app/elevation/qgselevationprofilelayertreemodel.h
Normal file
@ -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 <QSortFilterProxyModel>
|
||||
|
||||
/**
|
||||
* \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
|
62
src/app/elevation/qgselevationprofilelayertreeview.cpp
Normal file
62
src/app/elevation/qgselevationprofilelayertreeview.cpp
Normal file
@ -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 <QHeaderView>
|
||||
|
||||
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;
|
||||
}
|
63
src/app/elevation/qgselevationprofilelayertreeview.h
Normal file
63
src/app/elevation/qgselevationprofilelayertreeview.h
Normal file
@ -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 <QTreeView>
|
||||
|
||||
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
|
@ -40,15 +40,21 @@
|
||||
#include "qgsfillsymbollayer.h"
|
||||
#include "qgsmarkersymbol.h"
|
||||
#include "qgsmarkersymbollayer.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslayertreeregistrybridge.h"
|
||||
#include "qgselevationprofilelayertreeview.h"
|
||||
|
||||
#include <QToolBar>
|
||||
#include <QProgressBar>
|
||||
#include <QTimer>
|
||||
#include <QPrinter>
|
||||
#include <QSplitter>
|
||||
|
||||
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<QgsMapLayer *> 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();
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@ QgsMeshElevationPropertiesWidget::QgsMeshElevationPropertiesWidget( QgsMeshLayer
|
||||
: QgsMapLayerConfigWidget( layer, canvas, parent )
|
||||
{
|
||||
setupUi( this );
|
||||
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
|
||||
|
||||
mOffsetZSpinBox->setClearValue( 0 );
|
||||
mScaleZSpinBox->setClearValue( 1 );
|
||||
|
@ -25,6 +25,7 @@ QgsPointCloudElevationPropertiesWidget::QgsPointCloudElevationPropertiesWidget(
|
||||
: QgsMapLayerConfigWidget( layer, canvas, parent )
|
||||
{
|
||||
setupUi( this );
|
||||
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
|
||||
|
||||
mOffsetZSpinBox->setClearValue( 0 );
|
||||
mScaleZSpinBox->setClearValue( 1 );
|
||||
|
@ -25,6 +25,7 @@ QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRaste
|
||||
: QgsMapLayerConfigWidget( layer, canvas, parent )
|
||||
{
|
||||
setupUi( this );
|
||||
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
|
||||
|
||||
mOffsetZSpinBox->setClearValue( 0 );
|
||||
mScaleZSpinBox->setClearValue( 1 );
|
||||
|
@ -28,6 +28,7 @@ QgsVectorElevationPropertiesWidget::QgsVectorElevationPropertiesWidget( QgsVecto
|
||||
: QgsMapLayerConfigWidget( layer, canvas, parent )
|
||||
{
|
||||
setupUi( this );
|
||||
setObjectName( QStringLiteral( "mOptsPage_Elevation" ) );
|
||||
|
||||
mOffsetZSpinBox->setClearValue( 0 );
|
||||
mScaleZSpinBox->setClearValue( 1 );
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user