QGIS API Documentation 3.28.14-Firenze (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
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 );
107 const QIcon slIcon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( sl, QgsUnitTypes::RenderMillimeters, QSize( iconSize, iconSize ), QgsMapUnitScale(), symbol->type() );
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.
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.
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)
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.