mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
Add an explicit "Add Layers" button to elevation profile dock
This provides a user-friendly why of adding new layers to a plot - clicking it will show a filtered list of possible layers which can be added to the plot, but which currently aren't in the plot. (I.e it will include all raster layers from the project which aren't marked as having elevation data.) Selecting layers will cause them to automatically be marked as having elevation data and immediately added to the plot.
This commit is contained in:
parent
d0f61c9a52
commit
29f0d479d0
@ -28,6 +28,22 @@ Calculates the elevation range for a ``project``.
|
||||
|
||||
This method considers the elevation (or z) range available from layers contained within the project and
|
||||
returns the maximal combined elevation range of these layers.
|
||||
%End
|
||||
|
||||
static bool canEnableElevationForLayer( QgsMapLayer *layer );
|
||||
%Docstring
|
||||
Returns ``True`` if elevation can be enabled for a map ``layer``.
|
||||
|
||||
.. versionadded:: 3.32
|
||||
%End
|
||||
|
||||
static bool enableElevationForLayer( QgsMapLayer *layer );
|
||||
%Docstring
|
||||
Automatically enables elevation for a map ``layer``, using reasonable defaults.
|
||||
|
||||
Returns ``True`` if the elevation was enabled successfully.
|
||||
|
||||
.. versionadded:: 3.32
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "qgselevationprofilecanvas.h"
|
||||
#include "qgsdockablewidgethelper.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsmaplayerelevationproperties.h"
|
||||
#include "qgsmaplayermodel.h"
|
||||
#include "qgsmaptoolprofilecurve.h"
|
||||
#include "qgsmaptoolprofilecurvefromfeature.h"
|
||||
#include "qgsrubberband.h"
|
||||
@ -47,6 +49,8 @@
|
||||
#include "qgselevationprofiletoolmeasure.h"
|
||||
#include "qgssettingsentryimpl.h"
|
||||
#include "qgssettingstree.h"
|
||||
#include "qgsmaplayerproxymodel.h"
|
||||
#include "qgselevationutils.h"
|
||||
|
||||
|
||||
#include <QToolBar>
|
||||
@ -61,6 +65,71 @@ const QgsSettingsEntryDouble *QgsElevationProfileWidget::settingTolerance = new
|
||||
const QgsSettingsEntryBool *QgsElevationProfileWidget::settingShowLayerTree = new QgsSettingsEntryBool( QStringLiteral( "show-layer-tree" ), QgsSettingsTree::sTreeElevationProfile, true, QStringLiteral( "Whether the layer tree should be shown for elevation profile plots" ) );
|
||||
const QgsSettingsEntryBool *QgsElevationProfileWidget::settingLockAxis = new QgsSettingsEntryBool( QStringLiteral( "lock-axis-ratio" ), QgsSettingsTree::sTreeElevationProfile, false, QStringLiteral( "Whether the the distance and elevation axis scales are locked to each other" ) );
|
||||
|
||||
//
|
||||
// QgsElevationProfileLayersDialog
|
||||
//
|
||||
|
||||
QgsElevationProfileLayersDialog::QgsElevationProfileLayersDialog( QWidget *parent )
|
||||
: QDialog( parent )
|
||||
{
|
||||
setupUi( this );
|
||||
QgsGui::enableAutoGeometryRestore( this );
|
||||
|
||||
mFilterLineEdit->setShowClearButton( true );
|
||||
mFilterLineEdit->setShowSearchIcon( true );
|
||||
|
||||
mModel = new QgsMapLayerProxyModel( listMapLayers );
|
||||
listMapLayers->setModel( mModel );
|
||||
const QModelIndex firstLayer = mModel->index( 0, 0 );
|
||||
listMapLayers->selectionModel()->select( firstLayer, QItemSelectionModel::Select );
|
||||
|
||||
connect( listMapLayers, &QListView::doubleClicked, this, &QgsElevationProfileLayersDialog::accept );
|
||||
|
||||
connect( mFilterLineEdit, &QLineEdit::textChanged, mModel, &QgsMapLayerProxyModel::setFilterString );
|
||||
connect( mCheckBoxVisibleLayers, &QCheckBox::toggled, this, &QgsElevationProfileLayersDialog::filterVisible );
|
||||
|
||||
mFilterLineEdit->setFocus();
|
||||
}
|
||||
|
||||
void QgsElevationProfileLayersDialog::setVisibleLayers( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
mVisibleLayers = layers;
|
||||
}
|
||||
|
||||
void QgsElevationProfileLayersDialog::setHiddenLayers( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
mModel->setExceptedLayerList( layers );
|
||||
}
|
||||
|
||||
QList< QgsMapLayer *> QgsElevationProfileLayersDialog::selectedLayers() const
|
||||
{
|
||||
QList< QgsMapLayer * > layers;
|
||||
|
||||
const QModelIndexList selection = listMapLayers->selectionModel()->selectedIndexes();
|
||||
for ( const QModelIndex &index : selection )
|
||||
{
|
||||
const QModelIndex sourceIndex = mModel->mapToSource( index );
|
||||
if ( !sourceIndex.isValid() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QgsMapLayer *layer = mModel->sourceLayerModel()->layerFromIndex( sourceIndex );
|
||||
if ( layer )
|
||||
layers << layer;
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
void QgsElevationProfileLayersDialog::filterVisible( bool enabled )
|
||||
{
|
||||
if ( enabled )
|
||||
mModel->setLayerAllowlist( mVisibleLayers );
|
||||
else
|
||||
mModel->setLayerAllowlist( QList< QgsMapLayer * >() );
|
||||
}
|
||||
|
||||
|
||||
QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
|
||||
: QWidget( nullptr )
|
||||
, mCanvasName( name )
|
||||
@ -103,6 +172,11 @@ QgsElevationProfileWidget::QgsElevationProfileWidget( const QString &name )
|
||||
|
||||
mCanvas->setTool( mIdentifyTool );
|
||||
|
||||
QAction *addLayerAction = new QAction( tr( "Add Layers" ), this );
|
||||
addLayerAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionAddLayer.svg" ) ) );
|
||||
connect( addLayerAction, &QAction::triggered, this, &QgsElevationProfileWidget::addLayers );
|
||||
toolBar->addAction( addLayerAction );
|
||||
|
||||
QAction *showLayerTree = new QAction( tr( "Show Layer Tree" ), this );
|
||||
showLayerTree->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconLayerTree.svg" ) ) );
|
||||
showLayerTree->setCheckable( true );
|
||||
@ -386,6 +460,53 @@ void QgsElevationProfileWidget::cancelJobs()
|
||||
mCanvas->cancelJobs();
|
||||
}
|
||||
|
||||
void QgsElevationProfileWidget::addLayers()
|
||||
{
|
||||
QgsElevationProfileLayersDialog addDialog( this );
|
||||
const QMap<QString, QgsMapLayer *> allMapLayers = QgsProject::instance()->mapLayers();
|
||||
|
||||
// The add layers dialog should only show layers which CAN have elevation, yet currently don't
|
||||
// have it enabled. So collect layers which don't match this criteria now for filtering out.
|
||||
QList< QgsMapLayer * > layersWhichAlreadyHaveElevationOrCannotHaveElevation;
|
||||
for ( auto it = allMapLayers.constBegin(); it != allMapLayers.constEnd(); ++it )
|
||||
{
|
||||
if ( !QgsElevationUtils::canEnableElevationForLayer( it.value() ) || it.value()->elevationProperties()->hasElevation() )
|
||||
{
|
||||
layersWhichAlreadyHaveElevationOrCannotHaveElevation << it.value();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addDialog.setHiddenLayers( layersWhichAlreadyHaveElevationOrCannotHaveElevation );
|
||||
|
||||
addDialog.setVisibleLayers( mMainCanvas->layers( true ) );
|
||||
|
||||
if ( addDialog.exec() == QDialog::Accepted )
|
||||
{
|
||||
const QList<QgsMapLayer *> layers = addDialog.selectedLayers();
|
||||
QList< QgsMapLayer * > updatedLayers;
|
||||
if ( !layers.empty() )
|
||||
{
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
if ( QgsElevationUtils::enableElevationForLayer( layer ) )
|
||||
updatedLayers << layer;
|
||||
}
|
||||
|
||||
mLayerTreeView->proxyModel()->invalidate();
|
||||
for ( QgsMapLayer *layer : std::as_const( updatedLayers ) )
|
||||
{
|
||||
if ( QgsLayerTreeLayer *node = mLayerTree->findLayer( layer ) )
|
||||
{
|
||||
node->setItemVisibilityChecked( true );
|
||||
}
|
||||
}
|
||||
|
||||
updateCanvasLayers();
|
||||
scheduleUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsElevationProfileWidget::updateCanvasLayers()
|
||||
{
|
||||
QList<QgsMapLayer *> layers;
|
||||
@ -393,6 +514,10 @@ void QgsElevationProfileWidget::updateCanvasLayers()
|
||||
layers.reserve( layerOrder.size() );
|
||||
for ( QgsMapLayer *layer : layerOrder )
|
||||
{
|
||||
// safety check. maybe elevation properties have been disabled externally.
|
||||
if ( !layer->elevationProperties() || !layer->elevationProperties()->hasElevation() )
|
||||
continue;
|
||||
|
||||
if ( mLayerTree->findLayer( layer )->isVisible() )
|
||||
layers << layer;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "qgsgeometry.h"
|
||||
#include "qobjectuniqueptr.h"
|
||||
#include "qgselevationprofilelayertreeview.h"
|
||||
#include "ui_qgselevationprofileaddlayersdialogbase.h"
|
||||
|
||||
#include <QWidgetAction>
|
||||
#include <QElapsedTimer>
|
||||
@ -50,6 +51,7 @@ class QLabel;
|
||||
class QgsProfilePoint;
|
||||
class QgsSettingsEntryDouble;
|
||||
class QgsSettingsEntryBool;
|
||||
class QgsMapLayerProxyModel;
|
||||
|
||||
class QgsAppElevationProfileLayerTreeView : public QgsElevationProfileLayerTreeView
|
||||
{
|
||||
@ -63,6 +65,26 @@ class QgsAppElevationProfileLayerTreeView : public QgsElevationProfileLayerTreeV
|
||||
void contextMenuEvent( QContextMenuEvent *event ) override;
|
||||
};
|
||||
|
||||
class QgsElevationProfileLayersDialog: public QDialog, private Ui::QgsElevationProfileAddLayersDialogBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsElevationProfileLayersDialog( QWidget *parent = nullptr );
|
||||
void setVisibleLayers( const QList<QgsMapLayer *> &layers );
|
||||
void setHiddenLayers( const QList<QgsMapLayer *> &layers );
|
||||
QList< QgsMapLayer * > selectedLayers() const;
|
||||
|
||||
private slots:
|
||||
|
||||
void filterVisible( bool enabled );
|
||||
|
||||
private:
|
||||
|
||||
QgsMapLayerProxyModel *mModel = nullptr;
|
||||
QList< QgsMapLayer * > mVisibleLayers;
|
||||
};
|
||||
|
||||
class QgsElevationProfileWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -93,6 +115,7 @@ class QgsElevationProfileWidget : public QWidget
|
||||
void toggleDockModeRequested( bool docked );
|
||||
|
||||
private slots:
|
||||
void addLayers();
|
||||
void updateCanvasLayers();
|
||||
void onTotalPendingJobsCountChanged( int count );
|
||||
void setProfileCurve( const QgsGeometry &curve, bool resetView );
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "qgselevationutils.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsmaplayerelevationproperties.h"
|
||||
|
||||
#include "qgsrasterlayerelevationproperties.h"
|
||||
|
||||
QgsDoubleRange QgsElevationUtils::calculateZRangeForProject( QgsProject *project )
|
||||
{
|
||||
@ -54,3 +54,37 @@ QgsDoubleRange QgsElevationUtils::calculateZRangeForProject( QgsProject *project
|
||||
std::isnan( max ) ? std::numeric_limits< double >::max() : max );
|
||||
}
|
||||
|
||||
bool QgsElevationUtils::canEnableElevationForLayer( QgsMapLayer *layer )
|
||||
{
|
||||
return static_cast< bool >( layer->elevationProperties() );
|
||||
}
|
||||
|
||||
bool QgsElevationUtils::enableElevationForLayer( QgsMapLayer *layer )
|
||||
{
|
||||
switch ( layer->type() )
|
||||
{
|
||||
case Qgis::LayerType::Raster:
|
||||
{
|
||||
if ( QgsRasterLayerElevationProperties *properties = qobject_cast<QgsRasterLayerElevationProperties * >( layer->elevationProperties() ) )
|
||||
{
|
||||
properties->setEnabled( true );
|
||||
// This could potentially be made smarter, eg by checking the data type of bands. But that's likely overkill..!
|
||||
properties->setBandNumber( 1 );
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// can't automatically enable elevation for these layer types
|
||||
case Qgis::LayerType::Vector:
|
||||
case Qgis::LayerType::Plugin:
|
||||
case Qgis::LayerType::Mesh:
|
||||
case Qgis::LayerType::VectorTile:
|
||||
case Qgis::LayerType::Annotation:
|
||||
case Qgis::LayerType::PointCloud:
|
||||
case Qgis::LayerType::Group:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,22 @@ class CORE_EXPORT QgsElevationUtils
|
||||
*/
|
||||
static QgsDoubleRange calculateZRangeForProject( QgsProject *project );
|
||||
|
||||
/**
|
||||
* Returns TRUE if elevation can be enabled for a map \a layer.
|
||||
*
|
||||
* \since QGIS 3.32
|
||||
*/
|
||||
static bool canEnableElevationForLayer( QgsMapLayer *layer );
|
||||
|
||||
/**
|
||||
* Automatically enables elevation for a map \a layer, using reasonable defaults.
|
||||
*
|
||||
* Returns TRUE if the elevation was enabled successfully.
|
||||
*
|
||||
* \since QGIS 3.32
|
||||
*/
|
||||
static bool enableElevationForLayer( QgsMapLayer *layer );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -420,6 +420,11 @@ void QgsElevationProfileLayerTreeView::populateInitialLayers( QgsProject *projec
|
||||
}
|
||||
}
|
||||
|
||||
QgsElevationProfileLayerTreeProxyModel *QgsElevationProfileLayerTreeView::proxyModel()
|
||||
{
|
||||
return mProxyModel;
|
||||
}
|
||||
|
||||
void QgsElevationProfileLayerTreeView::resizeEvent( QResizeEvent *event )
|
||||
{
|
||||
header()->setMinimumSectionSize( viewport()->width() );
|
||||
|
@ -129,6 +129,13 @@ class GUI_EXPORT QgsElevationProfileLayerTreeView : public QTreeView
|
||||
*/
|
||||
void populateInitialLayers( QgsProject *project );
|
||||
|
||||
/**
|
||||
* Returns the view's proxy model.
|
||||
*
|
||||
* \since QGIS 3.32
|
||||
*/
|
||||
QgsElevationProfileLayerTreeProxyModel *proxyModel();
|
||||
|
||||
protected:
|
||||
|
||||
void resizeEvent( QResizeEvent *event ) override;
|
||||
|
102
src/ui/qgselevationprofileaddlayersdialogbase.ui
Normal file
102
src/ui/qgselevationprofileaddlayersdialogbase.ui
Normal file
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsElevationProfileAddLayersDialogBase</class>
|
||||
<widget class="QDialog" name="QgsElevationProfileAddLayersDialogBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>270</width>
|
||||
<height>194</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add Layers to Elevation Profile</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListView" name="listMapLayers">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QgsFilterLineEdit" name="mFilterLineEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="mCheckBoxVisibleLayers">
|
||||
<property name="toolTip">
|
||||
<string>If checked, only layers visible within the map will be listed</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show visible layers only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsFilterLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>qgsfilterlineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mFilterLineEdit</tabstop>
|
||||
<tabstop>listMapLayers</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>QgsElevationProfileAddLayersDialogBase</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>QgsElevationProfileAddLayersDialogBase</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
Loading…
x
Reference in New Issue
Block a user