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