Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Merge pull request #6057 from wonder-sk/layer-tree-filter-indicator
Layer tree view indicators API + filtered layer indicator
- Loading branch information
Showing
14 changed files
with
772 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/************************************************************************ | ||
* This file has been generated automatically from * | ||
* * | ||
* src/gui/layertree/qgslayertreeviewindicator.h * | ||
* * | ||
* Do not edit manually ! Edit header and run scripts/sipify.pl again * | ||
************************************************************************/ | ||
|
||
|
||
|
||
|
||
class QgsLayerTreeViewIndicator : QObject | ||
{ | ||
%Docstring | ||
Indicator that can be used in a layer tree view to display icons next to items of the layer tree. | ||
They add extra context to the item and interactivity (using clicked() signal). | ||
|
||
Indicators can be added/removed to individual layer tree items using :py:func:`QgsLayerTreeView.addIndicator()` | ||
and QgsLayerTreeView.removeIndicator() calls. | ||
|
||
.. versionadded:: 3.2 | ||
%End | ||
|
||
%TypeHeaderCode | ||
#include "qgslayertreeviewindicator.h" | ||
%End | ||
public: | ||
explicit QgsLayerTreeViewIndicator( QObject *parent /TransferThis/ = 0 ); | ||
%Docstring | ||
Constructs an indicator, optionally transferring ownership to a parent QObject | ||
%End | ||
|
||
QIcon icon() const; | ||
%Docstring | ||
Indicator icon that will be displayed in the layer tree view | ||
%End | ||
void setIcon( const QIcon &icon ); | ||
%Docstring | ||
Sets indicator icon that will be displayed in the layer tree view | ||
%End | ||
|
||
QString toolTip() const; | ||
%Docstring | ||
Returns tool tip text that will be shown when user hovers mouse over the indicator | ||
%End | ||
void setToolTip( const QString &tip ); | ||
%Docstring | ||
Sets tool tip text | ||
%End | ||
|
||
signals: | ||
void clicked( const QModelIndex &index ); | ||
%Docstring | ||
Signal that is emitted when user clicks on the indicator | ||
%End | ||
|
||
}; | ||
|
||
/************************************************************************ | ||
* This file has been generated automatically from * | ||
* * | ||
* src/gui/layertree/qgslayertreeviewindicator.h * | ||
* * | ||
* Do not edit manually ! Edit header and run scripts/sipify.pl again * | ||
************************************************************************/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/*************************************************************************** | ||
qgslayertreeviewfilterindicator.cpp | ||
-------------------------------------- | ||
Date : January 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 "qgslayertreeviewfilterindicator.h" | ||
|
||
#include "qgslayertree.h" | ||
#include "qgslayertreemodel.h" | ||
#include "qgslayertreeview.h" | ||
#include "qgsquerybuilder.h" | ||
#include "qgsvectorlayer.h" | ||
|
||
|
||
QgsLayerTreeViewFilterIndicatorProvider::QgsLayerTreeViewFilterIndicatorProvider( QgsLayerTreeView *view ) | ||
: QObject( view ) | ||
, mLayerTreeView( view ) | ||
{ | ||
mIcon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionFilter2.svg" ) ); | ||
|
||
QgsLayerTree *tree = mLayerTreeView->layerTreeModel()->rootGroup(); | ||
onAddedChildren( tree, 0, tree->children().count() - 1 ); | ||
|
||
connect( tree, &QgsLayerTree::addedChildren, this, &QgsLayerTreeViewFilterIndicatorProvider::onAddedChildren ); | ||
connect( tree, &QgsLayerTree::willRemoveChildren, this, &QgsLayerTreeViewFilterIndicatorProvider::onWillRemoveChildren ); | ||
} | ||
|
||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::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 ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( childLayerNode->layer() ) ) | ||
{ | ||
if ( vlayer->dataProvider() ) | ||
{ | ||
connect( vlayer->dataProvider(), &QgsDataProvider::dataChanged, this, &QgsLayerTreeViewFilterIndicatorProvider::onProviderDataChanged ); | ||
|
||
addOrRemoveIndicator( childLayerNode, vlayer->dataProvider() ); | ||
} | ||
} | ||
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, &QgsLayerTreeViewFilterIndicatorProvider::onLayerLoaded ); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::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 ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( childLayerNode->layer() ) ) | ||
{ | ||
if ( vlayer->dataProvider() ) | ||
disconnect( vlayer->dataProvider(), &QgsDataProvider::dataChanged, this, &QgsLayerTreeViewFilterIndicatorProvider::onProviderDataChanged ); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::onLayerLoaded() | ||
{ | ||
QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( sender() ); | ||
if ( !nodeLayer ) | ||
return; | ||
|
||
if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() ) ) | ||
{ | ||
if ( vlayer->dataProvider() ) | ||
{ | ||
connect( vlayer->dataProvider(), &QgsDataProvider::dataChanged, this, &QgsLayerTreeViewFilterIndicatorProvider::onProviderDataChanged ); | ||
|
||
addOrRemoveIndicator( nodeLayer, vlayer->dataProvider() ); | ||
} | ||
} | ||
} | ||
|
||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::onProviderDataChanged() | ||
{ | ||
QgsVectorDataProvider *provider = qobject_cast<QgsVectorDataProvider *>( sender() ); | ||
if ( !provider ) | ||
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()->dataProvider() == provider ) | ||
{ | ||
addOrRemoveIndicator( node, provider ); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::onIndicatorClicked( const QModelIndex &index ) | ||
{ | ||
QgsLayerTreeNode *node = mLayerTreeView->layerTreeModel()->index2node( index ); | ||
if ( !QgsLayerTree::isLayer( node ) ) | ||
return; | ||
|
||
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( QgsLayerTree::toLayer( node )->layer() ); | ||
if ( !vlayer || !vlayer->dataProvider() ) | ||
return; | ||
|
||
// launch the query builder | ||
QgsQueryBuilder qb( vlayer ); | ||
qb.setSql( vlayer->dataProvider()->subsetString() ); | ||
if ( qb.exec() ) | ||
vlayer->dataProvider()->setSubsetString( qb.sql() ); | ||
} | ||
|
||
QgsLayerTreeViewIndicator *QgsLayerTreeViewFilterIndicatorProvider::newIndicator( const QString &filter ) | ||
{ | ||
QgsLayerTreeViewIndicator *indicator = new QgsLayerTreeViewIndicator( this ); | ||
indicator->setIcon( mIcon ); | ||
updateIndicator( indicator, filter ); | ||
connect( indicator, &QgsLayerTreeViewIndicator::clicked, this, &QgsLayerTreeViewFilterIndicatorProvider::onIndicatorClicked ); | ||
mIndicators.insert( indicator ); | ||
return indicator; | ||
} | ||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::updateIndicator( QgsLayerTreeViewIndicator *indicator, const QString &filter ) | ||
{ | ||
indicator->setToolTip( QString( "<b>%1:</b><br>%2" ).arg( tr( "Filter" ) ).arg( filter ) ); | ||
} | ||
|
||
|
||
void QgsLayerTreeViewFilterIndicatorProvider::addOrRemoveIndicator( QgsLayerTreeNode *node, QgsVectorDataProvider *provider ) | ||
{ | ||
QString filter = provider->subsetString(); | ||
if ( !filter.isEmpty() ) | ||
{ | ||
const QList<QgsLayerTreeViewIndicator *> nodeIndicators = mLayerTreeView->indicators( node ); | ||
|
||
// maybe the indicator exists already | ||
foreach ( QgsLayerTreeViewIndicator *indicator, nodeIndicators ) | ||
{ | ||
if ( mIndicators.contains( indicator ) ) | ||
{ | ||
updateIndicator( indicator, filter ); | ||
return; | ||
} | ||
} | ||
|
||
// it does not exist: need to create a new one | ||
mLayerTreeView->addIndicator( node, newIndicator( filter ) ); | ||
} | ||
else | ||
{ | ||
const QList<QgsLayerTreeViewIndicator *> nodeIndicators = mLayerTreeView->indicators( node ); | ||
|
||
// there may be existing indicator we need to get rid of | ||
foreach ( QgsLayerTreeViewIndicator *indicator, nodeIndicators ) | ||
{ | ||
if ( mIndicators.contains( indicator ) ) | ||
{ | ||
mLayerTreeView->removeIndicator( node, indicator ); | ||
indicator->deleteLater(); | ||
return; | ||
} | ||
} | ||
|
||
// no indicator was there before, nothing to do | ||
} | ||
} |
Oops, something went wrong.