Skip to content
Permalink
Browse files

Merge pull request #39577 from elpaso/hidden-layers

Hidden layers
  • Loading branch information
elpaso committed Nov 5, 2020
2 parents e1f1af7 + 26a9cdf commit 3e398e2ab4e4ce8d64ab199353e16071b574c2ff
@@ -351,6 +351,13 @@ Updates model when node's name has changed
void nodeLayerWillBeUnloaded();
void layerLegendChanged();

void layerFlagsChanged();
%Docstring
Emitted when layer flags have changed.

.. versionadded:: 3.18
%End

void layerNeedsUpdate();

void legendNodeDataChanged();
@@ -84,6 +84,7 @@ This is the base class for all map layer types (vector, raster).
Identifiable,
Removable,
Searchable,
Private,
};
typedef QFlags<QgsMapLayer::LayerFlag> LayerFlags;

@@ -10,6 +10,50 @@




class QgsLayerTreeProxyModel : QSortFilterProxyModel
{
%Docstring

The QgsLayerTreeProxyModel class is a proxy model for QgsLayerTreeModel, supports
private layers and text filtering.

.. versionadded:: 3.18
%End

%TypeHeaderCode
#include "qgslayertreeview.h"
%End
public:

QgsLayerTreeProxyModel( QgsLayerTreeModel *treeModel, QObject *parent );
%Docstring
Constructs QgsLayerTreeProxyModel with source model ``treeModel`` and a ``parent``
%End

void setFilterText( const QString &filterText = QString() );
%Docstring
Sets filter to ``filterText``.
%End

bool showPrivateLayers() const;
%Docstring
Returns if private layers are shown.
%End

void setShowPrivateLayers( bool showPrivate );
%Docstring
Determines if private layers are shown.
%End

protected:

virtual bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const;


};


