QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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"
26#include "qgsguiutils.h"
27#include "qgslayertree.h"
28#include "qgslayertreelayer.h"
30#include "qgsvectorlayerutils.h"
32
33static 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
73{
74 mTree->clear();
75 mItems.clear();
76
77 class SymbolLayerFillVisitor : public QgsStyleEntityVisitorInterface
78 {
79 public:
80 SymbolLayerFillVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
81 mLayerItem( layerItem ), mLayer( layer ), mItems( items )
82 {}
83
84 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
85 {
87 return false;
88
89 mCurrentIdentifier = node.identifier;
90 mCurrentDescription = node.description;
91
92 return true;
93 }
94
95 bool visitSymbol( QTreeWidgetItem *rootItem, const QString &identifier, const QgsSymbol *symbol, QVector<int> rootPath )
96 {
97 bool ret = false;
98 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
99 {
100 QgsSymbolLayer *sl = const_cast<QgsSymbol *>( symbol )->symbolLayer( idx );
101 QgsSymbol *subSymbol = sl->subSymbol();
102
103 QVector<int> indexPath = rootPath;
104 indexPath.append( idx );
105
106 std::unique_ptr< QTreeWidgetItem > slItem = std::make_unique< QTreeWidgetItem >( rootItem );
108 slItem->setIcon( 0, slIcon );
109 if ( sl->layerType() == "MaskMarker" )
110 {
111 slItem->setText( 0, QObject::tr( "Mask symbol layer" ) );
112 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
113 slItem->setCheckState( 0, Qt::Unchecked );
114 }
115
116 if ( ( sl->layerType() == "MaskMarker" ) ||
117 ( subSymbol && visitSymbol( slItem.get(), identifier, subSymbol, indexPath ) ) )
118 {
119 const QgsSymbolLayerReference ref( mLayer->id(), QgsSymbolLayerId( mCurrentIdentifier + identifier, indexPath ) );
120 mItems[ref] = slItem.get();
121 rootItem->addChild( slItem.release() );
122 ret = true;
123 }
124 }
125 return ret;
126 }
127
128 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
129 {
130 if ( ! leaf.entity || leaf.entity->type() != QgsStyle::SymbolEntity )
131 return true;
132
133 const auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
134 const QgsSymbol *symbol = symbolEntity->symbol();
135 if ( ! symbol )
136 return true;
137
138 std::unique_ptr< QTreeWidgetItem > symbolItem = std::make_unique< QTreeWidgetItem >( mLayerItem, QStringList() << ( mCurrentDescription + leaf.description ) );
139 const QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, QSize( iconSize, iconSize ) );
140 symbolItem->setIcon( 0, icon );
141
142 if ( visitSymbol( symbolItem.get(), leaf.identifier, symbol, {} ) )
143 mLayerItem->addChild( symbolItem.release() );
144
145 return true;
146 }
147
148 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
149 QString mCurrentDescription;
150 QString mCurrentIdentifier;
151 QTreeWidgetItem *mLayerItem;
152 const QgsVectorLayer *mLayer;
153 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
154 };
155
156 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
157 {
158 public:
159 LabelMasksVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
160 mLayerItem( layerItem ), mLayer( layer ), mItems( items )
161 {}
162 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
163 {
165 {
166 currentRule = node.identifier;
167 currentDescription = node.description;
168 return true;
169 }
170 return false;
171 }
172 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
173 {
174 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
175 {
176 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
177 if ( labelSettingsEntity->settings().format().mask().enabled() )
178 {
179 const QString maskTitle = currentRule.isEmpty()
180 ? QObject::tr( "Label mask" )
181 : QObject::tr( "Label mask for '%1' rule" ).arg( currentDescription );
182 QTreeWidgetItem *slItem = new QTreeWidgetItem( mLayerItem, QStringList() << maskTitle );
183 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
184 slItem->setCheckState( 0, Qt::Unchecked );
185 mLayerItem->addChild( slItem );
186 mItems[QgsSymbolLayerReference( "__labels__" + mLayer->id(), { currentRule, 0 } )] = slItem;
187 }
188 }
189 return true;
190 }
191
192 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
193 // Current label rule, empty string for a simple labeling
194 QString currentRule;
195 QString currentDescription;
196 QTreeWidgetItem *mLayerItem;
197 const QgsVectorLayer *mLayer;
198 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
199 };
200
201 // populate the tree
202 const auto layers = QgsProject::instance()->layerTreeRoot()->findLayers();
203 for ( const QgsLayerTreeLayer *layerTreeLayer : layers )
204 {
205 const QgsMapLayer *layer = layerTreeLayer->layer();
206 const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( layer );
207 if ( ! vl )
208 continue;
209 if ( ! vl->renderer() )
210 continue;
211
212 std::unique_ptr< QTreeWidgetItem > layerItem = std::make_unique< QTreeWidgetItem >( mTree, QStringList() << layer->name() );
213 layerItem->setData( 0, Qt::UserRole, vl );
214
215 if ( vl->labeling() )
216 {
217 LabelMasksVisitor lblVisitor( layerItem.get(), vl, mItems );
218 vl->labeling()->accept( &lblVisitor );
219 }
220
221 SymbolLayerFillVisitor slVisitor( layerItem.get(), vl, mItems );
222 vl->renderer()->accept( &slVisitor );
223
224 if ( layerItem->childCount() > 0 )
225 mTree->addTopLevelItem( layerItem.release() );
226 }
227
228 expandAll( mTree->invisibleRootItem() );
229}
230
232QList<QgsMaskSourceSelectionWidget::MaskSource> QgsMaskSourceSelectionWidget::selection() const
233{
234 QList<QgsMaskSourceSelectionWidget::MaskSource> sel;
235 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
236 {
237 if ( it.value()->checkState( 0 ) == Qt::Checked )
238 {
239 const QgsSymbolLayerReference &ref = it.key();
241 source.isLabeling = ref.layerId().startsWith( "__labels__" );
242 source.layerId = source.isLabeling ? ref.layerId().mid( 10 ) : ref.layerId();
243 source.symbolLayerId = ref.symbolLayerId();
244 sel.append( source );
245 }
246 }
247 return sel;
248}
249
251void QgsMaskSourceSelectionWidget::setSelection( const QList<QgsMaskSourceSelectionWidget::MaskSource> &sel )
252{
253 // Clear current selection
254 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
255 {
256 it.value()->setCheckState( 0, Qt::Unchecked );
257 }
258
259 for ( const MaskSource &src : sel )
260 {
261 const QString layerId = ( src.isLabeling ? "__labels__" : "" ) + src.layerId;
262 const auto it = mItems.find( QgsSymbolLayerReference( layerId, src.symbolLayerId ) );
263 if ( it != mItems.end() )
264 {
265 it.value()->setCheckState( 0, Qt::Checked );
266 }
267 }
268}
269
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:1435
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1342
@ LabelSettingsEntity
Label settings.
Definition: qgsstyle.h:185
@ SymbolEntity
Symbols.
Definition: qgsstyle.h:180
We may need stable references to symbol layers, when pointers to symbol layers is not usable (when a ...
QVector< int > symbolLayerIndexPath() const
Returns the symbol layer index path inside the symbol.
QString symbolKey() const
Returns the key associated to the symbol.
Type used to refer to a specific symbol layer in a symbol of a layer.
QgsSymbolLayerId symbolLayerId() const
The symbol layer's id.
QString layerId() const
The referenced vector layer / feature renderer.
static QIcon symbolLayerPreviewIcon(const QgsSymbolLayer *layer, QgsUnitTypes::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.
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
virtual QString layerType() const =0
Returns a string that represents this layer type.
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
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
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)
void printSymbolLayerId(const QgsSymbolLayerId &lid)
QgsSymbolLayerId symbolLayerId
The symbol layer id.
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.