QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsmasksourceselectionwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmasksourceselectionwidget.cpp
3  ---------------------
4  begin : September 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 #include "qgsvectorlayerlabeling.h"
30 #include "qgsvectorlayerutils.h"
32 
33 static void expandAll( QTreeWidgetItem *item )
34 {
35  for ( int i = 0; i < item->childCount(); i++ )
36  expandAll( item->child( i ) );
37  item->setExpanded( true );
38 }
39 
41 {
42  std::cout << lid.symbolKey().toLocal8Bit().constData() << "/";
43  QVector<int> path = lid.symbolLayerIndexPath();
44  for ( int i = 0; i < path.size(); i++ )
45  {
46  std::cout << path[i] << "/";
47  }
48 }
49 
51 {
52  std::cout << ref.layerId().toLocal8Bit().constData() << "/";
54 }
55 
57  : QWidget( parent )
58 {
59  mTree = new QTreeWidget( this );
60  mTree->setHeaderHidden( true );
61 
62  connect( mTree, &QTreeWidget::itemChanged, this, [&]( QTreeWidgetItem *, int ) { emit this->changed(); } );
63 
64  // place the tree in a layout
65  QVBoxLayout *vbox = new QVBoxLayout();
66  vbox->setContentsMargins( 0, 0, 0, 0 );
67  vbox->addWidget( mTree );
68 
69  setLayout( vbox );
70 
71  update();
72 }
73 
75 {
76  mTree->clear();
77  mItems.clear();
78 
79  class SymbolLayerFillVisitor : public QgsStyleEntityVisitorInterface
80  {
81  public:
82  SymbolLayerFillVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
83  mLayerItem( layerItem ), mLayer( layer ), mItems( items )
84  {}
85 
86  bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
87  {
89  return false;
90 
91  mCurrentIdentifier = node.identifier;
92  mCurrentDescription = node.description;
93 
94  return true;
95  }
96 
97  bool visitSymbol( QTreeWidgetItem *rootItem, const QString &identifier, const QgsSymbol *symbol, QVector<int> rootPath )
98  {
99  bool ret = false;
100  for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
101  {
102  QgsSymbolLayer *sl = const_cast<QgsSymbol *>( symbol )->symbolLayer( idx );
103  QgsSymbol *subSymbol = sl->subSymbol();
104 
105  QVector<int> indexPath = rootPath;
106  indexPath.append( idx );
107 
108  std::unique_ptr< QTreeWidgetItem > slItem = qgis::make_unique< QTreeWidgetItem >( rootItem );
110  slItem->setIcon( 0, slIcon );
111  if ( sl->layerType() == "MaskMarker" )
112  {
113  slItem->setText( 0, QObject::tr( "Mask symbol layer" ) );
114  slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
115  slItem->setCheckState( 0, Qt::Unchecked );
116  }
117 
118  if ( ( sl->layerType() == "MaskMarker" ) ||
119  ( subSymbol && visitSymbol( slItem.get(), identifier, subSymbol, indexPath ) ) )
120  {
121  QgsSymbolLayerReference ref( mLayer->id(), QgsSymbolLayerId( mCurrentIdentifier + identifier, indexPath ) );
122  mItems[ref] = slItem.get();
123  rootItem->addChild( slItem.release() );
124  ret = true;
125  }
126  }
127  return ret;
128  }
129 
130  bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
131  {
132  if ( ! leaf.entity || leaf.entity->type() != QgsStyle::SymbolEntity )
133  return true;
134 
135  const auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
136  const QgsSymbol *symbol = symbolEntity->symbol();
137  if ( ! symbol )
138  return true;
139 
140  std::unique_ptr< QTreeWidgetItem > symbolItem = qgis::make_unique< QTreeWidgetItem >( mLayerItem, QStringList() << ( mCurrentDescription + leaf.description ) );
141  QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, QSize( iconSize, iconSize ) );
142  symbolItem->setIcon( 0, icon );
143 
144  if ( visitSymbol( symbolItem.get(), leaf.identifier, symbol, {} ) )
145  mLayerItem->addChild( symbolItem.release() );
146 
147  return true;
148  }
149 
150  const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
151  QString mCurrentDescription;
152  QString mCurrentIdentifier;
153  QTreeWidgetItem *mLayerItem;
154  const QgsVectorLayer *mLayer;
155  QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
156  };
157 
158  class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
159  {
160  public:
161  LabelMasksVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
162  mLayerItem( layerItem ), mLayer( layer ), mItems( items )
163  {}
164  bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
165  {
167  {
168  currentRule = node.identifier;
169  currentDescription = node.description;
170  return true;
171  }
172  return false;
173  }
174  bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
175  {
176  if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
177  {
178  auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
179  if ( labelSettingsEntity->settings().format().mask().enabled() )
180  {
181  QString maskTitle = currentRule.isEmpty()
182  ? QObject::tr( "Label mask" )
183  : QObject::tr( "Label mask for '%1' rule" ).arg( currentDescription );
184  QTreeWidgetItem *slItem = new QTreeWidgetItem( mLayerItem, QStringList() << maskTitle );
185  slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
186  slItem->setCheckState( 0, Qt::Unchecked );
187  mLayerItem->addChild( slItem );
188  mItems[QgsSymbolLayerReference( "__labels__" + mLayer->id(), { currentRule, 0 } )] = slItem;
189  }
190  }
191  return true;
192  }
193 
194  QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
195  // Current label rule, empty string for a simple labeling
196  QString currentRule;
197  QString currentDescription;
198  QTreeWidgetItem *mLayerItem;
199  const QgsVectorLayer *mLayer;
200  QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
201  };
202 
203  // populate the tree
204  const auto layers = QgsProject::instance()->layerTreeRoot()->findLayers();
205  for ( const QgsLayerTreeLayer *layerTreeLayer : layers )
206  {
207  const QgsMapLayer *layer = layerTreeLayer->layer();
208  const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( layer );
209  if ( ! vl )
210  continue;
211  if ( ! vl->renderer() )
212  continue;
213 
214  std::unique_ptr< QTreeWidgetItem > layerItem = qgis::make_unique< QTreeWidgetItem >( mTree, QStringList() << layer->name() );
215  layerItem->setData( 0, Qt::UserRole, vl );
216 
217  if ( vl->labeling() )
218  {
219  LabelMasksVisitor lblVisitor( layerItem.get(), vl, mItems );
220  vl->labeling()->accept( &lblVisitor );
221  }
222 
223  SymbolLayerFillVisitor slVisitor( layerItem.get(), vl, mItems );
224  vl->renderer()->accept( &slVisitor );
225 
226  if ( layerItem->childCount() > 0 )
227  mTree->addTopLevelItem( layerItem.release() );
228  }
229 
230  expandAll( mTree->invisibleRootItem() );
231 }
232 
234 QList<QgsMaskSourceSelectionWidget::MaskSource> QgsMaskSourceSelectionWidget::selection() const
235 {
236  QList<QgsMaskSourceSelectionWidget::MaskSource> sel;
237  for ( auto it = mItems.begin(); it != mItems.end(); it++ )
238  {
239  if ( it.value()->checkState( 0 ) == Qt::Checked )
240  {
241  const QgsSymbolLayerReference &ref = it.key();
243  source.isLabeling = ref.layerId().startsWith( "__labels__" );
244  source.layerId = source.isLabeling ? ref.layerId().mid( 10 ) : ref.layerId();
245  source.symbolLayerId = ref.symbolLayerId();
246  sel.append( source );
247  }
248  }
249  return sel;
250 }
251 
253 void QgsMaskSourceSelectionWidget::setSelection( const QList<QgsMaskSourceSelectionWidget::MaskSource> &sel )
254 {
255  // Clear current selection
256  for ( auto it = mItems.begin(); it != mItems.end(); it++ )
257  {
258  it.value()->setCheckState( 0, Qt::Unchecked );
259  }
260 
261  for ( const MaskSource &src : sel )
262  {
263  QString layerId = ( src.isLabeling ? "__labels__" : "" ) + src.layerId;
264  auto it = mItems.find( QgsSymbolLayerReference( layerId, src.symbolLayerId ) );
265  if ( it != mItems.end() )
266  {
267  it.value()->setCheckState( 0, Qt::Checked );
268  }
269  }
270 }
271 
QgsMaskSourceSelectionWidget::selection
QList< MaskSource > selection() const
Returns the current selection.
Definition: qgsmasksourceselectionwidget.cpp:234
QgsMaskSourceSelectionWidget::update
void update()
Updates the possible sources, from the project layers.
Definition: qgsmasksourceselectionwidget.cpp:74
QgsLayerTreeGroup::findLayers
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Definition: qgslayertreegroup.cpp:223
QgsMaskSourceSelectionWidget::MaskSource::layerId
QString layerId
The source layer id.
Definition: qgsmasksourceselectionwidget.h:45
QgsStyleSymbolEntity
Definition: qgsstyle.h:1134
QgsFeatureRenderer::accept
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
Definition: qgsrenderer.cpp:465
printSymbolLayerRef
void printSymbolLayerRef(const QgsSymbolLayerReference &ref)
Definition: qgsmasksourceselectionwidget.cpp:50
qgssymbollayerutils.h
QgsSymbolLayerReference
Definition: qgssymbollayerreference.h:117
QgsStyleEntityVisitorInterface::Node::description
QString description
A string describing the node.
Definition: qgsstyleentityvisitor.h:141
qgslayertreelayer.h
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsStyleEntityVisitorInterface
Definition: qgsstyleentityvisitor.h:33
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:168
QgsSymbol
Definition: qgssymbol.h:63
QgsMaskSourceSelectionWidget::setSelection
void setSelection(const QList< MaskSource > &sel)
Sets the symbol layer selection.
Definition: qgsmasksourceselectionwidget.cpp:253
QgsStyleEntityVisitorInterface::StyleLeaf
Contains information relating to the style entity currently being visited.
Definition: qgsstyleentityvisitor.h:60
QgsStyle::SymbolEntity
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
qgsmasksourceselectionwidget.h
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:264
QgsStyle::LabelSettingsEntity
@ LabelSettingsEntity
Label settings.
Definition: qgsstyle.h:185
printSymbolLayerId
void printSymbolLayerId(const QgsSymbolLayerId &lid)
Definition: qgsmasksourceselectionwidget.cpp:40
QgsSymbolLayerUtils::symbolPreviewIcon
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
Definition: qgssymbollayerutils.cpp:762
QgsProject::layerTreeRoot
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
Definition: qgsproject.cpp:3016
QgsSymbolLayer
Definition: qgssymbollayer.h:52
QgsMaskSourceSelectionWidget::MaskSource::isLabeling
bool isLabeling
Whether it is a labeling mask or not.
Definition: qgsmasksourceselectionwidget.h:48
QgsVectorLayer::labeling
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
Definition: qgsvectorlayer.h:1598
QgsLayerTreeLayer
Definition: qgslayertreelayer.h:43
QgsMaskSourceSelectionWidget::QgsMaskSourceSelectionWidget
QgsMaskSourceSelectionWidget(QWidget *parent=nullptr)
constructor
Definition: qgsmasksourceselectionwidget.cpp:56
QgsMaskSourceSelectionWidget::MaskSource
Definition: qgsmasksourceselectionwidget.h:42
qgslegendsymbolitem.h
QgsStyleEntityVisitorInterface::StyleLeaf::description
QString description
A string describing the style entity.
Definition: qgsstyleentityvisitor.h:98
qgsmasksymbollayer.h
qgsvectorlayerutils.h
QgsStyleEntityInterface::type
virtual QgsStyle::StyleEntity type() const =0
Returns the type of style entity.
QgsMaskSourceSelectionWidget::MaskSource::symbolLayerId
QgsSymbolLayerId symbolLayerId
The symbol layer id.
Definition: qgsmasksourceselectionwidget.h:51
QgsStyleEntityVisitorInterface::NodeType::SymbolRule
@ SymbolRule
Rule based symbology or label child rule.
QgsStyleEntityVisitorInterface::Node
Contains information relating to a node (i.e.
Definition: qgsstyleentityvisitor.h:110
qgsrenderer.h
QgsSymbolLayerReference::symbolLayerId
QgsSymbolLayerId symbolLayerId() const
The symbol layer's id.
Definition: qgssymbollayerreference.h:136
qgslayertree.h
QgsStyleLabelSettingsEntity
Definition: qgsstyle.h:1227
QgsSymbolLayer::subSymbol
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Definition: qgssymbollayer.h:348
QgsStyleEntityVisitorInterface::StyleLeaf::entity
const QgsStyleEntityInterface * entity
Reference to style entity being visited.
Definition: qgsstyleentityvisitor.h:103
qgsvectorlayer.h
QgsSymbolLayerId::symbolLayerIndexPath
QVector< int > symbolLayerIndexPath() const
Returns the symbol layer index path inside the symbol.
Definition: qgssymbollayerreference.h:86
QgsStyleEntityVisitorInterface::StyleLeaf::identifier
QString identifier
A string identifying the style entity.
Definition: qgsstyleentityvisitor.h:85
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsMaskSourceSelectionWidget::changed
void changed()
Emitted when an item was changed.
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:85
QgsSymbolLayerId
We may need stable references to symbol layers, when pointers to symbol layers is not usable (when a ...
Definition: qgssymbollayerreference.h:53
QgsSymbolLayer::layerType
virtual QString layerType() const =0
Returns a string that represents this layer type.
QgsSymbolLayerId::symbolKey
QString symbolKey() const
Returns the key associated to the symbol.
Definition: qgssymbollayerreference.h:81
qgsvectorlayerlabeling.h
QgsSymbolLayerReference::layerId
QString layerId() const
The referenced vector layer / feature renderer.
Definition: qgssymbollayerreference.h:131
qgsguiutils.h
QgsGuiUtils::scaleIconSize
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
Definition: qgsguiutils.cpp:257
QgsStyleEntityVisitorInterface::Node::identifier
QString identifier
A string identifying the node.
Definition: qgsstyleentityvisitor.h:133
QgsAbstractVectorLayerLabeling::accept
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the labeling...
Definition: qgsvectorlayerlabeling.cpp:44
QgsSymbolLayerUtils::symbolLayerPreviewIcon
static QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to an icon.
Definition: qgssymbollayerutils.cpp:849
qgsproject.h
QgsStyleEntityVisitorInterface::Node::type
QgsStyleEntityVisitorInterface::NodeType type
Node type.
Definition: qgsstyleentityvisitor.h:125
qgsstyleentityvisitor.h
QgsSymbol::symbolLayerCount
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:183
QgsVectorLayer::renderer
QgsFeatureRenderer * renderer()
Returns renderer.
Definition: qgsvectorlayer.h:881