35#include <QInputDialog>
46#include "moc_qgsmasksourceselectionwidget.cpp"
48using namespace Qt::StringLiterals;
50static void expandAll( QTreeWidgetItem *item )
52 for (
int i = 0; i < item->childCount(); i++ )
53 expandAll( item->child( i ) );
54 item->setExpanded(
true );
59 std::cout << ref.
layerId().toLocal8Bit().constData() <<
"/" << ref.
symbolLayerIdV2().toLocal8Bit().constData();
65 QVBoxLayout *vbox =
new QVBoxLayout();
66 vbox->setContentsMargins( 0, 0, 0, 0 );
68 QHBoxLayout *hLayout =
new QHBoxLayout();
70 mSetComboBox =
new QComboBox();
72 mManagerModel->setAllowEmptyObject(
true );
74 mManagerProxyModel->setSourceModel( mManagerModel );
75 mSetComboBox->setModel( mManagerProxyModel );
76 connect( mSetComboBox, qOverload< int >( &QComboBox::currentIndexChanged ),
this, &QgsMaskSourceSelectionWidget::selectedSetChanged );
78 mSetsToolButton =
new QToolButton();
79 mSetsToolButton->setText( u
"…"_s );
80 mSetsToolButton->setPopupMode( QToolButton::InstantPopup );
82 QMenu *toolMenu =
new QMenu( mSetsToolButton );
83 connect( toolMenu, &QMenu::aboutToShow,
this, [
this] {
84 const bool isCustomSelected = isCustomSet();
85 mRemoveAction->setEnabled( !isCustomSelected );
86 mRenameAction->setEnabled( !isCustomSelected );
88 QAction *addAction =
new QAction( tr(
"New Selective Masking Set…" ), toolMenu );
89 connect( addAction, &QAction::triggered,
this, &QgsMaskSourceSelectionWidget::newSet );
90 toolMenu->addAction( addAction );
91 mRemoveAction =
new QAction( tr(
"Remove Set…" ), toolMenu );
92 connect( mRemoveAction, &QAction::triggered,
this, &QgsMaskSourceSelectionWidget::removeSet );
93 toolMenu->addAction( mRemoveAction );
94 mRenameAction =
new QAction( tr(
"Rename Set…" ), toolMenu );
95 connect( mRenameAction, &QAction::triggered,
this, &QgsMaskSourceSelectionWidget::renameSet );
96 toolMenu->addAction( mRenameAction );
97 mSetsToolButton->setMenu( toolMenu );
99 hLayout->addWidget(
new QLabel( tr(
"Preset" ) ) );
100 hLayout->addWidget( mSetComboBox, 1 );
101 hLayout->addWidget( mSetsToolButton, 1 );
102 vbox->addLayout( hLayout );
104 mTree =
new QTreeWidget(
this );
105 mTree->setHeaderHidden(
true );
107 connect( mTree, &QTreeWidget::itemChanged,
this, &QgsMaskSourceSelectionWidget::onItemChanged );
109 vbox->addWidget( mTree, 1 );
116 mBlockChangedSignals++;
123 SymbolLayerFillVisitor( QTreeWidgetItem *layerItem,
const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items, QScreen *screen )
124 : mLayerItem( layerItem )
144 , symbol( _symbol ) {};
148 QList<TreeNode> children;
152 bool visitSymbol( TreeNode &parent,
const QString &identifier,
const QgsSymbol *symbol, QVector<int> rootPath )
160 QVector<int> indexPath = rootPath;
161 indexPath.append( idx );
163 TreeNode node( symbol, sl );
164 if ( ( sl->
layerType() ==
"MaskMarker" ) || ( subSymbol && visitSymbol( node, identifier, subSymbol, indexPath ) ) )
167 parent.children << node;
179 const QgsSymbol *symbol = symbolEntity->symbol();
183 TreeNode node( symbol );
184 if ( visitSymbol( node, leaf.
identifier, symbol, {} ) )
190 void createItems(
const QString &leafDescription, QTreeWidgetItem *rootItem,
const TreeNode &node )
192 QTreeWidgetItem *item =
nullptr;
196 item =
new QTreeWidgetItem( rootItem, QStringList() << ( mCurrentDescription + leafDescription ) );
198 item->setIcon( 0, icon );
203 item =
new QTreeWidgetItem( rootItem );
206 item->setIcon( 0, slIcon );
207 if ( node.sl->layerType() ==
"MaskMarker" )
209 item->setText( 0, QObject::tr(
"Mask symbol layer" ) );
210 item->setFlags( item->flags() | Qt::ItemIsUserCheckable );
211 item->setCheckState( 0, Qt::Unchecked );
218 rootItem->addChild( item );
220 for ( TreeNode child : node.children )
221 createItems( leafDescription, item, child );
225 QString mCurrentDescription;
226 QTreeWidgetItem *mLayerItem;
228 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
229 QPointer<QScreen> mScreen;
235 LabelMasksVisitor( QTreeWidgetItem *layerItem,
const QgsVectorLayer *layer, QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &items )
236 : mLayerItem( layerItem )
255 if ( labelSettingsEntity->settings().format().mask().enabled() )
257 const QString maskTitle = currentRule.isEmpty() ? QObject::tr(
"Label mask" ) : QObject::tr(
"Label mask for '%1' rule" ).arg( currentDescription );
258 QTreeWidgetItem *slItem =
new QTreeWidgetItem( mLayerItem, QStringList() << maskTitle );
259 slItem->setFlags( slItem->flags() | Qt::ItemIsUserCheckable );
260 slItem->setCheckState( 0, Qt::Unchecked );
261 mLayerItem->addChild( slItem );
268 QHash<QString, QHash<QString, QSet<QgsSymbolLayerId>>> masks;
271 QString currentDescription;
272 QTreeWidgetItem *mLayerItem;
274 QHash<QgsSymbolLayerReference, QTreeWidgetItem *> &mItems;
288 auto layerItem = std::make_unique<QTreeWidgetItem>( mTree, QStringList() << layer->
name() );
289 layerItem->setData( 0, Qt::UserRole, QVariant::fromValue( vl ) );
293 LabelMasksVisitor lblVisitor( layerItem.get(), vl, mItems );
297 SymbolLayerFillVisitor slVisitor( layerItem.get(), vl, mItems, screen() );
300 if ( layerItem->childCount() > 0 )
301 mTree->addTopLevelItem( layerItem.release() );
304 expandAll( mTree->invisibleRootItem() );
305 mBlockChangedSignals--;
312 const QModelIndex selectedIndex = mManagerProxyModel->mapToSource( mManagerProxyModel->index( mSetComboBox->currentIndex(), 0 ) );
316 set.
setName( mManagerModel->data( selectedIndex, Qt::DisplayRole ).toString() );
320 for (
auto it = mItems.begin(); it != mItems.end(); it++ )
322 if ( it.value()->checkState( 0 ) == Qt::Checked )
326 const bool isLabeling = ref.
layerId().startsWith(
"__labels__" );
347 mBlockChangedSignals++;
348 for (
auto it = mItems.begin(); it != mItems.end(); it++ )
350 it.value()->setCheckState( 0, Qt::Unchecked );
353 const QVector< QgsSelectiveMaskSource > sources = set.
sources();
357 switch ( source.sourceType() )
360 layerId = source.layerId();
363 layerId = u
"__labels__%1"_s.arg( source.layerId() );
367 if ( it != mItems.end() )
369 it.value()->setCheckState( 0, Qt::Checked );
374 mSetComboBox->setCurrentIndex( 0 );
378 mSetComboBox->setCurrentIndex( mSetComboBox->findText( set.
name() ) );
380 mBlockChangedSignals--;
383void QgsMaskSourceSelectionWidget::selectedSetChanged()
385 mBlockChangedSignals++;
386 if ( !isCustomSet() )
388 const QModelIndex selectedIndex = mManagerProxyModel->mapToSource( mManagerProxyModel->index( mSetComboBox->currentIndex(), 0 ) );
393 mBlockChangedSignals--;
398void QgsMaskSourceSelectionWidget::emitChanged()
400 if ( !mBlockChangedSignals )
406void QgsMaskSourceSelectionWidget::onItemChanged()
408 if ( mBlockChangedSignals )
411 if ( !isCustomSet() )
413 const QgsSelectiveMaskingSourceSet set =
sourceSet();
419void QgsMaskSourceSelectionWidget::newSet()
423 QStringList existingNames;
425 existingNames.reserve( sets.size() );
426 for (
const QgsSelectiveMaskingSourceSet &set : sets )
428 existingNames << set.
name();
431 QgsNewNameDialog dlg( tr(
"selective masking set" ), newTitle, QStringList(), existingNames, Qt::CaseSensitive,
this );
432 dlg.setWindowTitle( tr(
"Create Selective Masking Set" ) );
433 dlg.setHintString( tr(
"Enter a unique selective masking set name" ) );
434 dlg.setOverwriteEnabled(
false );
435 dlg.setAllowEmptyName(
false );
436 dlg.setConflictingNameWarning( tr(
"A masking set with this name already exists." ) );
438 if ( dlg.exec() != QDialog::Accepted )
443 QgsSelectiveMaskingSourceSet newSet;
444 newSet.setName( dlg.name() );
446 mSetComboBox->setCurrentIndex( mSetComboBox->findText( newSet.name() ) );
449void QgsMaskSourceSelectionWidget::removeSet()
454 const QString setName = mSetComboBox->currentText();
455 if ( QMessageBox::warning(
this, tr(
"Remove Selective Masking Set" ), tr(
"Do you really want to remove the selective masking set “%1”?" ).arg( setName ), QMessageBox::Ok | QMessageBox::Cancel )
461 mSetComboBox->setCurrentIndex( 0 );
465void QgsMaskSourceSelectionWidget::renameSet()
470 const QString setName = mSetComboBox->currentText();
472 QStringList existingNames;
474 existingNames.reserve( sets.size() );
475 for (
const QgsSelectiveMaskingSourceSet &set : sets )
477 if ( set.
name() != setName )
478 existingNames << set.
name();
481 QgsNewNameDialog dlg( tr(
"selective masking set" ), setName, QStringList(), existingNames, Qt::CaseSensitive,
this );
482 dlg.setWindowTitle( tr(
"Rename Selective Masking Set" ) );
483 dlg.setHintString( tr(
"Enter a unique selective masking set name" ) );
484 dlg.setOverwriteEnabled(
false );
485 dlg.setAllowEmptyName(
false );
486 dlg.setConflictingNameWarning( tr(
"A masking set with this name already exists." ) );
488 if ( dlg.exec() != QDialog::Accepted )
496bool QgsMaskSourceSelectionWidget::isCustomSet()
const
498 const QModelIndex selectedIndex = mManagerProxyModel->mapToSource( mManagerProxyModel->index( mSetComboBox->currentIndex(), 0 ) );
@ Label
A mask generated from a labeling provider.
@ SymbolLayer
A mask generated from a symbol layer.
@ 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.
Struct for storing maximum and minimum scales for measurements in map units.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
const QgsSelectiveMaskingSourceSetManager * selectiveMaskingSourceSetManager() const
Returns the project's selective masking set manager, which manages storage of a set of selective mask...
Stores properties relating to a screen.
Encapsulates a single source for selective masking (e.g.
void setSourceId(const QString &id)
Sets the symbol layer or label rule id.
void setLayerId(const QString &id)
Sets the source layer id.
void setSourceType(Qgis::SelectiveMaskSourceType type)
Sets the source type.
List model representing the selective masking source sets available in a selective masking source set...
QVariant data(const QModelIndex &index, int role) const override
@ IsEmptyObject
true if row represents the empty object
@ SetId
Selective masking source set unique ID.
QSortFilterProxyModel subclass for QgsSelectiveMaskingSourceSetManagerModel.
bool renameSet(const QString &oldName, const QString &newName)
Renames a set in the manager from oldName to newName.
QVector< QgsSelectiveMaskingSourceSet > sets() const
Returns a list of all sets contained in the manager.
QgsSelectiveMaskingSourceSet setById(const QString &id) const
Returns the set with a matching id, or an invalid set if no matching sets were found.
bool addSet(const QgsSelectiveMaskingSourceSet &set)
Adds a set to the manager.
QString generateUniqueTitle() const
Generates a unique title for a new set, which does not clash with any already contained by the manage...
bool removeSet(const QString &name)
Removes the set with matching name from the manager.
bool updateSet(const QgsSelectiveMaskingSourceSet &set)
Updates the definition of a set already in the manager.
Represents a named set of selective masking sources (QgsSelectiveMaskSource).
void setName(const QString &name)
Sets the set's unique name.
void setId(const QString &id)
Sets the unique identifier for the set.
QVector< QgsSelectiveMaskSource > sources() const
Returns the list of selective mask sources configured in this set.
void append(const QgsSelectiveMaskSource &source)
Appends a source to the set.
QString name() const
Returns the set's unique name.
bool isValid() const
Returns true if the source set is valid, or false if it is invalid (default constructed).
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.
A symbol entity for QgsStyle databases.
@ LabelSettingsEntity
Label settings.
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.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
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,...
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.