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