class QgsLayerTreeView : QTreeView
{
%Docstring
@@ -55,6 +99,74 @@ Overridden :py:func:`~QgsLayerTreeView.setModel` from base class. Only QgsLayerT
QgsLayerTreeModel *layerTreeModel() const;
%Docstring
Gets access to the model casted to :py:class:`QgsLayerTreeModel`
%End

QgsLayerTreeProxyModel *proxyModel() const;
%Docstring
Returns the proxy model used by the view.

This can be used to set filters controlling which layers are shown in the view.

.. versionadded:: 3.18
%End

QgsLayerTreeNode *index2node( const QModelIndex &index ) const;
%Docstring
Returns layer tree node for given proxy model tree ``index``. Returns root node for invalid index.
Returns ``None`` if index does not refer to a layer tree node (e.g. it is a legend node)

Unlike :py:func:`QgsLayerTreeModel.index2Node()`, calling this method correctly accounts
for mapping the view indexes through the view's proxy model to the source model.

.. versionadded:: 3.18
%End

QModelIndex node2index( QgsLayerTreeNode *node ) const;
%Docstring
Returns proxy model index for a given node. If the node does not belong to the layer tree, the result is undefined

Unlike :py:func:`QgsLayerTreeModel.node2index()`, calling this method correctly accounts
for mapping the view indexes through the view's proxy model to the source model.

.. versionadded:: 3.18
%End


QModelIndex node2sourceIndex( QgsLayerTreeNode *node ) const;
%Docstring
Returns source model index for a given node. If the node does not belong to the layer tree, the result is undefined

.. versionadded:: 3.18
%End


QgsLayerTreeModelLegendNode *index2legendNode( const QModelIndex &index ) const;
%Docstring
Returns legend node for given proxy model tree ``index``. Returns ``None`` for invalid index

Unlike :py:func:`QgsLayerTreeModel.index2legendNode()`, calling this method correctly accounts
for mapping the view indexes through the view's proxy model to the source model.

.. versionadded:: 3.18
%End

QModelIndex legendNode2index( QgsLayerTreeModelLegendNode *legendNode );
%Docstring
Returns proxy model index for a given legend node. If the legend node does not belong to the layer tree, the result is undefined.
If the legend node is belongs to the tree but it is filtered out, invalid model index is returned.

Unlike :py:func:`QgsLayerTreeModel.legendNode2index()`, calling this method correctly accounts
for mapping the view indexes through the view's proxy model to the source model.

.. versionadded:: 3.18
%End

QModelIndex legendNode2sourceIndex( QgsLayerTreeModelLegendNode *legendNode );
%Docstring
Returns index for a given legend node. If the legend node does not belong to the layer tree, the result is undefined.
If the legend node is belongs to the tree but it is filtered out, invalid model index is returned.

.. versionadded:: 3.18
%End

QgsLayerTreeViewDefaultActions *defaultActions();
@@ -219,6 +331,20 @@ Set width of contextual menu mark, at right of layer node items.
Set the message bar to display messages from the layer tree

.. versionadded:: 3.14
%End

void setShowPrivateLayers( bool showPrivate );
%Docstring
Set the show private layers to ``showPrivate``

.. versionadded:: 3.18
%End

bool showPrivateLayers( );
%Docstring
Returns the show private layers status

.. versionadded:: 3.18
%End

signals:
@@ -4772,12 +4772,23 @@ void QgisApp::initLayerTreeView()
btnVisibilityPresets->setPopupMode( QToolButton::InstantPopup );
btnVisibilityPresets->setMenu( QgsMapThemes::instance()->menu() );

// filter legend action
mActionFilterLegend = new QAction( tr( "Filter Legend by Map Content" ), this );
mActionFilterLegend->setCheckable( true );
mActionFilterLegend->setToolTip( tr( "Filter Legend by Map Content" ) );
mActionFilterLegend->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFilter2.svg" ) ) );
connect( mActionFilterLegend, &QAction::toggled, this, &QgisApp::updateFilterLegend );
// filter legend actions
mFilterLegendToolButton = new QToolButton( this );
mFilterLegendToolButton->setAutoRaise( true );
mFilterLegendToolButton->setToolTip( tr( "Filter Legend by Map Content" ) );
mFilterLegendToolButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFilter2.svg" ) ) );
mFilterLegendToolButton->setPopupMode( QToolButton::InstantPopup );
QMenu *filterLegendMenu = new QMenu( this );
mFilterLegendToolButton->setMenu( filterLegendMenu );
mFilterLegendByMapContentAction = new QAction( tr( "Filter Legend by Map Content" ), this );
mFilterLegendByMapContentAction->setCheckable( true );
connect( mFilterLegendByMapContentAction, &QAction::toggled, this, &QgisApp::updateFilterLegend );
filterLegendMenu->addAction( mFilterLegendByMapContentAction );

mFilterLegendToggleShowPrivateLayersAction = new QAction( tr( "Show Private Layers" ), this );
mFilterLegendToggleShowPrivateLayersAction->setCheckable( true );
connect( mFilterLegendToggleShowPrivateLayersAction, &QAction::toggled, this, [ = ]( bool showPrivateLayers ) { layerTreeView()->setShowPrivateLayers( showPrivateLayers ); } );
filterLegendMenu->addAction( mFilterLegendToggleShowPrivateLayersAction );

mLegendExpressionFilterButton = new QgsLegendFilterButton( this );
mLegendExpressionFilterButton->setToolTip( tr( "Filter legend by expression" ) );
@@ -4805,7 +4816,7 @@ void QgisApp::initLayerTreeView()
toolbar->addAction( mActionStyleDock );
toolbar->addAction( actionAddGroup );
toolbar->addWidget( btnVisibilityPresets );
toolbar->addAction( mActionFilterLegend );
toolbar->addWidget( mFilterLegendToolButton );
toolbar->addWidget( mLegendExpressionFilterButton );
toolbar->addAction( actionExpandAll );
toolbar->addAction( actionCollapseAll );
@@ -4916,7 +4927,7 @@ void QgisApp::autoSelectAddedLayer( QList<QgsMapLayer *> layers )
if ( !nodeLayer )
return;

QModelIndex index = mLayerTreeView->layerTreeModel()->node2index( nodeLayer );
QModelIndex index = mLayerTreeView->node2index( nodeLayer );
mLayerTreeView->setCurrentIndex( index );
}
}
@@ -7115,7 +7126,7 @@ bool QgisApp::addProject( const QString &projectFile )
mMapCanvas->updateScale();
QgsDebugMsgLevel( QStringLiteral( "Scale restored..." ), 3 );

mActionFilterLegend->setChecked( QgsProject::instance()->readBoolEntry( QStringLiteral( "Legend" ), QStringLiteral( "filterByMap" ) ) );
mFilterLegendByMapContentAction->setChecked( QgsProject::instance()->readBoolEntry( QStringLiteral( "Legend" ), QStringLiteral( "filterByMap" ) ) );

