QGIS API Documentation 3.36.0-Maidenhead (09951dc0acf)
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 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.
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.
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.