Skip to content

Commit

Permalink
[FEATURE] Layer tree view indicator for non-removable (required) layers
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Sep 11, 2018
1 parent 602b3e9 commit b8197ed
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -58,6 +58,7 @@ SET(QGIS_APP_SRCS
qgslayertreeviewembeddedindicator.cpp
qgslayertreeviewfilterindicator.cpp
qgslayertreeviewmemoryindicator.cpp
qgslayertreeviewnonremovableindicator.cpp
qgsloadstylefromdbdialog.cpp
qgsmapcanvasdockwidget.cpp
qgsmaplayerstyleguiutils.cpp
Expand Down Expand Up @@ -281,6 +282,7 @@ SET (QGIS_APP_MOC_HDRS
qgslayertreeviewembeddedindicator.h
qgslayertreeviewmemoryindicator.h
qgslayertreeviewfilterindicator.h
qgslayertreeviewnonremovableindicator.h
qgsloadstylefromdbdialog.h
qgsmapcanvasdockwidget.h
qgsmaplayerstyleguiutils.h
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -204,6 +204,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgslayertreeviewembeddedindicator.h"
#include "qgslayertreeviewfilterindicator.h"
#include "qgslayertreeviewmemoryindicator.h"
#include "qgslayertreeviewnonremovableindicator.h"
#include "qgslayout.h"
#include "qgslayoutatlas.h"
#include "qgslayoutcustomdrophandler.h"
Expand Down Expand Up @@ -3873,6 +3874,7 @@ void QgisApp::initLayerTreeView()
new QgsLayerTreeViewFilterIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
new QgsLayerTreeViewEmbeddedIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
new QgsLayerTreeViewMemoryIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
new QgsLayerTreeViewNonRemovableIndicatorProvider( mLayerTreeView ); // gets parented to the layer view

setupLayerTreeViewFromSettings();

Expand Down
165 changes: 165 additions & 0 deletions src/app/qgslayertreeviewnonremovableindicator.cpp
@@ -0,0 +1,165 @@
/***************************************************************************
qgslayertreeviewnonremovableindicator.cpp
--------------------------------------
Date : Sep 2018
Copyright : (C) 2018 by Martin Dobias
Email : wonder dot sk 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 "qgslayertreeviewnonremovableindicator.h"

#include "qgslayertree.h"
#include "qgslayertreemodel.h"
#include "qgslayertreeview.h"


QgsLayerTreeViewNonRemovableIndicatorProvider::QgsLayerTreeViewNonRemovableIndicatorProvider( QgsLayerTreeView *view )
: QObject( view )
, mLayerTreeView( view )
{
mIcon = QgsApplication::getThemeIcon( QStringLiteral( "/lockedGray.svg" ) );

QgsLayerTree *tree = mLayerTreeView->layerTreeModel()->rootGroup();
onAddedChildren( tree, 0, tree->children().count() - 1 );

connect( tree, &QgsLayerTree::addedChildren, this, &QgsLayerTreeViewNonRemovableIndicatorProvider::onAddedChildren );
connect( tree, &QgsLayerTree::willRemoveChildren, this, &QgsLayerTreeViewNonRemovableIndicatorProvider::onWillRemoveChildren );
}

void QgsLayerTreeViewNonRemovableIndicatorProvider::onAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
{
// recursively connect to providers' dataChanged() signal

QList<QgsLayerTreeNode *> children = node->children();
for ( int i = indexFrom; i <= indexTo; ++i )
{
QgsLayerTreeNode *childNode = children[i];

if ( QgsLayerTree::isGroup( childNode ) )
{
onAddedChildren( childNode, 0, childNode->children().count() - 1 );
}
else if ( QgsLayerTree::isLayer( childNode ) )
{
QgsLayerTreeLayer *childLayerNode = QgsLayerTree::toLayer( childNode );
if ( QgsMapLayer *layer = childLayerNode->layer() )
{
connect( layer, &QgsMapLayer::flagsChanged, this, &QgsLayerTreeViewNonRemovableIndicatorProvider::onFlagsChanged );
addOrRemoveIndicator( childLayerNode, layer );
}
else if ( !childLayerNode->layer() )
{
// wait for layer to be loaded (e.g. when loading project, first the tree is loaded, afterwards the references to layers are resolved)
connect( childLayerNode, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeViewNonRemovableIndicatorProvider::onLayerLoaded );
}
}
}
}


void QgsLayerTreeViewNonRemovableIndicatorProvider::onWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
{
// recursively disconnect from providers' dataChanged() signal

QList<QgsLayerTreeNode *> children = node->children();
for ( int i = indexFrom; i <= indexTo; ++i )
{
QgsLayerTreeNode *childNode = children[i];

if ( QgsLayerTree::isGroup( childNode ) )
{
onWillRemoveChildren( childNode, 0, childNode->children().count() - 1 );
}
else if ( QgsLayerTree::isLayer( childNode ) )
{
QgsLayerTreeLayer *childLayerNode = QgsLayerTree::toLayer( childNode );
if ( childLayerNode->layer() )
disconnect( childLayerNode->layer(), &QgsMapLayer::flagsChanged, this, &QgsLayerTreeViewNonRemovableIndicatorProvider::onFlagsChanged );
}
}
}


void QgsLayerTreeViewNonRemovableIndicatorProvider::onLayerLoaded()
{
QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( sender() );
if ( !nodeLayer )
return;

if ( QgsMapLayer *layer = nodeLayer->layer() )
{
connect( layer, &QgsMapLayer::flagsChanged, this, &QgsLayerTreeViewNonRemovableIndicatorProvider::onFlagsChanged );
addOrRemoveIndicator( nodeLayer, layer );
}
}

void QgsLayerTreeViewNonRemovableIndicatorProvider::onFlagsChanged()
{
QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
if ( !layer )
return;

// walk the tree and find layer node that needs to be updated
const QList<QgsLayerTreeLayer *> layerNodes = mLayerTreeView->layerTreeModel()->rootGroup()->findLayers();
for ( QgsLayerTreeLayer *node : layerNodes )
{
if ( node->layer() && node->layer() == layer )
{
addOrRemoveIndicator( node, layer );
break;
}
}
}


std::unique_ptr<QgsLayerTreeViewIndicator> QgsLayerTreeViewNonRemovableIndicatorProvider::newIndicator()
{
std::unique_ptr< QgsLayerTreeViewIndicator > indicator = qgis::make_unique< QgsLayerTreeViewIndicator >( this );
indicator->setIcon( mIcon );
indicator->setToolTip( tr( "Layer required by the project" ) );
mIndicators.insert( indicator.get() );
return indicator;
}

void QgsLayerTreeViewNonRemovableIndicatorProvider::addOrRemoveIndicator( QgsLayerTreeNode *node, QgsMapLayer *layer )
{
bool removable = layer->flags() & QgsMapLayer::Removable;
if ( !removable )
{
const QList<QgsLayerTreeViewIndicator *> nodeIndicators = mLayerTreeView->indicators( node );

// maybe the indicator exists already
for ( QgsLayerTreeViewIndicator *indicator : nodeIndicators )
{
if ( mIndicators.contains( indicator ) )
return;
}

// it does not exist: need to create a new one
mLayerTreeView->addIndicator( node, newIndicator().release() );
}
else
{
const QList<QgsLayerTreeViewIndicator *> nodeIndicators = mLayerTreeView->indicators( node );

// there may be existing indicator we need to get rid of
for ( QgsLayerTreeViewIndicator *indicator : nodeIndicators )
{
if ( mIndicators.contains( indicator ) )
{
mLayerTreeView->removeIndicator( node, indicator );
indicator->deleteLater();
return;
}
}

// no indicator was there before, nothing to do
}
}
54 changes: 54 additions & 0 deletions src/app/qgslayertreeviewnonremovableindicator.h
@@ -0,0 +1,54 @@
/***************************************************************************
qgslayertreeviewnonremovableindicator.h
--------------------------------------
Date : Sep 2018
Copyright : (C) 2018 by Martin Dobias
Email : wonder dot sk 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 QGSLAYERTREEVIEWNONREMOVABLEINDICATOR_H
#define QGSLAYERTREEVIEWNONREMOVABLEINDICATOR_H

#include "qgslayertreeviewindicator.h"

#include <QSet>
#include <memory>

class QgsLayerTreeNode;
class QgsLayerTreeView;
class QgsMapLayer;

class QgsLayerTreeViewNonRemovableIndicatorProvider : public QObject
{
Q_OBJECT
public:
explicit QgsLayerTreeViewNonRemovableIndicatorProvider( QgsLayerTreeView *view );

private slots:
//! Connects to signals of layers newly added to the tree
void onAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo );
//! Disconnects from layers about to be removed from the tree
void onWillRemoveChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo );
//! Starts listening to layer provider's dataChanged signal
void onLayerLoaded();
void onFlagsChanged();

private:
std::unique_ptr< QgsLayerTreeViewIndicator > newIndicator();
void addOrRemoveIndicator( QgsLayerTreeNode *node, QgsMapLayer *layer );

private:
QgsLayerTreeView *mLayerTreeView = nullptr;
QIcon mIcon;
QSet<QgsLayerTreeViewIndicator *> mIndicators;
};


#endif // QGSLAYERTREEVIEWNONREMOVABLEINDICATOR_H

0 comments on commit b8197ed

Please sign in to comment.