QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 mCurrentIdentifier = node.identifier;
81 mCurrentDescription = node.description;
82
83 return true;
84 }
85
86 bool visitSymbol( QTreeWidgetItem *rootItem, const QString &identifier, const QgsSymbol *symbol, QVector<int> rootPath )
87 {
88 bool ret = false;
89 for ( int idx = 0; idx < symbol->symbolLayerCount(); idx++ )
90 {
91 QgsSymbolLayer *sl = const_cast<QgsSymbol *>( symbol )->symbolLayer( idx );
92 QgsSymbol *subSymbol = sl->subSymbol();
93
94 QVector<int> indexPath = rootPath;
95 indexPath.append( idx );
96
97 std::unique_ptr< QTreeWidgetItem > slItem = std::make_unique< QTreeWidgetItem >( rootItem );
98 const QIcon slIcon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( sl, Qgis::RenderUnit::Millimeters, QSize( iconSize, iconSize ), QgsMapUnitScale(), symbol->type(), nullptr, QgsScreenProperties( mScreen.data() ) );
99 slItem->setIcon( 0, slIcon );
100 if ( sl->layerType() == "MaskMarker" )
101 {
102 slItem->setText( 0, QObject::tr( "Mask symbol layer" ) );
103 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
104 slItem->setCheckState( 0, Qt::Unchecked );
105 }
106
107 if ( ( sl->layerType() == "MaskMarker" ) ||
108 ( subSymbol && visitSymbol( slItem.get(), identifier, subSymbol, indexPath ) ) )
109 {
110 const QgsSymbolLayerReference ref( mLayer->id(), sl->id() );
111 mItems[ref] = slItem.get();
112 rootItem->addChild( slItem.release() );
113 ret = true;
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 std::unique_ptr< QTreeWidgetItem > symbolItem = std::make_unique< QTreeWidgetItem >( mLayerItem, QStringList() << ( mCurrentDescription + leaf.description ) );
130 const QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, QSize( iconSize, iconSize ), 0, nullptr, QgsScreenProperties( mScreen.data() ) );
131 symbolItem->setIcon( 0, icon );
132
133 if ( visitSymbol( symbolItem.get(), leaf.identifier, symbol, {} ) )
134 mLayerItem->addChild( symbolItem.release() );
135
136 return true;
137 }
138
139 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
140 QString mCurrentDescription;
141 QString mCurrentIdentifier;
142 QTreeWidgetItem *mLayerItem;
143 const QgsVectorLayer *mLayer;
144 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
145 QPointer< QScreen > mScreen;
146 };
147
148 class LabelMasksVisitor : public QgsStyleEntityVisitorInterface
149 {
150 public:
151 LabelMasksVisitor( QTreeWidgetItem *layerItem, const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items ):
152 mLayerItem( layerItem ), mLayer( layer ), mItems( items )
153 {}
154 bool visitEnter( const QgsStyleEntityVisitorInterface::Node &node ) override
155 {
157 {
158 currentRule = node.identifier;
159 currentDescription = node.description;
160 return true;
161 }
162 return false;
163 }
164 bool visit( const QgsStyleEntityVisitorInterface::StyleLeaf &leaf ) override
165 {
166 if ( leaf.entity && leaf.entity->type() == QgsStyle::LabelSettingsEntity )
167 {
168 auto labelSettingsEntity = static_cast<const QgsStyleLabelSettingsEntity *>( leaf.entity );
169 if ( labelSettingsEntity->settings().format().mask().enabled() )
170 {
171 const QString maskTitle = currentRule.isEmpty()
172 ? QObject::tr( "Label mask" )
173 : QObject::tr( "Label mask for '%1' rule" ).arg( currentDescription );
174 QTreeWidgetItem *slItem = new QTreeWidgetItem( mLayerItem, QStringList() << maskTitle );
175 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
176 slItem->setCheckState( 0, Qt::Unchecked );
177 mLayerItem->addChild( slItem );
178 mItems[QgsSymbolLayerReference( "__labels__" + mLayer->id(), currentRule )] = slItem;
179 }
180 }
181 return true;
182 }
183
184 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
185 // Current label rule, empty string for a simple labeling
186 QString currentRule;
187 QString currentDescription;
188 QTreeWidgetItem *mLayerItem;
189 const QgsVectorLayer *mLayer;
190 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
191 };
192
193 // populate the tree
194 const auto layers = QgsProject::instance()->layerTreeRoot()->findLayers();
195 for ( const QgsLayerTreeLayer *layerTreeLayer : layers )
196 {
197 QgsMapLayer *layer = layerTreeLayer->layer();
198 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
199 if ( ! vl )
200 continue;
201 if ( ! vl->renderer() )
202 continue;
203
204 std::unique_ptr< QTreeWidgetItem > layerItem = std::make_unique< QTreeWidgetItem >( mTree, QStringList() << layer->name() );
205 layerItem->setData( 0, Qt::UserRole, QVariant::fromValue( vl ) );
206
207 if ( vl->labeling() )
208 {
209 LabelMasksVisitor lblVisitor( layerItem.get(), vl, mItems );
210 vl->labeling()->accept( &lblVisitor );
211 }
212
213 SymbolLayerFillVisitor slVisitor( layerItem.get(), vl, mItems, screen() );
214 vl->renderer()->accept( &slVisitor );
215
216 if ( layerItem->childCount() > 0 )
217 mTree->addTopLevelItem( layerItem.release() );
218 }
219
220 expandAll( mTree->invisibleRootItem() );
221}
222
224QList<QgsMaskSourceSelectionWidget::MaskSource> QgsMaskSourceSelectionWidget::selection() const
225{
226 QList<QgsMaskSourceSelectionWidget::MaskSource> sel;
227 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
228 {
229 if ( it.value()->checkState( 0 ) == Qt::Checked )
230 {
231 const QgsSymbolLayerReference &ref = it.key();
233 source.isLabeling = ref.layerId().startsWith( "__labels__" );
234 source.layerId = source.isLabeling ? ref.layerId().mid( 10 ) : ref.layerId();
235 source.symbolLayerId = ref.symbolLayerIdV2();
236 sel.append( source );
237 }
238 }
239 return sel;
240}
241
243void QgsMaskSourceSelectionWidget::setSelection( const QList<QgsMaskSourceSelectionWidget::MaskSource> &sel )
244{
245 // Clear current selection
246 for ( auto it = mItems.begin(); it != mItems.end(); it++ )
247 {
248 it.value()->setCheckState( 0, Qt::Unchecked );
249 }
250
251 for ( const MaskSource &src : sel )
252 {
253 const QString layerId = ( src.isLabeling ? "__labels__" : "" ) + src.layerId;
254 const auto it = mItems.find( QgsSymbolLayerReference( layerId, src.symbolLayerId ) );
255 if ( it != mItems.end() )
256 {
257 it.value()->setCheckState( 0, Qt::Checked );
258 }
259 }
260}
@ 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:78
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:481
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.
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:94
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:156
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.