QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgssymbollayerselectionwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbollayerselectionwidget.h
3  ---------------------
4  begin : July 2019
5  copyright : (C) 2019 by Hugo Mercier
6  email : hugo dot mercier at oslandia dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QTreeWidget>
17 #include <QVBoxLayout>
18 
20 #include "qgsproject.h"
21 #include "qgsvectorlayer.h"
22 #include "qgslegendsymbolitem.h"
23 #include "symbology/qgsrenderer.h"
24 #include "qgsstyleentityvisitor.h"
26 #include "qgsguiutils.h"
27 #include "qgslayertree.h"
28 #include "qgslayertreelayer.h"
29 
31  : QWidget( parent )
32 {
33  mTree = new QTreeWidget( this );
34  mTree->setHeaderHidden( true );
35 
36  connect( mTree, &QTreeWidget::itemChanged, this, [&]( QTreeWidgetItem *, int ) { emit this->changed(); } );
37 
38  // place the tree in a layout
39  QVBoxLayout *vbox = new QVBoxLayout();
40  vbox->setContentsMargins( 0, 0, 0, 0 );
41  vbox->addWidget( mTree );
42 
43  setLayout( vbox );
44 }
45 
47 {
48  mLayer = layer;
49  mItems.clear();
50  mTree->clear();
51 
52  class TreeFillVisitor : public QgsStyleEntityVisitorInterface
53  {
54  public:
55  TreeFillVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerId, QTreeWidgetItem *> &items ):
56  mLayerItem( layerItem ), mLayer( layer ), mItems( items )
57  {}
58 
59  bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
60  {
62  return false;
63 
64  mCurrentIdentifier = node.identifier;
65  mCurrentDescription = node.description;
66 
67  return true;
68  }
69 
70  void visitSymbol( QTreeWidgetItem *rootItem, const QString &identifier, const QgsSymbol *symbol, QVector<int> rootPath )
71  {
72  for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
73  {
74  const QgsSymbolLayer *sl = symbol->symbolLayer( idx );
75  // Skip mask symbol layers. It makes no sense to take them as mask targets.
76  if ( sl->layerType() == "MaskMarker" )
77  continue;
78 
79  const QgsSymbol *subSymbol = const_cast<QgsSymbolLayer *>( sl )->subSymbol();
80 
81  QVector<int> indexPath = rootPath;
82  indexPath.append( idx );
83 
84  QTreeWidgetItem *slItem = new QTreeWidgetItem();
86  slItem->setData( 0, Qt::UserRole, idx );
87  slItem->setIcon( 0, slIcon );
88  auto flags = slItem->flags();
89  if ( ! subSymbol || subSymbol->symbolLayerCount() == 0 )
90  {
91  flags.setFlag( Qt::ItemIsUserCheckable, true );
92  slItem->setCheckState( 0, Qt::Unchecked );
93  }
94  else
95  {
96  flags.setFlag( Qt::ItemIsUserCheckable, false );
97  }
98  slItem->setFlags( flags );
99  rootItem->addChild( slItem );
100  slItem->setExpanded( true );
101 
102  mItems[QgsSymbolLayerId( mCurrentIdentifier + identifier, indexPath )] = slItem;
103 
104  if ( subSymbol )
105  {
106  visitSymbol( slItem, identifier, subSymbol, indexPath );
107  }
108  }
109  }
110 
111  bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
112  {
113  if ( ! leaf.entity || leaf.entity->type() != QgsStyle::SymbolEntity )
114  return true;
115 
116  const auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
117  const QgsSymbol *symbol = symbolEntity->symbol();
118  if ( ! symbol )
119  return true;
120 
121  // either leaf.description or mCurrentDescription is defined
122  QTreeWidgetItem *symbolItem = new QTreeWidgetItem( QStringList() << ( mCurrentDescription + leaf.description ) );
123  QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, QSize( iconSize, iconSize ) );
124  symbolItem->setData( 0, Qt::UserRole, mCurrentIdentifier );
125  symbolItem->setIcon( 0, icon );
126  mLayerItem->addChild( symbolItem );
127  symbolItem->setExpanded( true );
128 
129  visitSymbol( symbolItem, leaf.identifier, symbol, {} );
130 
131  return true;
132  }
133 
134  const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
135  QString mCurrentDescription;
136  QString mCurrentIdentifier;
137  QTreeWidgetItem *mLayerItem;
138  const QgsVectorLayer *mLayer;
139  QHash<QgsSymbolLayerId, QTreeWidgetItem *> &mItems;
140  };
141 
142  // populate the tree
143  if ( ! mLayer )
144  return;
145  if ( ! mLayer->renderer() )
146  return;
147 
148  TreeFillVisitor visitor( mTree->invisibleRootItem(), mLayer, mItems );
149  mLayer->renderer()->accept( &visitor );
150 }
151 
152 QSet<QgsSymbolLayerId> QgsSymbolLayerSelectionWidget::selection() const
153 {
154  QSet<QgsSymbolLayerId> sel;
155  for ( auto it = mItems.begin(); it != mItems.end(); it++ )
156  {
157  if ( it.value()->checkState( 0 ) == Qt::Checked )
158  sel.insert( it.key() );
159  }
160  return sel;
161 }
162 
163 void QgsSymbolLayerSelectionWidget::setSelection( const QSet<QgsSymbolLayerId> &sel )
164 {
165  // clear selection
166  for ( auto it = mItems.begin(); it != mItems.end(); it++ )
167  {
168  if ( it.value()->flags() & Qt::ItemIsUserCheckable )
169  it.value()->setCheckState( 0, Qt::Unchecked );
170  }
171 
172  // apply selection passed in parameter
173  for ( const QgsSymbolLayerId &lid : sel )
174  {
175  auto it = mItems.find( lid );
176  if ( it != mItems.end() )
177  ( *it )->setCheckState( 0, Qt::Checked );
178  }
179 }
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
virtual QgsStyle::StyleEntity type() const =0
Returns the type of style entity.
An interface for classes which can visit style entity (e.g.
@ SymbolRule
Rule based symbology or label child rule.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1219
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
We may need stable references to symbol layers, when pointers to symbol layers is not usable (when a ...
QgsSymbolLayerSelectionWidget(QWidget *parent=nullptr)
Default constructor.
QSet< QgsSymbolLayerId > selection() const
Returns current symbol layer selection.
void changed()
Signal emitted when something the configuration is changed.
void setLayer(const QgsVectorLayer *layer)
Populate the tree with selectable symbol layers from a given layer.
void setSelection(const QSet< QgsSymbolLayerId > &sel)
Sets the symbol layer selection.
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
static QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to an icon.
virtual QString layerType() const =0
Returns a string that represents this layer type.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:38
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
Definition: qgssymbol.cpp:420
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:160
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
Represents a vector layer which manages a vector based data sets.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
Contains information relating to a node (i.e.
QString identifier
A string identifying the node.
QString description
A string describing the node.
QgsStyleEntityVisitorInterface::NodeType type
Node type.
Contains information relating to the style entity currently being visited.
QString description
A string describing the style entity.
const QgsStyleEntityInterface * entity
Reference to style entity being visited.
QString identifier
A string identifying the style entity.