29#include "moc_qgssymbolselectordialog.cpp"
31using namespace Qt::StringLiterals;
46#include <QColorDialog>
48#include <QInputDialog>
68 mDDSize = mMarker->dataDefinedSize();
69 mDDAngle = mMarker->dataDefinedAngle();
71 if ( !mDDSize && !mDDAngle )
78 mDDWidth = mLine->dataDefinedWidth();
86void DataDefinedRestorer::save()
90 mSize = mMarkerSymbolLayer->size();
91 mAngle = mMarkerSymbolLayer->angle();
92 mMarkerOffset = mMarkerSymbolLayer->offset();
96 mWidth = mLineSymbolLayer->width();
97 mLineOffset = mLineSymbolLayer->offset();
101void DataDefinedRestorer::restore()
103 if ( mMarker && mMarker->symbolLayerCount() > 1 )
105 if ( mDDSize && ( mSize != mMarkerSymbolLayer->size() || mMarkerOffset != mMarkerSymbolLayer->offset() ) )
106 mMarker->setDataDefinedSize( mDDSize );
107 if ( mDDAngle && mAngle != mMarkerSymbolLayer->angle() )
108 mMarker->setDataDefinedAngle( mDDAngle );
110 else if ( mLine && mLine->symbolLayerCount() > 1 )
112 if ( mDDWidth && ( mWidth != mLineSymbolLayer->width() || mLineOffset != mLineSymbolLayer->offset() ) )
113 mLine->setDataDefinedWidth( mDDWidth );
129 setWindowModality( Qt::WindowModal );
133 this->layout()->setContentsMargins( 0, 0, 0, 0 );
135 layersTree->setMaximumHeight(
static_cast<int>(
Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 7 ) );
136 layersTree->setMinimumHeight( layersTree->maximumHeight() );
137 lblPreview->setMaximumWidth( layersTree->maximumHeight() );
151 iconColorLock.addFile(
QgsApplication::iconPath( u
"mIconColorUnlocked.svg"_s ), QSize(), QIcon::Normal, QIcon::Off );
152 iconColorLock.addFile(
QgsApplication::iconPath( u
"mIconColorUnlocked.svg"_s ), QSize(), QIcon::Active, QIcon::Off );
154 mLockColorAction =
new QAction( tr(
"Lock Color" ),
this );
155 mLockColorAction->setToolTip( tr(
"Avoid changing the color of the layer when the symbol color is changed" ) );
156 mLockColorAction->setCheckable(
true );
157 mLockColorAction->setIcon( iconColorLock );
159 QIcon iconSelectLock;
160 iconSelectLock.addFile(
QgsApplication::iconPath( u
"mIconSelectLocked.svg"_s ), QSize(), QIcon::Normal, QIcon::On );
161 iconSelectLock.addFile(
QgsApplication::iconPath( u
"mIconSelectLocked.svg"_s ), QSize(), QIcon::Active, QIcon::On );
162 iconSelectLock.addFile(
QgsApplication::iconPath( u
"mIconSelectUnlocked.svg"_s ), QSize(), QIcon::Normal, QIcon::Off );
163 iconSelectLock.addFile(
QgsApplication::iconPath( u
"mIconSelectUnlocked.svg"_s ), QSize(), QIcon::Active, QIcon::Off );
165 mLockSelectionColorAction =
new QAction( tr(
"Lock Color When Selected" ),
this );
166 mLockSelectionColorAction->setToolTip( tr(
"Avoid changing the color of the layer when a feature is selected" ) );
167 mLockSelectionColorAction->setCheckable(
true );
168 mLockSelectionColorAction->setIcon( iconSelectLock );
170 QMenu *lockMenu =
new QMenu(
this );
171 lockMenu->addAction( mLockColorAction );
172 lockMenu->addAction( mLockSelectionColorAction );
173 btnLock->setMenu( lockMenu );
174 btnLock->setPopupMode( QToolButton::InstantPopup );
181 connect( mSymbolLayersModel, &QAbstractItemModel::dataChanged,
this, &QgsSymbolSelectorWidget::modelDataChanged );
184 layersTree->setModel( mSymbolLayersModel );
185 layersTree->setHeaderHidden(
true );
187 layersTree->setStyleSheet( u
"QTreeView::indicator:indeterminate {background: transparent; border: none; }"_s );
199 mPreviewExpressionContext.setFeature( mPreviewFeature );
207 QItemSelectionModel *selModel = layersTree->selectionModel();
210 mSymbolLayersModel->setSymbol( mSymbol );
212 layersTree->expandAll();
220 connect( mLockSelectionColorAction, &QAction::toggled,
this, [
this](
bool checked ) {
228 updateLockButtonIcon();
234 updateLockButtonIcon();
239 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
240 layersTree->setCurrentIndex( newIndex );
273 widget->mOwnedSymbol = std::move(
symbol );
279 if ( !mAdvancedMenu )
281 mAdvancedMenu =
new QMenu(
this );
285 return mAdvancedMenu;
292 if (
auto *lExpressionContext = mContext.expressionContext() )
294 mPreviewExpressionContext = *lExpressionContext;
298 mPreviewExpressionContext.setFeature( mPreviewFeature );
301 QWidget *widget = stackedWidget->currentWidget();
304 layerProp->setContext(
context );
308 listWidget->setContext(
context );
329void QgsSymbolSelectorWidget::reloadSymbol()
331 mSymbolLayersModel->
setSymbol( mSymbol );
332 layersTree->expandAll();
335void QgsSymbolSelectorWidget::updateUi()
337 QgsSymbolLayerModelNode *node = currentNode();
343 btnUp->setEnabled(
false );
344 btnDown->setEnabled(
false );
345 btnRemoveLayer->setEnabled(
false );
346 btnLock->setEnabled(
false );
347 btnDuplicate->setEnabled(
false );
352 const int currentRow = node->
rowIndex();
354 btnUp->setEnabled( currentRow > 0 );
355 btnDown->setEnabled( currentRow < rowCount - 1 );
356 btnRemoveLayer->setEnabled( rowCount > 1 );
357 btnLock->setEnabled(
true );
358 btnDuplicate->setEnabled(
true );
366 std::unique_ptr<QgsSymbol> symbolClone( mSymbol->clone() );
368 lblPreview->setPixmap( QPixmap::fromImage( preview ) );
377 mSymbolLayersModel->updatePreviewIcons( node );
385 if ( !node || !node->
isLayer() )
393 QgsSymbolLayerModelNode *node = currentLayerNode();
394 return node ? node->
layer() :
nullptr;
399 const QModelIndex idx = layersTree->currentIndex();
400 if ( !idx.isValid() )
403 return mSymbolLayersModel->index2node( idx );
417 mDataDefineRestorer = std::make_unique<DataDefinedRestorer>( parent->
symbol(), node->
layer() );
421 setWidget( layerProp );
433 mDataDefineRestorer.reset();
439 symbolsList->setContext( mContext );
441 setWidget( symbolsList );
450 if ( !node || node->
isLayer() )
461 mSymbolLayersModel->updateNode(
symbol, parent );
463 layersTree->expandRecursively( mSymbolLayersModel->node2index( parent->
childAt( 0 ) ) );
464 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( parent->
childAt( 0 ) ) );
470 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
471 layersTree->setCurrentIndex( newIndex );
474 emitSymbolModified();
479void QgsSymbolSelectorWidget::setWidget( QWidget *widget )
481 const int index = stackedWidget->addWidget( widget );
482 stackedWidget->setCurrentIndex( index );
483 if ( mPresentWidget )
484 mPresentWidget->deleteLater();
485 mPresentWidget = widget;
488void QgsSymbolSelectorWidget::updateLockButton()
490 QgsSymbolLayer *layer = currentLayer();
493 mLockColorAction->setChecked( layer->
isLocked() );
496 updateLockButtonIcon();
499void QgsSymbolSelectorWidget::updateLockButtonIcon()
501 if ( mLockColorAction->isChecked() && mLockSelectionColorAction->isChecked() )
503 else if ( mLockColorAction->isChecked() )
505 else if ( mLockSelectionColorAction->isChecked() )
513 const QModelIndex idx = layersTree->currentIndex();
517 layersTree->expandRecursively( mSymbolLayersModel->node2index( newNode ) );
518 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( newNode ) );
521 emitSymbolModified();
530 mSymbolLayersModel->removeLayer( node );
534 emitSymbolModified();
539 moveLayerByOffset( +1 );
544 moveLayerByOffset( -1 );
547void QgsSymbolSelectorWidget::moveLayerByOffset(
int offset )
555 layersTree->setCurrentIndex( mSymbolLayersModel->
node2index( node ) );
558 emitSymbolModified();
567 layer->
setLocked( mLockColorAction->isChecked() );
568 updateLockButtonIcon();
582 layersTree->expandRecursively( mSymbolLayersModel->node2index( newNode ) );
583 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( newNode ) );
588 emitSymbolModified();
595 mSymbolLayersModel->changeLayer( node, newLayer );
597 QModelIndex nodeIndex = mSymbolLayersModel->node2index( node );
598 layersTree->expandRecursively( nodeIndex );
599 layersTree->setCurrentIndex( nodeIndex );
602 emitSymbolModified();
607void QgsSymbolSelectorWidget::updateListIcons()
609 mSymbolLayersModel->
setScreen( screen() );
616 setLayout(
new QVBoxLayout() );
619 mButtonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
621 connect( mButtonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
622 connect( mButtonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject );
623 connect( mButtonBox, &QDialogButtonBox::helpRequested,
this, &QgsSymbolSelectorDialog::showHelp );
625 layout()->addWidget( mSelectorWidget );
626 layout()->addWidget( mButtonBox );
630 mSelectorWidget->setMinimumSize( 460, 560 );
631 setObjectName( u
"SymbolSelectorDialog"_s );
638 layout()->setContentsMargins( 0, 0, 0, 0 );
642 setWindowTitle( tr(
"Symbol Selector" ) );
644 mSelectorWidget->setDockMode( embedded );
649 return mSelectorWidget->advancedMenu();
654 mSelectorWidget->setContext(
context );
659 return mSelectorWidget->context();
664 return mSelectorWidget->symbol();
670 if ( !isWindow() && e->key() == Qt::Key_Escape )
676 QDialog::keyPressEvent( e );
680void QgsSymbolSelectorDialog::reloadSymbol()
682 mSelectorWidget->reloadSymbol();
687 mSelectorWidget->loadSymbol(
symbol );
690void QgsSymbolSelectorDialog::updateUi()
692 mSelectorWidget->updateUi();
695void QgsSymbolSelectorDialog::updateLockButton()
697 mSelectorWidget->updateLockButton();
702 return mSelectorWidget->currentLayerNode();
707 return mSelectorWidget->currentLayer();
710void QgsSymbolSelectorDialog::moveLayerByOffset(
int offset )
712 mSelectorWidget->moveLayerByOffset( offset );
715void QgsSymbolSelectorDialog::setWidget( QWidget *widget )
717 mSelectorWidget->setWidget( widget );
722 mSelectorWidget->moveLayerDown();
727 mSelectorWidget->moveLayerUp();
732 mSelectorWidget->addLayer();
737 mSelectorWidget->removeLayer();
742 mSelectorWidget->lockLayer();
747 mSelectorWidget->duplicateLayer();
752 mSelectorWidget->layerChanged();
757 mSelectorWidget->updateLayerPreview();
762 mSelectorWidget->updatePreview();
767 mSelectorWidget->symbolChanged();
772 mSelectorWidget->changeLayer( layer );
780void QgsSymbolSelectorDialog::showHelp()
785void QgsSymbolSelectorWidget::projectDataChanged()
787 mBlockModified =
true;
790 mBlockModified =
false;
793void QgsSymbolSelectorWidget::modelDataChanged(
const QModelIndex &,
const QModelIndex &,
const QList<int> &roles )
795 if ( roles.contains( Qt::CheckStateRole ) )
797 emitSymbolModified();
803void QgsSymbolSelectorWidget::layersAboutToBeRemoved(
const QList<QgsMapLayer *> &layers )
805 if ( mVectorLayer && layers.contains( mVectorLayer ) )
811void QgsSymbolSelectorWidget::emitSymbolModified()
813 if ( !mBlockModified )
QFlags< SymbolLayerUserFlag > SymbolLayerUserFlags
Symbol layer user flags.
@ FlagIncludeCrosshairsForMarkerSymbols
Include a crosshairs reference image in the background of marker symbol previews.
@ DisableSelectionRecoloring
If present, indicates that the symbol layer should not be recolored when rendering selected features.
static const double UI_SCALE_FACTOR
UI scaling factor.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
static QgsSvgCache * svgCache()
Returns the application's SVG cache, used for caching SVG images and handling parameter replacement w...
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
void remoteImageFetched(const QString &url)
Emitted when the cache has finished retrieving an image file from a remote url.
Abstract base class for line symbol layers.
A line symbol type, for rendering LineString and MultiLineString geometries.
Abstract base class for marker symbol layers.
A marker symbol type, for rendering Point and MultiPoint geometries.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
static QgsProject * instance()
Returns the QgsProject singleton instance.
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
A utility class for dynamic handling of changes to screen properties.
void screenDpiChanged(double dpi)
Emitted whenever the screen dpi associated with the widget is changed.
Stores properties relating to a screen.
A database of saved style entities, including symbols, color ramps, text formats and others.
void remoteSvgFetched(const QString &url)
Emitted when the cache has finished retrieving an SVG file from a remote url.
A node contained within a QgsSymbolLayerModel.
QgsSymbolLayerModelNode * parent()
Returns the pointer of the parent node. If parent is nullptr, the node is a root node.
QgsSymbol * symbol()
Returns the symbol pointer; helpful in determining a layer's parent symbol.
QgsSymbolLayer * layer()
Returns the symbol layer pointer.
int rowCount() const
Returns the number of rows(children) belonging to the node.
QgsSymbolLayerModelNode * childAt(int index) const
Returns the child node at the given index.
int rowIndex() const
Returns the row index of the node within its parent.
bool isRootNode() const
Returns true if the node is a root node (i.e. has no parent).
bool isLayer() const
Returns true if the node is a symbol layer. And otherwise, it is a symbol.
A QAbstractItemModel subclass for displaying a QgsSymbol in a tree view in the symbology panel.
void moveLayerByOffset(QgsSymbolLayerModelNode *node, int offset)
Moves the symbol layer node by the offset in the parent hierarchy.
QModelIndex node2index(QgsSymbolLayerModelNode *node) const
Returns the model index corresponding to the given node.
void setSymbol(QgsSymbol *symbol)
Sets the symbol associated with the model.
void setScreen(QScreen *screen)
Set the QScreen of the model itself.
Abstract base class for symbol layers.
Qgis::SymbolType type() const
bool isLocked() const
Returns true if the symbol layer colors are locked and the layer will ignore any symbol-level color c...
void setUserFlags(Qgis::SymbolLayerUserFlags flags)
Sets user-controlled flags which control the symbol layer's behavior.
Qgis::SymbolLayerUserFlags userFlags() const
Returns user-controlled flags which control the symbol layer's behavior.
void setLocked(bool locked)
Sets whether the layer's colors are locked.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsSymbolSelectorDialog(QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr, bool embedded=false)
Constructor for QgsSymbolSelectorDialog.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
QMenu * advancedMenu()
Returns menu for "advanced" button - create it if doesn't exist and show the advanced button.
void symbolChanged()
Slot to update tree when a new symbol from style.
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog's button box.
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void keyPressEvent(QKeyEvent *e) override
void loadSymbol(QgsSymbol *symbol)
Loads the given symbol into the widget.
void updateLayerPreview()
void duplicateLayer()
Duplicates the current symbol layer and places the duplicated layer above the current symbol layer.
void changeLayer(QgsSymbolLayer *layer)
Alters tree and sets proper widget when Layer Type is changed.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
Abstract base class for all rendered symbols.
Qgis::SymbolType type() const
Returns the symbol's type.
Q_DECL_DEPRECATED void setLayer(const QgsVectorLayer *layer)
Sets the vector layer associated with the symbol.
Represents a vector layer which manages a vector based dataset.
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH