mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] Indicators for layer tree view + filter indicator implementation
This adds a mini-framework for display of extra icons in layer tree views next to layer and group names. Tool tip text can be associated with indicators to give extra context for indicators. In addition, a signal gets emitted when user clicks indicators and custom actions can be defined. The main window's layer tree view (ToC) gets support for indicators that are shown when a vector layer has a filter applied. This makes it easier for users to understand that they are looking at a subset of all data. Clicking the indicator's icon brings up query builder.
This commit is contained in:
parent
68ee969b30
commit
f56d70f3f8
@ -287,6 +287,7 @@
|
||||
%Include layertree/qgslayertreemapcanvasbridge.sip
|
||||
%Include layertree/qgslayertreeview.sip
|
||||
%Include layertree/qgslayertreeviewdefaultactions.sip
|
||||
%Include layertree/qgslayertreeviewindicator.sip
|
||||
%Include layout/qgslayoutcustomdrophandler.sip
|
||||
%Include layout/qgslayoutdesignerinterface.sip
|
||||
%Include layout/qgslayoutitemcombobox.sip
|
||||
|
@ -109,6 +109,37 @@ Return list of selected nodes filtered to just layer nodes
|
||||
QList<QgsMapLayer *> selectedLayers() const;
|
||||
%Docstring
|
||||
Get list of selected layers
|
||||
%End
|
||||
|
||||
void addIndicator( QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator );
|
||||
%Docstring
|
||||
Adds an indicator to the given layer tree node. Indicators are icons shown next to layer/group names
|
||||
in the layer tree view. They can be used to show extra information with tree nodes and they allow
|
||||
user interaction.
|
||||
|
||||
Does not take ownership of the indicator. One indicator object may be used for multiple layer tree nodes.
|
||||
\sa removeIndicator
|
||||
\sa indicators
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
void removeIndicator( QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator );
|
||||
%Docstring
|
||||
Removes a previously added indicator to a layer tree node. Does not delete the indicator.
|
||||
\sa addIndicator
|
||||
\sa indicators
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
QList<QgsLayerTreeViewIndicator *> indicators( QgsLayerTreeNode *node ) const;
|
||||
%Docstring
|
||||
Returns list of indicators associated with a particular layer tree node.
|
||||
\sa addIndicator
|
||||
\sa removeIndicator
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
public slots:
|
||||
@ -153,7 +184,6 @@ Emitted when a current layer is changed
|
||||
virtual void dropEvent( QDropEvent *event );
|
||||
|
||||
|
||||
|
||||
protected slots:
|
||||
|
||||
void modelRowsInserted( const QModelIndex &index, int start, int end );
|
||||
@ -166,6 +196,7 @@ Emitted when a current layer is changed
|
||||
void onModelReset();
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
62
python/gui/layertree/qgslayertreeviewindicator.sip
Normal file
62
python/gui/layertree/qgslayertreeviewindicator.sip
Normal file
@ -0,0 +1,62 @@
|
||||
/************************************************************************
|
||||
* 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 );
|
||||
|
||||
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 *
|
||||
************************************************************************/
|
@ -52,6 +52,7 @@ SET(QGIS_APP_SRCS
|
||||
qgslabelengineconfigdialog.cpp
|
||||
qgslabelinggui.cpp
|
||||
qgslabelingwidget.cpp
|
||||
qgslayertreeviewfilterindicator.cpp
|
||||
qgsloadstylefromdbdialog.cpp
|
||||
qgsmapcanvasdockwidget.cpp
|
||||
qgsmaplayerstyleguiutils.cpp
|
||||
@ -263,6 +264,7 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgslabelinggui.h
|
||||
qgslabelingwidget.h
|
||||
qgslabelpropertydialog.h
|
||||
qgslayertreeviewfilterindicator.h
|
||||
qgsloadstylefromdbdialog.h
|
||||
qgsmapcanvasdockwidget.h
|
||||
qgsmaplayerstyleguiutils.h
|
||||
|
@ -201,6 +201,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
|
||||
#include "qgslayertreeutils.h"
|
||||
#include "qgslayertreeview.h"
|
||||
#include "qgslayertreeviewdefaultactions.h"
|
||||
#include "qgslayertreeviewfilterindicator.h"
|
||||
#include "qgslayout.h"
|
||||
#include "qgslayoutatlas.h"
|
||||
#include "qgslayoutcustomdrophandler.h"
|
||||
@ -3623,7 +3624,6 @@ void QgisApp::addUserInputWidget( QWidget *widget )
|
||||
mUserInputDockWidget->addUserInputWidget( widget );
|
||||
}
|
||||
|
||||
|
||||
void QgisApp::initLayerTreeView()
|
||||
{
|
||||
mLayerTreeView->setWhatsThis( tr( "Map legend that displays all the layers currently on the map canvas. Click on the checkbox to turn a layer on or off. Double-click on a layer in the legend to customize its appearance and set other properties." ) );
|
||||
@ -3646,6 +3646,7 @@ void QgisApp::initLayerTreeView()
|
||||
|
||||
mLayerTreeView->setModel( model );
|
||||
mLayerTreeView->setMenuProvider( new QgsAppLayerTreeViewMenuProvider( mLayerTreeView, mMapCanvas ) );
|
||||
new QgsLayerTreeViewFilterIndicatorManager( mLayerTreeView ); // gets parented to the layer view
|
||||
|
||||
setupLayerTreeViewFromSettings();
|
||||
|
||||
|
165
src/app/qgslayertreeviewfilterindicator.cpp
Normal file
165
src/app/qgslayertreeviewfilterindicator.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/***************************************************************************
|
||||
qgslayertreeviewfilterindicator.cpp
|
||||
--------------------------------------
|
||||
Date : Januray 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"
|
||||
|
||||
|
||||
QgsLayerTreeViewFilterIndicatorManager::QgsLayerTreeViewFilterIndicatorManager( QgsLayerTreeView *view )
|
||||
: QObject( view )
|
||||
, mLayerTreeView( view )
|
||||
{
|
||||
mIndicator = new QgsLayerTreeViewIndicator( this );
|
||||
mIndicator->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFilter2.svg" ) ) );
|
||||
mIndicator->setToolTip( "Filtered" );
|
||||
connect( mIndicator, &QgsLayerTreeViewIndicator::clicked, this, &QgsLayerTreeViewFilterIndicatorManager::onIndicatorClicked );
|
||||
|
||||
QgsLayerTree *tree = mLayerTreeView->layerTreeModel()->rootGroup();
|
||||
onAddedChildren( tree, 0, tree->children().count() - 1 );
|
||||
|
||||
connect( tree, &QgsLayerTree::addedChildren, this, &QgsLayerTreeViewFilterIndicatorManager::onAddedChildren );
|
||||
connect( tree, &QgsLayerTree::willRemoveChildren, this, &QgsLayerTreeViewFilterIndicatorManager::onWillRemoveChildren );
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewFilterIndicatorManager::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, &QgsLayerTreeViewFilterIndicatorManager::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, &QgsLayerTreeViewFilterIndicatorManager::onLayerLoaded );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewFilterIndicatorManager::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, &QgsLayerTreeViewFilterIndicatorManager::onProviderDataChanged );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewFilterIndicatorManager::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, &QgsLayerTreeViewFilterIndicatorManager::onProviderDataChanged );
|
||||
|
||||
addOrRemoveIndicator( nodeLayer, vlayer->dataProvider() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewFilterIndicatorManager::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 QgsLayerTreeViewFilterIndicatorManager::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() );
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewFilterIndicatorManager::addOrRemoveIndicator( QgsLayerTreeNode *node, QgsVectorDataProvider *provider )
|
||||
{
|
||||
QString filter = provider->subsetString();
|
||||
if ( !filter.isEmpty() )
|
||||
mLayerTreeView->addIndicator( node, mIndicator );
|
||||
else
|
||||
mLayerTreeView->removeIndicator( node, mIndicator );
|
||||
}
|
53
src/app/qgslayertreeviewfilterindicator.h
Normal file
53
src/app/qgslayertreeviewfilterindicator.h
Normal file
@ -0,0 +1,53 @@
|
||||
/***************************************************************************
|
||||
qgslayertreeviewfilterindicator.h
|
||||
--------------------------------------
|
||||
Date : Januray 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 QGSLAYERTREEVIEWFILTERINDICATOR_H
|
||||
#define QGSLAYERTREEVIEWFILTERINDICATOR_H
|
||||
|
||||
#include "qgslayertreeviewindicator.h"
|
||||
|
||||
class QgsLayerTreeNode;
|
||||
class QgsLayerTreeView;
|
||||
class QgsVectorDataProvider;
|
||||
|
||||
|
||||
//! Adds indicators showing whether vector layers have a filter applied.
|
||||
class QgsLayerTreeViewFilterIndicatorManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QgsLayerTreeViewFilterIndicatorManager( 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();
|
||||
//! Adds/removes indicator of a layer
|
||||
void onProviderDataChanged();
|
||||
|
||||
void onIndicatorClicked( const QModelIndex &index );
|
||||
|
||||
private:
|
||||
void addOrRemoveIndicator( QgsLayerTreeNode *node, QgsVectorDataProvider *provider );
|
||||
|
||||
private:
|
||||
QgsLayerTreeView *mLayerTreeView;
|
||||
QgsLayerTreeViewIndicator *mIndicator = nullptr;
|
||||
};
|
||||
|
||||
#endif // QGSLAYERTREEVIEWFILTERINDICATOR_H
|
@ -159,6 +159,8 @@ SET(QGIS_GUI_SRCS
|
||||
layertree/qgslayertreemapcanvasbridge.cpp
|
||||
layertree/qgslayertreeview.cpp
|
||||
layertree/qgslayertreeviewdefaultactions.cpp
|
||||
layertree/qgslayertreeviewindicator.cpp
|
||||
layertree/qgslayertreeviewitemdelegate.cpp
|
||||
|
||||
layout/qgslayoutcustomdrophandler.cpp
|
||||
layout/qgslayoutitemguiregistry.cpp
|
||||
@ -677,6 +679,8 @@ SET(QGIS_GUI_MOC_HDRS
|
||||
layertree/qgslayertreemapcanvasbridge.h
|
||||
layertree/qgslayertreeview.h
|
||||
layertree/qgslayertreeviewdefaultactions.h
|
||||
layertree/qgslayertreeviewindicator.h
|
||||
layertree/qgslayertreeviewitemdelegate.h
|
||||
|
||||
layout/qgslayoutcustomdrophandler.h
|
||||
layout/qgslayoutdesignerinterface.h
|
||||
|
@ -26,6 +26,9 @@
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
|
||||
#include "qgslayertreeviewindicator.h"
|
||||
#include "qgslayertreeviewitemdelegate.h"
|
||||
|
||||
|
||||
QgsLayerTreeView::QgsLayerTreeView( QWidget *parent )
|
||||
: QTreeView( parent )
|
||||
@ -42,6 +45,10 @@ QgsLayerTreeView::QgsLayerTreeView( QWidget *parent )
|
||||
setSelectionMode( ExtendedSelection );
|
||||
setDefaultDropAction( Qt::MoveAction );
|
||||
|
||||
// we need a custom item delegate in order to draw indicators
|
||||
setItemDelegate( new QgsLayerTreeViewItemDelegate( this ) );
|
||||
setStyle( new QgsLayerTreeViewProxyStyle( this ) );
|
||||
|
||||
connect( this, &QTreeView::collapsed, this, &QgsLayerTreeView::updateExpandedStateToNode );
|
||||
connect( this, &QTreeView::expanded, this, &QgsLayerTreeView::updateExpandedStateToNode );
|
||||
}
|
||||
@ -332,6 +339,22 @@ QList<QgsMapLayer *> QgsLayerTreeView::selectedLayers() const
|
||||
return list;
|
||||
}
|
||||
|
||||
void QgsLayerTreeView::addIndicator( QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator )
|
||||
{
|
||||
if ( !mIndicators[node].contains( indicator ) )
|
||||
mIndicators[node].append( indicator );
|
||||
}
|
||||
|
||||
void QgsLayerTreeView::removeIndicator( QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator )
|
||||
{
|
||||
mIndicators[node].removeOne( indicator );
|
||||
}
|
||||
|
||||
QList<QgsLayerTreeViewIndicator *> QgsLayerTreeView::indicators( QgsLayerTreeNode *node ) const
|
||||
{
|
||||
return mIndicators.value( node );
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeView::refreshLayerSymbology( const QString &layerId )
|
||||
{
|
||||
@ -388,6 +411,10 @@ void QgsLayerTreeView::collapseAllNodes()
|
||||
|
||||
void QgsLayerTreeView::mouseReleaseEvent( QMouseEvent *event )
|
||||
{
|
||||
// we need to keep last mouse position in order to know whether to emit an indicator's clicked() signal
|
||||
// (the item delegate needs to know which indicator has been clicked)
|
||||
mLastReleaseMousePos = event->pos();
|
||||
|
||||
const QgsLayerTreeModel::Flags oldFlags = layerTreeModel()->flags();
|
||||
if ( event->modifiers() & Qt::ControlModifier )
|
||||
layerTreeModel()->setFlags( oldFlags | QgsLayerTreeModel::ActionHierarchical );
|
||||
|
@ -26,6 +26,7 @@ class QgsLayerTreeModel;
|
||||
class QgsLayerTreeNode;
|
||||
class QgsLayerTreeModelLegendNode;
|
||||
class QgsLayerTreeViewDefaultActions;
|
||||
class QgsLayerTreeViewIndicator;
|
||||
class QgsLayerTreeViewMenuProvider;
|
||||
class QgsMapLayer;
|
||||
|
||||
@ -106,6 +107,34 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
|
||||
//! Get list of selected layers
|
||||
QList<QgsMapLayer *> selectedLayers() const;
|
||||
|
||||
/**
|
||||
* Adds an indicator to the given layer tree node. Indicators are icons shown next to layer/group names
|
||||
* in the layer tree view. They can be used to show extra information with tree nodes and they allow
|
||||
* user interaction.
|
||||
*
|
||||
* Does not take ownership of the indicator. One indicator object may be used for multiple layer tree nodes.
|
||||
* \sa removeIndicator
|
||||
* \sa indicators
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
void addIndicator( QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator );
|
||||
|
||||
/**
|
||||
* Removes a previously added indicator to a layer tree node. Does not delete the indicator.
|
||||
* \sa addIndicator
|
||||
* \sa indicators
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
void removeIndicator( QgsLayerTreeNode *node, QgsLayerTreeViewIndicator *indicator );
|
||||
|
||||
/**
|
||||
* Returns list of indicators associated with a particular layer tree node.
|
||||
* \sa addIndicator
|
||||
* \sa removeIndicator
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
QList<QgsLayerTreeViewIndicator *> indicators( QgsLayerTreeNode *node ) const;
|
||||
|
||||
public slots:
|
||||
//! Force refresh of layer symbology. Normally not needed as the changes of layer's renderer are monitored by the model
|
||||
void refreshLayerSymbology( const QString &layerId );
|
||||
@ -138,7 +167,6 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
|
||||
|
||||
void dropEvent( QDropEvent *event ) override;
|
||||
|
||||
|
||||
protected slots:
|
||||
|
||||
void modelRowsInserted( const QModelIndex &index, int start, int end );
|
||||
@ -157,6 +185,13 @@ class GUI_EXPORT QgsLayerTreeView : public QTreeView
|
||||
QgsLayerTreeViewMenuProvider *mMenuProvider = nullptr;
|
||||
//! Keeps track of current layer ID (to check when to emit signal about change of current layer)
|
||||
QString mCurrentLayerID;
|
||||
//! Storage of indicators used with the tree view
|
||||
QHash< QgsLayerTreeNode *, QList<QgsLayerTreeViewIndicator *> > mIndicators;
|
||||
//! Used by the item delegate for identification of which indicator has been clicked
|
||||
QPoint mLastReleaseMousePos;
|
||||
|
||||
// friend so it can access viewOptions() method and mLastReleaseMousePos without making them public
|
||||
friend class QgsLayerTreeViewItemDelegate;
|
||||
};
|
||||
|
||||
|
||||
|
22
src/gui/layertree/qgslayertreeviewindicator.cpp
Normal file
22
src/gui/layertree/qgslayertreeviewindicator.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
/***************************************************************************
|
||||
qgslayertreeviewindicator.cpp
|
||||
--------------------------------------
|
||||
Date : Januray 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 "qgslayertreeviewindicator.h"
|
||||
|
||||
QgsLayerTreeViewIndicator::QgsLayerTreeViewIndicator( QObject *parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
|
||||
}
|
60
src/gui/layertree/qgslayertreeviewindicator.h
Normal file
60
src/gui/layertree/qgslayertreeviewindicator.h
Normal file
@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
qgslayertreeviewindicator.h
|
||||
--------------------------------------
|
||||
Date : Januray 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 QGSLAYERTREEVIEWINDICATOR_H
|
||||
#define QGSLAYERTREEVIEWINDICATOR_H
|
||||
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QObject>
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* 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 QgsLayerTreeView::addIndicator()
|
||||
* and QgsLayerTreeView::removeIndicator() calls.
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class GUI_EXPORT QgsLayerTreeViewIndicator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QgsLayerTreeViewIndicator( QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
//! Indicator icon that will be displayed in the layer tree view
|
||||
QIcon icon() const { return mIcon; }
|
||||
//! Sets indicator icon that will be displayed in the layer tree view
|
||||
void setIcon( const QIcon &icon ) { mIcon = icon; }
|
||||
|
||||
//! Returns tool tip text that will be shown when user hovers mouse over the indicator
|
||||
QString toolTip() const { return mToolTip; }
|
||||
//! Sets tool tip text
|
||||
void setToolTip( const QString &tip ) { mToolTip = tip; }
|
||||
|
||||
signals:
|
||||
//! Signal that is emitted when user clicks on the indicator
|
||||
void clicked( const QModelIndex &index );
|
||||
|
||||
private:
|
||||
QIcon mIcon;
|
||||
QString mToolTip;
|
||||
};
|
||||
|
||||
#endif // QGSLAYERTREEVIEWINDICATOR_H
|
168
src/gui/layertree/qgslayertreeviewitemdelegate.cpp
Normal file
168
src/gui/layertree/qgslayertreeviewitemdelegate.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
/***************************************************************************
|
||||
qgslayertreeviewitemdelegate.cpp
|
||||
--------------------------------------
|
||||
Date : Januray 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 "qgslayertreeviewitemdelegate.h"
|
||||
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgslayertreeview.h"
|
||||
#include "qgslayertreeviewindicator.h"
|
||||
|
||||
#include <QHelpEvent>
|
||||
#include <QToolTip>
|
||||
|
||||
|
||||
QgsLayerTreeViewProxyStyle::QgsLayerTreeViewProxyStyle( QgsLayerTreeView *treeView )
|
||||
: mLayerTreeView( treeView )
|
||||
{
|
||||
setParent( treeView );
|
||||
}
|
||||
|
||||
|
||||
QRect QgsLayerTreeViewProxyStyle::subElementRect( QStyle::SubElement element, const QStyleOption *option, const QWidget *widget ) const
|
||||
{
|
||||
if ( element == SE_ItemViewItemText || element == SE_LayerTreeItemIndicator )
|
||||
{
|
||||
if ( const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>( option ) )
|
||||
{
|
||||
if ( QgsLayerTreeNode *node = mLayerTreeView->layerTreeModel()->index2node( vopt->index ) )
|
||||
{
|
||||
int count = mLayerTreeView->indicators( node ).count();
|
||||
if ( count )
|
||||
{
|
||||
QRect r = QProxyStyle::subElementRect( SE_ItemViewItemText, option, widget );
|
||||
int indiWidth = r.height() * count;
|
||||
int textWidth = r.width() - indiWidth;
|
||||
if ( element == SE_LayerTreeItemIndicator )
|
||||
{
|
||||
return QRect( r.left() + textWidth, r.top(), indiWidth, r.height() );
|
||||
}
|
||||
else if ( element == SE_ItemViewItemText )
|
||||
{
|
||||
return QRect( r.left(), r.top(), textWidth, r.height() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QProxyStyle::subElementRect( element, option, widget );
|
||||
}
|
||||
|
||||
|
||||
// -----
|
||||
|
||||
|
||||
QgsLayerTreeViewItemDelegate::QgsLayerTreeViewItemDelegate( QgsLayerTreeView *parent )
|
||||
: QStyledItemDelegate( parent )
|
||||
, mLayerTreeView( parent )
|
||||
{
|
||||
connect( mLayerTreeView, &QgsLayerTreeView::clicked, this, &QgsLayerTreeViewItemDelegate::onClicked );
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewItemDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const
|
||||
{
|
||||
QStyledItemDelegate::paint( painter, option, index );
|
||||
|
||||
QgsLayerTreeNode *node = mLayerTreeView->layerTreeModel()->index2node( index );
|
||||
if ( !node )
|
||||
return;
|
||||
|
||||
const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
|
||||
if ( indicators.isEmpty() )
|
||||
return;
|
||||
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
|
||||
QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
|
||||
int spacing = indRect.height() / 10;
|
||||
int h = indRect.height();
|
||||
int x = indRect.left();
|
||||
|
||||
for ( QgsLayerTreeViewIndicator *indicator : indicators )
|
||||
{
|
||||
QRect rect( x + spacing, indRect.top() + spacing, h - spacing * 2, h - spacing * 2 );
|
||||
x += h;
|
||||
|
||||
QIcon::Mode mode = QIcon::Normal;
|
||||
if ( !( opt.state & QStyle::State_Enabled ) )
|
||||
mode = QIcon::Disabled;
|
||||
else if ( opt.state & QStyle::State_Selected )
|
||||
mode = QIcon::Selected;
|
||||
|
||||
indicator->icon().paint( painter, rect, Qt::AlignCenter, mode );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool QgsLayerTreeViewItemDelegate::helpEvent( QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index )
|
||||
{
|
||||
if ( event && event->type() == QEvent::ToolTip )
|
||||
{
|
||||
QHelpEvent *he = static_cast<QHelpEvent *>( event );
|
||||
|
||||
QgsLayerTreeNode *node = mLayerTreeView->layerTreeModel()->index2node( index );
|
||||
if ( node )
|
||||
{
|
||||
const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
|
||||
if ( !indicators.isEmpty() )
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
|
||||
|
||||
if ( indRect.contains( he->pos() ) )
|
||||
{
|
||||
int indicatorIndex = ( he->pos().x() - indRect.left() ) / indRect.height();
|
||||
if ( indicatorIndex >= 0 && indicatorIndex < indicators.count() )
|
||||
{
|
||||
const QString tooltip = indicators[indicatorIndex]->toolTip();
|
||||
if ( !tooltip.isEmpty() )
|
||||
{
|
||||
QToolTip::showText( he->globalPos(), tooltip, view );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QStyledItemDelegate::helpEvent( event, view, option, index );
|
||||
}
|
||||
|
||||
|
||||
void QgsLayerTreeViewItemDelegate::onClicked( const QModelIndex &index )
|
||||
{
|
||||
QgsLayerTreeNode *node = mLayerTreeView->layerTreeModel()->index2node( index );
|
||||
if ( !node )
|
||||
return;
|
||||
|
||||
const QList<QgsLayerTreeViewIndicator *> indicators = mLayerTreeView->indicators( node );
|
||||
if ( indicators.isEmpty() )
|
||||
return;
|
||||
|
||||
QStyleOptionViewItem opt( mLayerTreeView->viewOptions() );
|
||||
opt.rect = mLayerTreeView->visualRect( index );
|
||||
initStyleOption( &opt, index );
|
||||
QRect indRect = mLayerTreeView->style()->subElementRect( static_cast<QStyle::SubElement>( QgsLayerTreeViewProxyStyle::SE_LayerTreeItemIndicator ), &opt, mLayerTreeView );
|
||||
|
||||
QPoint pos = mLayerTreeView->mLastReleaseMousePos;
|
||||
if ( indRect.contains( pos ) )
|
||||
{
|
||||
int indicatorIndex = ( pos.x() - indRect.left() ) / indRect.height();
|
||||
if ( indicatorIndex >= 0 && indicatorIndex < indicators.count() )
|
||||
emit indicators[indicatorIndex]->clicked( index );
|
||||
}
|
||||
}
|
74
src/gui/layertree/qgslayertreeviewitemdelegate.h
Normal file
74
src/gui/layertree/qgslayertreeviewitemdelegate.h
Normal file
@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
qgslayertreeviewitemdelegate.h
|
||||
--------------------------------------
|
||||
Date : Januray 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 QGSLAYERTREEVIEWITEMDELEGATE_H
|
||||
#define QGSLAYERTREEVIEWITEMDELEGATE_H
|
||||
|
||||
/// @cond PRIVATE
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the QGIS API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
|
||||
class QgsLayerTreeView;
|
||||
|
||||
#include <QProxyStyle>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
/**
|
||||
* Proxy style to make the item text rect shorter so that indicators fit in without colliding with text
|
||||
*/
|
||||
class QgsLayerTreeViewProxyStyle : public QProxyStyle
|
||||
{
|
||||
public:
|
||||
explicit QgsLayerTreeViewProxyStyle( QgsLayerTreeView *treeView );
|
||||
|
||||
QRect subElementRect( SubElement element, const QStyleOption *option, const QWidget *widget ) const override;
|
||||
|
||||
static const unsigned long SE_LayerTreeItemIndicator = SE_CustomBase + 1;
|
||||
|
||||
private:
|
||||
QgsLayerTreeView *mLayerTreeView;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Item delegate that adds drawing of indicators
|
||||
*/
|
||||
class QgsLayerTreeViewItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QgsLayerTreeViewItemDelegate( QgsLayerTreeView *parent );
|
||||
|
||||
void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
|
||||
|
||||
bool helpEvent( QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index ) override;
|
||||
|
||||
private slots:
|
||||
void onClicked( const QModelIndex &index );
|
||||
|
||||
private:
|
||||
QgsLayerTreeView *mLayerTreeView;
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
#endif // QGSLAYERTREEVIEWITEMDELEGATE_H
|
Loading…
x
Reference in New Issue
Block a user