QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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"
25#include "qgsguiutils.h"
26#include "qgslayertree.h"
27#include "qgslayertreelayer.h"
29
30static void expandAll( QTreeWidgetItem *item )
31{
32 for ( int i = 0; i < item->childCount(); i++ )
33 expandAll( item->child( i ) );
34 item->setExpanded( true );
35}
36
38{
39 std::cout << ref.layerId().toLocal8Bit().constData() << "/" << ref.symbolLayerIdV2().toLocal8Bit().constData();
40}
41
43 : QWidget( parent )
44{
45 mTree = new QTreeWidget( this );
46 mTree->setHeaderHidden( true );
47
48 connect( mTree, &QTreeWidget::itemChanged, this, [&]( QTreeWidgetItem *, int ) { emit this->changed(); } );
49
50 // place the tree in a layout
51 QVBoxLayout *vbox = new QVBoxLayout();
52 vbox->setContentsMargins( 0, 0, 0, 0 );
53 vbox->addWidget( mTree );
54
55 setLayout( vbox );
56}
57
59{
60 mTree->clear();
61 mItems.clear();
62
63 class SymbolLayerFillVisitor : public QgsStyleEntityVisitorInterface
64 {
65 public:
66 SymbolLayerFillVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
67 mLayerItem( layerItem ), mLayer( layer ), mItems( items )
68 {}
69
70 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
71 {
73 return false;
74
75 mCurrentIdentifier = node.identifier;
76 mCurrentDescription = node.description;
77
78 return true;
79 }
80
81 bool visitSymbol( QTreeWidgetItem *rootItem, const QString &identifier, const QgsSymbol *symbol, QVector<int> rootPath )
82 {
83 bool ret = false;
84 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
85 {
86 QgsSymbolLayer *sl = const_cast<QgsSymbol *>( symbol )->symbolLayer( idx );
87 QgsSymbol *subSymbol = sl->subSymbol();
88
89 QVector<int> indexPath = rootPath;
90 indexPath.append( idx );
91
92 std::unique_ptr< QTreeWidgetItem > slItem = std::make_unique< QTreeWidgetItem >( rootItem );
93 const QIcon slIcon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( sl, Qgis::RenderUnit::Millimeters, QSize( iconSize, iconSize ), QgsMapUnitScale(), symbol->type() );
94 slItem->setIcon( 0, slIcon );
95 if ( sl->layerType() == "MaskMarker" )
96 {
97 slItem->setText( 0, QObject::tr( "Mask symbol layer" ) );
98 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
99 slItem->setCheckState( 0, Qt::Unchecked );
100 }
101
102 if ( ( sl->layerType() == "MaskMarker" ) ||
103 ( subSymbol && visitSymbol( slItem.get(), identifier, subSymbol, indexPath ) ) )
104 {
105 const QgsSymbolLayerReference ref( mLayer->id(), sl->id() );
106 mItems[ref] = slItem.get();
107 rootItem->addChild( slItem.release() );
108 ret = true;
109 }
110 }
111 return ret;
112 }
113
114 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
115 {
116 if ( ! leaf.entity || leaf.entity->type() != QgsStyle::SymbolEntity )
117 return true;
118
119 const auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
120 const QgsSymbol *symbol = symbolEntity->symbol();
121 if ( ! symbol )
122 return true;
123
124 std::unique_ptr< QTreeWidgetItem > symbolItem = std::make_unique< QTreeWidgetItem >( mLayerItem, QStringList() << ( mCurrentDescription + leaf.description ) );
125 const QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, QSize( iconSize, iconSize ) );
126 symbolItem->setIcon( 0, icon );
127
128 if ( visitSymbol( symbolItem.get(), leaf.identifier, symbol, {} ) )
129 mLayerItem->addChild( symbolItem.release() );
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<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
140 };
141
142 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
143 {
144 public:
145 LabelMasksVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
146 mLayerItem( layerItem ), mLayer( layer ), mItems( items )
147 {}
148 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
149 {
151 {
152 currentRule = node.identifier;
153 currentDescription = node.description;
154 return true;
155 }
156 return false;
157 }
158 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
159 {
160 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
161 {
162 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
163 if ( labelSettingsEntity->settings().format().mask().enabled() )
164 {
165 const QString maskTitle = currentRule.isEmpty()
166 ? QObject::tr( "Label mask" )
167 : QObject::tr( "Label mask for '%1' rule" ).arg( currentDescription );
168 QTreeWidgetItem *slItem = new QTreeWidgetItem( mLayerItem, QStringList() << maskTitle );
169 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
170 slItem->setCheckState( 0, Qt::Unchecked );
171 mLayerItem->addChild( slItem );
172 mItems[QgsSymbolLayerReference( "__labels__" + mLayer->id(), currentRule )] = slItem;
173 }
174 }
175 return true;
176 }
177
178 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
179 // Current label rule, empty string for a simple labeling
180 QString currentRule;
181 QString currentDescription;
182 QTreeWidgetItem *mLayerItem;
183 const QgsVectorLayer *mLayer;
184 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
185 };
186
187 // populate the tree
188 const auto layers = QgsProject::instance()->layerTreeRoot()->findLayers();
189 for ( const QgsLayerTreeLayer *layerTreeLayer : layers )
190 {
191 QgsMapLayer *layer = layerTreeLayer->layer();
192 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
193 if ( ! vl )
194 continue;
195 if ( ! vl->renderer() )
196 continue;
197
198 std::unique_ptr< QTreeWidgetItem > layerItem = std::make_unique< QTreeWidgetItem >( mTree, QStringList() << layer->name() );
199 layerItem->setData( 0, Qt::UserRole, QVariant::fromValue( vl ) );
200
201 if ( vl->labeling() )
202 {
203 LabelMasksVisitor lblVisitor( layerItem.get(), vl, mItems );
204 vl->labeling()->accept( &lblVisitor );
205 }
206
207 SymbolLayerFillVisitor slVisitor( layerItem.get(), vl, mItems );
208 vl->renderer()->accept( &slVisitor );
209
210 if ( layerItem->childCount() > 0 )
211 mTree->addTopLevelItem( layerItem.release() );
212 }
213
214 expandAll( mTree->invisibleRootItem() );
215}
216
218QList<QgsMaskSourceSelectionWidget::MaskSource> QgsMaskSourceSelectionWidget::selection() const
219{
220 QList<QgsMaskSourceSelectionWidget::MaskSource> sel;
221 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
222 {
223 if ( it.value()->checkState( 0 ) == Qt::Checked )
224 {
225 const QgsSymbolLayerReference &ref = it.key();
227 source.isLabeling = ref.layerId().startsWith( "__labels__" );
228 source.layerId = source.isLabeling ? ref.layerId().mid( 10 ) : ref.layerId();
229 source.symbolLayerId = ref.symbolLayerIdV2();
230 sel.append( source );
231 }
232 }
233 return sel;
234}
235
237void QgsMaskSourceSelectionWidget::setSelection( const QList<QgsMaskSourceSelectionWidget::MaskSource> &sel )
238{
239 // Clear current selection
240 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
241 {
242 it.value()->setCheckState( 0, Qt::Unchecked );
243 }
244
245 for ( const MaskSource &src : sel )
246 {
247 const QString layerId = ( src.isLabeling ? "__labels__" : "" ) + src.layerId;
248 const auto it = mItems.find( QgsSymbolLayerReference( layerId, src.symbolLayerId ) );
249 if ( it != mItems.end() )
250 {
251 it.value()->setCheckState( 0, Qt::Checked );
252 }
253 }
254}
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the labeling...
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Layer tree node points to a map layer.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
Struct for storing maximum and minimum scales for measurements in map units.
void setSelection(const QList< MaskSource > &sel)
Sets the symbol layer selection.
void changed()
Emitted when an item was changed.
void update()
Updates the possible sources, from the project layers.
QList< MaskSource > selection() const
Returns the current selection.
QgsMaskSourceSelectionWidget(QWidget *parent=nullptr)
constructor
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
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 label settings entity for QgsStyle databases.
Definition: qgsstyle.h:1434
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1341
@ LabelSettingsEntity
Label settings.
Definition: qgsstyle.h:185
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
Type used to refer to a specific symbol layer in a symbol of a layer.
QString symbolLayerIdV2() const
The symbol layer's id.
QString layerId() const
The referenced vector layer / feature renderer.
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, Qgis::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::SymbolType parentSymbolType=Qgis::SymbolType::Hybrid, QgsMapLayer *mapLayer=nullptr)
Draws a symbol layer preview to an icon.
virtual QString layerType() const =0
Returns a string that represents this layer type.
QString id() const
Returns symbol layer identifier This id is unique in the whole project.
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:93
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:215
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
Represents a vector layer which manages a vector based data sets.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
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,...
void printSymbolLayerRef(const QgsSymbolLayerReference &ref)
bool isLabeling
Whether it is a labeling mask or not.
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.