QGIS API Documentation 3.38.0-Grenoble (exported)
Loading...
Searching...
No Matches
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#include <QPointer>
19#include <QScreen>
20
22#include "qgsproject.h"
23#include "qgsvectorlayer.h"
27#include "qgsguiutils.h"
28#include "qgslayertree.h"
29#include "qgslayertreelayer.h"
31
32static void expandAll( QTreeWidgetItem *item )
33{
34 for ( int i = 0; i < item->childCount(); i++ )
35 expandAll( item->child( i ) );
36 item->setExpanded( true );
37}
38
40{
41 std::cout << ref.layerId().toLocal8Bit().constData() << "/" << ref.symbolLayerIdV2().toLocal8Bit().constData();
42}
43
45 : QWidget( parent )
46{
47 mTree = new QTreeWidget( this );
48 mTree->setHeaderHidden( true );
49
50 connect( mTree, &QTreeWidget::itemChanged, this, [&]( QTreeWidgetItem *, int ) { emit this->changed(); } );
51
52 // place the tree in a layout
53 QVBoxLayout *vbox = new QVBoxLayout();
54 vbox->setContentsMargins( 0, 0, 0, 0 );
55 vbox->addWidget( mTree );
56
57 setLayout( vbox );
58}
59
61{
62 mTree->clear();
63 mItems.clear();
64
65 class SymbolLayerFillVisitor : public QgsStyleEntityVisitorInterface
66 {
67 public:
68 SymbolLayerFillVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items, QScreen *screen )
69 : mLayerItem( layerItem )
70 , mLayer( layer )
71 , mItems( items )
72 , mScreen( screen )
73 {}
74
75 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
76 {
78 return false;
79
80 mCurrentDescription = node.description;
81
82 return true;
83 }
84
85 struct TreeNode
86 {
87 TreeNode( const QgsSymbol *_symbol, const QgsSymbolLayer *_sl = nullptr )
88 : sl( _sl ), symbol( _symbol ) {};
89
90 const QgsSymbolLayer *sl = nullptr;
91 const QgsSymbol *symbol = nullptr;
92 QList<TreeNode> children;
93 };
94
95
96 bool visitSymbol( TreeNode &parent, const QString &identifier, const QgsSymbol *symbol, QVector<int> rootPath )
97 {
98 bool ret = false;
99 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
100 {
101 QgsSymbolLayer *sl = const_cast<QgsSymbol *>( symbol )->symbolLayer( idx );
102 QgsSymbol *subSymbol = sl->subSymbol();
103
104 QVector<int> indexPath = rootPath;
105 indexPath.append( idx );
106
107 TreeNode node( symbol, sl );
108 if ( ( sl->layerType() == "MaskMarker" ) ||
109 ( subSymbol && visitSymbol( node, identifier, subSymbol, indexPath ) ) )
110 {
111 ret = true;
112 parent.children << node;
113 }
114 }
115 return ret;
116 }
117
118 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
119 {
120 if ( ! leaf.entity || leaf.entity->type() != QgsStyle::SymbolEntity )
121 return true;
122
123 const auto symbolEntity = static_cast<const QgsStyleSymbolEntity *>( leaf.entity );
124 const QgsSymbol *symbol = symbolEntity->symbol();
125 if ( ! symbol )
126 return true;
127
128 TreeNode node( symbol );
129 if ( visitSymbol( node, leaf.identifier, symbol, {} ) )
130 createItems( leaf.description, mLayerItem, node );
131
132 return true;
133 }
134
135 void createItems( const QString &leafDescription, QTreeWidgetItem *rootItem, const TreeNode &node )
136 {
137 QTreeWidgetItem *item = nullptr;
138 // root symbol node
139 if ( !node.sl )
140 {
141 item = new QTreeWidgetItem( rootItem, QStringList() << ( mCurrentDescription + leafDescription ) );
142 const QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( node.symbol, QSize( iconSize, iconSize ), 0, nullptr, QgsScreenProperties( mScreen.data() ) );
143 item->setIcon( 0, icon );
144 }
145 // symbol layer node
146 else
147 {
148 item = new QTreeWidgetItem( rootItem );
149 const QIcon slIcon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( node.sl, Qgis::RenderUnit::Millimeters, QSize( iconSize, iconSize ), QgsMapUnitScale(), node.symbol->type(), nullptr, QgsScreenProperties( mScreen.data() ) );
150 item->setIcon( 0, slIcon );
151 if ( node.sl->layerType() == "MaskMarker" )
152 {
153 item->setText( 0, QObject::tr( "Mask symbol layer" ) );
154 item->setFlags( item->flags() | Qt::ItemIsUserCheckable );
155 item->setCheckState( 0, Qt::Unchecked );
156
157 const QgsSymbolLayerReference ref( mLayer->id(), node.sl->id() );
158 mItems[ref] = item;
159 }
160 }
161
162 rootItem->addChild( item );
163
164 for ( TreeNode child : node.children )
165 createItems( leafDescription, item, child );
166 };
167
168 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
169 QString mCurrentDescription;
170 QTreeWidgetItem *mLayerItem;
171 const QgsVectorLayer *mLayer;
172 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
173 QPointer< QScreen > mScreen;
174 };
175
176 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
177 {
178 public:
179 LabelMasksVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
180 mLayerItem( layerItem ), mLayer( layer ), mItems( items )
181 {}
182 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
183 {
185 {
186 currentRule = node.identifier;
187 currentDescription = node.description;
188 return true;
189 }
190 return false;
191 }
192 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
193 {
194 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
195 {
196 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
197 if ( labelSettingsEntity->settings().format().mask().enabled() )
198 {
199 const QString maskTitle = currentRule.isEmpty()
200 ? QObject::tr( "Label mask" )
201 : QObject::tr( "Label mask for '%1' rule" ).arg( currentDescription );
202 QTreeWidgetItem *slItem = new QTreeWidgetItem( mLayerItem, QStringList() << maskTitle );
203 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
204 slItem->setCheckState( 0, Qt::Unchecked );
205 mLayerItem->addChild( slItem );
206 mItems[QgsSymbolLayerReference( "__labels__" + mLayer->id(), currentRule )] = slItem;
207 }
208 }
209 return true;
210 }
211
212 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
213 // Current label rule, empty string for a simple labeling
214 QString currentRule;
215 QString currentDescription;
216 QTreeWidgetItem *mLayerItem;
217 const QgsVectorLayer *mLayer;
218 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
219 };
220
221 // populate the tree
222 const auto layers = QgsProject::instance()->layerTreeRoot()->findLayers();
223 for ( const QgsLayerTreeLayer *layerTreeLayer : layers )
224 {
225 QgsMapLayer *layer = layerTreeLayer->layer();
226 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
227 if ( ! vl )
228 continue;
229 if ( ! vl->renderer() )
230 continue;
231
232 std::unique_ptr< QTreeWidgetItem > layerItem = std::make_unique< QTreeWidgetItem >( mTree, QStringList() << layer->name() );
233 layerItem->setData( 0, Qt::UserRole, QVariant::fromValue( vl ) );
234
235 if ( vl->labeling() )
236 {
237 LabelMasksVisitor lblVisitor( layerItem.get(), vl, mItems );
238 vl->labeling()->accept( &lblVisitor );
239 }
240
241 SymbolLayerFillVisitor slVisitor( layerItem.get(), vl, mItems, screen() );
242 vl->renderer()->accept( &slVisitor );
243
244 if ( layerItem->childCount() > 0 )
245 mTree->addTopLevelItem( layerItem.release() );
246 }
247
248 expandAll( mTree->invisibleRootItem() );
249}
250
252QList<QgsMaskSourceSelectionWidget::MaskSource> QgsMaskSourceSelectionWidget::selection() const
253{
254 QList<QgsMaskSourceSelectionWidget::MaskSource> sel;
255 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
256 {
257 if ( it.value()->checkState( 0 ) == Qt::Checked )
258 {
259 const QgsSymbolLayerReference &ref = it.key();
261 source.isLabeling = ref.layerId().startsWith( "__labels__" );
262 source.layerId = source.isLabeling ? ref.layerId().mid( 10 ) : ref.layerId();
263 source.symbolLayerId = ref.symbolLayerIdV2();
264 sel.append( source );
265 }
266 }
267 return sel;
268}
269
271void QgsMaskSourceSelectionWidget::setSelection( const QList<QgsMaskSourceSelectionWidget::MaskSource> &sel )
272{
273 // Clear current selection
274 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
275 {
276 it.value()->setCheckState( 0, Qt::Unchecked );
277 }
278
279 for ( const MaskSource &src : sel )
280 {
281 const QString layerId = ( src.isLabeling ? "__labels__" : "" ) + src.layerId;
282 const auto it = mItems.find( QgsSymbolLayerReference( layerId, src.symbolLayerId ) );
283 if ( it != mItems.end() )
284 {
285 it.value()->setCheckState( 0, Qt::Checked );
286 }
287 }
288}
@ Millimeters
Millimeters.
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:75
QString name
Definition qgsmaplayer.h:79
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.
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
Stores properties relating to a screen.
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:1465
A symbol entity for QgsStyle databases.
Definition qgsstyle.h:1372
@ 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 symbolLayerPreviewIcon(const QgsSymbolLayer *layer, Qgis::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::SymbolType parentSymbolType=Qgis::SymbolType::Hybrid, QgsMapLayer *mapLayer=nullptr, const QgsScreenProperties &screen=QgsScreenProperties())
Draws a symbol layer preview to an icon.
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr, const QgsScreenProperties &screen=QgsScreenProperties())
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:94
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition qgssymbol.h:215
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.
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.