Skip to content

Commit

Permalink
[FEATURE] Layer tree indicators for memory layers
Browse files Browse the repository at this point in the history
Shows a memory layer icon in the layer tree for all memory
layers, with a tooltip warning that the contents of the layer
will be lost when closing the project.

Should help avoid data loss by users who don't realise that
certain layers are temporary only.
  • Loading branch information
nyalldawson committed Aug 6, 2018
1 parent f3235f7 commit a953587
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/app/CMakeLists.txt
Expand Up @@ -56,6 +56,7 @@ SET(QGIS_APP_SRCS
qgslabelingwidget.cpp
qgslayertreeviewembeddedindicator.cpp
qgslayertreeviewfilterindicator.cpp
qgslayertreeviewmemoryindicator.cpp
qgsloadstylefromdbdialog.cpp
qgsmapcanvasdockwidget.cpp
qgsmaplayerstyleguiutils.cpp
Expand Down Expand Up @@ -275,6 +276,7 @@ SET (QGIS_APP_MOC_HDRS
qgslabelingwidget.h
qgslabelpropertydialog.h
qgslayertreeviewembeddedindicator.h
qgslayertreeviewmemoryindicator.h
qgslayertreeviewfilterindicator.h
qgsloadstylefromdbdialog.h
qgsmapcanvasdockwidget.h
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -206,6 +206,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgslayertreeviewdefaultactions.h"
#include "qgslayertreeviewembeddedindicator.h"
#include "qgslayertreeviewfilterindicator.h"
#include "qgslayertreeviewmemoryindicator.h"
#include "qgslayout.h"
#include "qgslayoutatlas.h"
#include "qgslayoutcustomdrophandler.h"
Expand Down Expand Up @@ -3803,6 +3804,7 @@ void QgisApp::initLayerTreeView()
mLayerTreeView->setMenuProvider( new QgsAppLayerTreeViewMenuProvider( mLayerTreeView, mMapCanvas ) );
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

setupLayerTreeViewFromSettings();

Expand Down
95 changes: 95 additions & 0 deletions src/app/qgslayertreeviewmemoryindicator.cpp
@@ -0,0 +1,95 @@
/***************************************************************************
qgslayertreeviewmemoryindicator.h
--------------------------------------
Date : July 2018
Copyright : (C) 2018 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 "qgslayertreeviewmemoryindicator.h"
#include "qgslayertree.h"
#include "qgslayertreemodel.h"
#include "qgslayertreeview.h"

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

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

connect( tree, &QgsLayerTree::addedChildren, this, &QgsLayerTreeViewMemoryIndicatorProvider::onAddedChildren );
}

void QgsLayerTreeViewMemoryIndicatorProvider::onAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo )
{
// recursively populate indicators
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 ) )
{
if ( QgsLayerTreeLayer *layerNode = dynamic_cast< QgsLayerTreeLayer * >( childNode ) )
{
if ( layerNode->layer() && layerNode->layer()->dataProvider()->name() == QLatin1String( "memory" ) )
addIndicatorForMemoryLayer( childNode );
else if ( !layerNode->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( layerNode, &QgsLayerTreeLayer::layerLoaded, this, &QgsLayerTreeViewMemoryIndicatorProvider::onLayerLoaded );
}
}
}
}
}

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

if ( layerNode->layer() && layerNode->layer()->dataProvider()->name() == QLatin1String( "memory" ) )
addIndicatorForMemoryLayer( layerNode );
}

std::unique_ptr< QgsLayerTreeViewIndicator > QgsLayerTreeViewMemoryIndicatorProvider::newIndicator()
{
std::unique_ptr< QgsLayerTreeViewIndicator > indicator = qgis::make_unique< QgsLayerTreeViewIndicator >( this );
indicator->setIcon( mIcon );
indicator->setToolTip( tr( "Temporary scratch layer only<br><b>Contents will be discarded after closing this project</b>" ) );
mIndicators.insert( indicator.get() );
return indicator;
}

void QgsLayerTreeViewMemoryIndicatorProvider::addIndicatorForMemoryLayer( QgsLayerTreeNode *node )
{
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() );
}
49 changes: 49 additions & 0 deletions src/app/qgslayertreeviewmemoryindicator.h
@@ -0,0 +1,49 @@
/***************************************************************************
qgslayertreeviewmemoryindicator.h
--------------------------------------
Date : July 2018
Copyright : (C) 2018 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 QGSLAYERTREEVIEWMEMORYINDICATOR_H
#define QGSLAYERTREEVIEWMEMORYINDICATOR_H

#include "qgslayertreeviewindicator.h"

#include <QSet>
#include <memory>

class QgsLayerTreeNode;
class QgsLayerTreeView;

//! Adds indicators showing whether layers are memory layers.
class QgsLayerTreeViewMemoryIndicatorProvider : public QObject
{
Q_OBJECT
public:
explicit QgsLayerTreeViewMemoryIndicatorProvider( QgsLayerTreeView *view );

private slots:
//! Connects to signals of layers newly added to the tree
void onAddedChildren( QgsLayerTreeNode *node, int indexFrom, int indexTo );
void onLayerLoaded();

private:
std::unique_ptr< QgsLayerTreeViewIndicator > newIndicator();
void addIndicatorForMemoryLayer( QgsLayerTreeNode *node );

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

#endif // QGSLAYERTREEVIEWMEMORYINDICATOR_H

0 comments on commit a953587

Please sign in to comment.