// Select the first layer
if ( mLayerTreeView->layerTreeModel()->rootGroup()->findLayers().count() > 0 )
@@ -7740,10 +7751,10 @@ void QgisApp::toggleFilterLegendByExpression( bool checked )
void QgisApp::updateFilterLegend()
{
bool hasExpressions = mLegendExpressionFilterButton->isChecked() && QgsLayerTreeUtils::hasLegendFilterExpression( *mLayerTreeView->layerTreeModel()->rootGroup() );
if ( mActionFilterLegend->isChecked() || hasExpressions )
if ( mFilterLegendByMapContentAction->isChecked() || hasExpressions )
{
layerTreeView()->layerTreeModel()->setLegendFilter( &mMapCanvas->mapSettings(),
/* useExtent */ mActionFilterLegend->isChecked(),
/* useExtent */ mFilterLegendByMapContentAction->isChecked(),
/* polygon */ QgsGeometry(),
hasExpressions );
}
@@ -11647,8 +11658,43 @@ void QgisApp::removeLayer()
}

bool shiftHeld = QApplication::queryKeyboardModifiers().testFlag( Qt::ShiftModifier );
//display a warning
if ( !shiftHeld && promptConfirmation && QMessageBox::warning( this, tr( "Remove layers and groups" ), tr( "Remove %n legend entries?", "number of legend items to remove", selectedNodes.count() ), QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )

// Check if there are any hidden layer elements and display a confirmation dialog
QStringList hiddenLayerNames;
auto harvest = [ &hiddenLayerNames ]( const QgsLayerTreeNode * parent )
{
const auto cChildren { parent->children() };
for ( const auto &c : cChildren )
{
if ( QgsLayerTree::isLayer( c ) )
{
const auto treeLayer { QgsLayerTree::toLayer( c ) };
if ( treeLayer->layer() && treeLayer->layer()->flags().testFlag( QgsMapLayer::LayerFlag::Private ) )
{
hiddenLayerNames.push_back( treeLayer->layer()->name( ) );
}
}
}
};

for ( const auto &n : qgis::as_const( selectedNodes ) )
{
harvest( n );
}

QString message { tr( "Remove %n legend entries?", "number of legend items to remove", selectedNodes.count() ) };
if ( ! hiddenLayerNames.isEmpty() )
{
if ( hiddenLayerNames.count( ) > 10 )
{
const int layerCount { hiddenLayerNames.count( ) };
hiddenLayerNames = hiddenLayerNames.mid( 0, 10 );
hiddenLayerNames.push_back( tr( "(%n more hidden layers)", "number of hidden layers not shown", layerCount - 10 ) );
}
message.append( tr( "The following hidden layers will be removed:\n%1" ).arg( hiddenLayerNames.join( '\n' ) ) );
}

if ( !shiftHeld && promptConfirmation && QMessageBox::warning( this, tr( "Remove layers and groups" ), message, QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
{
return;
}
@@ -13439,7 +13485,7 @@ void QgisApp::closeProject()

mLegendExpressionFilterButton->setExpressionText( QString() );
mLegendExpressionFilterButton->setChecked( false );
mActionFilterLegend->setChecked( false );
mFilterLegendByMapContentAction->setChecked( false );

closeAdditionalMapCanvases();
closeAdditional3DMapCanvases();
@@ -2622,7 +2622,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! A class that facilitates tracing of features
QgsMapCanvasTracer *mTracer = nullptr;

QAction *mActionFilterLegend = nullptr;
QToolButton *mFilterLegendToolButton = nullptr;
QAction *mFilterLegendByMapContentAction = nullptr;
QAction *mFilterLegendToggleShowPrivateLayersAction = nullptr;
QAction *mActionStyleDock = nullptr;

QgsLegendFilterButton *mLegendExpressionFilterButton = nullptr;
@@ -75,7 +75,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()

// TODO: update drawing order
}
else if ( QgsLayerTreeNode *node = mView->layerTreeModel()->index2node( idx ) )
else if ( QgsLayerTreeNode *node = mView->index2node( idx ) )
{
// layer or group selected
if ( QgsLayerTree::isGroup( node ) )
@@ -616,7 +616,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
menu->addAction( tr( "&Properties…" ), QgisApp::instance(), &QgisApp::layerProperties );
}
}
else if ( QgsLayerTreeModelLegendNode *node = mView->layerTreeModel()->index2legendNode( idx ) )
else if ( QgsLayerTreeModelLegendNode *node = mView->index2legendNode( idx ) )
{
if ( QgsSymbolLegendNode *symbolNode = qobject_cast< QgsSymbolLegendNode * >( node ) )
{

0 comments on commit 3e398e2

Please sign in to comment.
You can’t perform that action at this time.