QGIS API Documentation 4.3.0-Master (3b7b3208a79)
Loading...
Searching...
No Matches
qgssymbolselectordialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgssymbolselectordialog.cpp
3 ---------------------
4 begin : November 2009
5 copyright : (C) 2009 by Martin Dobias
6 email : wonder dot sk at gmail 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
17
19#include "qgsscreenhelper.h"
20#include "qgsstyle.h"
21#include "qgssymbol.h"
22#include "qgssymbollayer.h"
23#include "qgssymbollayermodel.h"
25#include "qgssymbollayerutils.h"
26
27#include <QString>
28
29#include "moc_qgssymbolselectordialog.cpp"
30
31using namespace Qt::StringLiterals;
32
33// the widgets
36#include "qgsapplication.h"
37#include "qgsvectorlayer.h"
38#include "qgssvgcache.h"
39#include "qgsimagecache.h"
40#include "qgsproject.h"
41#include "qgsgui.h"
42#include "qgsmarkersymbol.h"
43#include "qgslinesymbol.h"
44#include "qscreen.h"
45
46#include <QColorDialog>
47#include <QPainter>
48#include <QInputDialog>
49#include <QMessageBox>
50#include <QKeyEvent>
51#include <QMenu>
52
53#include <QWidget>
54#include <QFile>
55#include <memory>
56
58
59
60DataDefinedRestorer::DataDefinedRestorer( QgsSymbol *symbol, const QgsSymbolLayer *symbolLayer )
61
62{
63 if ( symbolLayer->type() == Qgis::SymbolType::Marker && symbol->type() == Qgis::SymbolType::Marker )
64 {
65 Q_ASSERT( symbol->type() == Qgis::SymbolType::Marker );
66 mMarker = static_cast<QgsMarkerSymbol *>( symbol );
67 mMarkerSymbolLayer = static_cast<const QgsMarkerSymbolLayer *>( symbolLayer );
68 mDDSize = mMarker->dataDefinedSize();
69 mDDAngle = mMarker->dataDefinedAngle();
70 // check if restore is actually needed
71 if ( !mDDSize && !mDDAngle )
72 mMarker = nullptr;
73 }
74 else if ( symbolLayer->type() == Qgis::SymbolType::Line && symbol->type() == Qgis::SymbolType::Line )
75 {
76 mLine = static_cast<QgsLineSymbol *>( symbol );
77 mLineSymbolLayer = static_cast<const QgsLineSymbolLayer *>( symbolLayer );
78 mDDWidth = mLine->dataDefinedWidth();
79 // check if restore is actually needed
80 if ( !mDDWidth )
81 mLine = nullptr;
82 }
83 save();
84}
85
86void DataDefinedRestorer::save()
87{
88 if ( mMarker )
89 {
90 mSize = mMarkerSymbolLayer->size();
91 mAngle = mMarkerSymbolLayer->angle();
92 mMarkerOffset = mMarkerSymbolLayer->offset();
93 }
94 else if ( mLine )
95 {
96 mWidth = mLineSymbolLayer->width();
97 mLineOffset = mLineSymbolLayer->offset();
98 }
99}
100
101void DataDefinedRestorer::restore()
102{
103 if ( mMarker && mMarker->symbolLayerCount() > 1 )
104 {
105 if ( mDDSize && ( mSize != mMarkerSymbolLayer->size() || mMarkerOffset != mMarkerSymbolLayer->offset() ) )
106 mMarker->setDataDefinedSize( mDDSize );
107 if ( mDDAngle && mAngle != mMarkerSymbolLayer->angle() )
108 mMarker->setDataDefinedAngle( mDDAngle );
109 }
110 else if ( mLine && mLine->symbolLayerCount() > 1 )
111 {
112 if ( mDDWidth && ( mWidth != mLineSymbolLayer->width() || mLineOffset != mLineSymbolLayer->offset() ) )
113 mLine->setDataDefinedWidth( mDDWidth );
114 }
115 save();
116}
117
119
121
123 : QgsPanelWidget( parent )
124 , mStyle( style )
125 , mSymbol( symbol )
126 , mVectorLayer( vl )
127{
128#ifdef Q_OS_MAC
129 setWindowModality( Qt::WindowModal );
130#endif
131
132 setupUi( this );
133 this->layout()->setContentsMargins( 0, 0, 0, 0 );
134
135 layersTree->setMaximumHeight( static_cast<int>( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 7 ) );
136 layersTree->setMinimumHeight( layersTree->maximumHeight() );
137 lblPreview->setMaximumWidth( layersTree->maximumHeight() );
138
139 // setup icons
140 btnAddLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
141 btnRemoveLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
142 QIcon iconLock;
143 iconLock.addFile( QgsApplication::iconPath( u"locked.svg"_s ), QSize(), QIcon::Normal, QIcon::On );
144 iconLock.addFile( QgsApplication::iconPath( u"locked.svg"_s ), QSize(), QIcon::Active, QIcon::On );
145 iconLock.addFile( QgsApplication::iconPath( u"unlocked.svg"_s ), QSize(), QIcon::Normal, QIcon::Off );
146 iconLock.addFile( QgsApplication::iconPath( u"unlocked.svg"_s ), QSize(), QIcon::Active, QIcon::Off );
147
148 QIcon iconColorLock;
149 iconColorLock.addFile( QgsApplication::iconPath( u"mIconColorLocked.svg"_s ), QSize(), QIcon::Normal, QIcon::On );
150 iconColorLock.addFile( QgsApplication::iconPath( u"mIconColorLocked.svg"_s ), QSize(), QIcon::Active, QIcon::On );
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 );
153
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 );
158
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 );
164
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 );
169
170 QMenu *lockMenu = new QMenu( this );
171 lockMenu->addAction( mLockColorAction );
172 lockMenu->addAction( mLockSelectionColorAction );
173 btnLock->setMenu( lockMenu );
174 btnLock->setPopupMode( QToolButton::InstantPopup );
175
176 btnDuplicate->setIcon( QIcon( QgsApplication::iconPath( "mActionDuplicateLayer.svg" ) ) );
177 btnUp->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
178 btnDown->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
179
180 mSymbolLayersModel = new QgsSymbolLayerModel( mVectorLayer, layersTree, screen() );
181 connect( mSymbolLayersModel, &QAbstractItemModel::dataChanged, this, &QgsSymbolSelectorWidget::modelDataChanged );
182
183 // Set the symbol
184 layersTree->setModel( mSymbolLayersModel );
185 layersTree->setHeaderHidden( true );
186 // Hide partially checked checkbox, see thread https://github.com/qgis/QGIS/pull/67099#issuecomment-5729627430
187 layersTree->setStyleSheet( u"QTreeView::indicator:indeterminate {background: transparent; border: none; }"_s );
188
189 //get first feature from layer for previews
190 if ( mVectorLayer )
191 {
192#if 0 // this is too expensive to do for many providers. TODO revisit when support for connection timeouts is complete across all providers
193 // short timeout for request - it doesn't really matter if we don't get the feature, and this call is blocking UI
194 QgsFeatureIterator it = mVectorLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ).setConnectionTimeout( 100 ) );
195 it.nextFeature( mPreviewFeature );
196#endif
197 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) );
198#if 0
199 mPreviewExpressionContext.setFeature( mPreviewFeature );
200#endif
201 }
202 else
203 {
204 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
205 }
206
207 QItemSelectionModel *selModel = layersTree->selectionModel();
208 connect( selModel, &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
209
210 mSymbolLayersModel->setSymbol( mSymbol );
211
212 layersTree->expandAll();
214
215 connect( btnUp, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerUp );
216 connect( btnDown, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerDown );
217 connect( btnAddLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::addLayer );
218 connect( btnRemoveLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::removeLayer );
219 connect( mLockColorAction, &QAction::toggled, this, &QgsSymbolSelectorWidget::lockLayer );
220 connect( mLockSelectionColorAction, &QAction::toggled, this, [this]( bool checked ) {
221 QgsSymbolLayer *layer = currentLayer();
222 if ( !layer )
223 return;
224
225 Qgis::SymbolLayerUserFlags flags = layer->userFlags();
227 layer->setUserFlags( flags );
228 updateLockButtonIcon();
229 emit symbolModified();
230 } );
231 connect( btnDuplicate, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::duplicateLayer );
233
234 updateLockButtonIcon();
235
236 updateUi();
237
238 // set symbol as active item in the tree
239 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
240 layersTree->setCurrentIndex( newIndex );
241
242 setPanelTitle( tr( "Symbol Selector" ) );
243
244 // when a remote svg has been fetched, update the widget's previews
245 // this is required if the symbol utilizes remote svgs, and the current previews
246 // have been generated using the temporary "downloading" svg. In this case
247 // we require the preview to be regenerated to use the correct fetched
248 // svg
249 connect( QgsApplication::svgCache(), &QgsSvgCache::remoteSvgFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
250
251 // when a remote image has been fetched, update the widget's previews
252 // this is required if the symbol utilizes remote images, and the current previews
253 // have been generated using the temporary "downloading" image. In this case
254 // we require the preview to be regenerated to use the correct fetched
255 // image
256 connect( QgsApplication::imageCache(), &QgsImageCache::remoteImageFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
257
258 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
259 // need updating to reflect the new colors
260 connect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
261
262 connect( QgsProject::instance(), static_cast<void ( QgsProject::* )( const QList<QgsMapLayer *> &layers )>( &QgsProject::layersWillBeRemoved ), this, &QgsSymbolSelectorWidget::layersAboutToBeRemoved );
263
264 auto screenHelper = new QgsScreenHelper( this );
266 connect( screenHelper, &QgsScreenHelper::screenDpiChanged, this, &QgsSymbolSelectorWidget::updateListIcons );
267}
268
270{
271 QgsSymbolSelectorWidget *widget = new QgsSymbolSelectorWidget( symbol.get(), style, vl, parent );
272 // transfer ownership of symbol to widget, so that we are guaranteed it will last for the duration of the widget
273 widget->mOwnedSymbol = std::move( symbol );
274 return widget;
275}
276
278{
279 if ( !mAdvancedMenu )
280 {
281 mAdvancedMenu = new QMenu( this );
282 // Brute force method to activate the Advanced menu
283 layerChanged();
284 }
285 return mAdvancedMenu;
286}
287
289{
290 mContext = context;
291
292 if ( auto *lExpressionContext = mContext.expressionContext() )
293 {
294 mPreviewExpressionContext = *lExpressionContext;
295 if ( mVectorLayer )
296 mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
297
298 mPreviewExpressionContext.setFeature( mPreviewFeature );
299 }
300
301 QWidget *widget = stackedWidget->currentWidget();
302 if ( QgsLayerPropertiesWidget *layerProp = qobject_cast<QgsLayerPropertiesWidget *>( widget ) )
303 {
304 layerProp->setContext( context );
305 }
306 else if ( QgsSymbolsListWidget *listWidget = qobject_cast<QgsSymbolsListWidget *>( widget ) )
307 {
308 listWidget->setContext( context );
309 }
310
311 layerChanged();
313}
314
316{
317 return mContext;
318}
319
321{
322 if ( !symbol )
323 return;
324
325 mSymbol = symbol;
326 reloadSymbol();
327}
328
329void QgsSymbolSelectorWidget::reloadSymbol()
330{
331 mSymbolLayersModel->setSymbol( mSymbol );
332 layersTree->expandAll();
333}
334
335void QgsSymbolSelectorWidget::updateUi()
336{
337 QgsSymbolLayerModelNode *node = currentNode();
338 if ( !node )
339 return;
340
341 if ( !node->isLayer() )
342 {
343 btnUp->setEnabled( false );
344 btnDown->setEnabled( false );
345 btnRemoveLayer->setEnabled( false );
346 btnLock->setEnabled( false );
347 btnDuplicate->setEnabled( false );
348 return;
349 }
350
351 const int rowCount = node->parent()->rowCount();
352 const int currentRow = node->rowIndex();
353
354 btnUp->setEnabled( currentRow > 0 );
355 btnDown->setEnabled( currentRow < rowCount - 1 );
356 btnRemoveLayer->setEnabled( rowCount > 1 );
357 btnLock->setEnabled( true );
358 btnDuplicate->setEnabled( true );
359}
360
362{
363 if ( !mSymbol )
364 return;
365
366 std::unique_ptr<QgsSymbol> symbolClone( mSymbol->clone() );
367 const QImage preview = symbolClone->bigSymbolPreviewImage( &mPreviewExpressionContext, Qgis::SymbolPreviewFlag::FlagIncludeCrosshairsForMarkerSymbols, QgsScreenProperties( screen() ) );
368 lblPreview->setPixmap( QPixmap::fromImage( preview ) );
369}
370
372{
373 // get current layer item and update its icon
374
375 QgsSymbolLayerModelNode *node = currentLayerNode();
376 if ( node )
377 mSymbolLayersModel->updatePreviewIcons( node );
378 // update also preview of the whole symbol
380}
381
382QgsSymbolLayerModelNode *QgsSymbolSelectorWidget::currentLayerNode()
383{
384 QgsSymbolLayerModelNode *node = currentNode();
385 if ( !node || !node->isLayer() )
386 return nullptr;
387
388 return node;
389}
390
391QgsSymbolLayer *QgsSymbolSelectorWidget::currentLayer()
392{
393 QgsSymbolLayerModelNode *node = currentLayerNode();
394 return node ? node->layer() : nullptr;
395}
396
397QgsSymbolLayerModelNode *QgsSymbolSelectorWidget::currentNode()
398{
399 const QModelIndex idx = layersTree->currentIndex();
400 if ( !idx.isValid() )
401 return nullptr;
402
403 return mSymbolLayersModel->index2node( idx );
404}
405
407{
408 updateUi();
409
410 QgsSymbolLayerModelNode *node = currentNode();
411 if ( !node )
412 return;
413
414 if ( node->isLayer() )
415 {
416 QgsSymbolLayerModelNode *parent = node->parent();
417 mDataDefineRestorer = std::make_unique<DataDefinedRestorer>( parent->symbol(), node->layer() );
418 QgsLayerPropertiesWidget *layerProp = new QgsLayerPropertiesWidget( node->layer(), parent->symbol(), mVectorLayer );
419 layerProp->setDockMode( this->dockMode() );
420 layerProp->setContext( mContext );
421 setWidget( layerProp );
422 connect( layerProp, &QgsLayerPropertiesWidget::changed, mDataDefineRestorer.get(), &DataDefinedRestorer::restore );
424 connect( layerProp, &QgsLayerPropertiesWidget::changed, this, &QgsSymbolSelectorWidget::emitSymbolModified );
425 // This connection when layer type is changed
427
428 connectChildPanel( layerProp );
429 }
430 else
431 {
432 // then it must be a symbol
433 mDataDefineRestorer.reset();
435 node->symbol()->setLayer( mVectorLayer );
437 // Now populate symbols of that type using the symbols list widget:
438 QgsSymbolsListWidget *symbolsList = new QgsSymbolsListWidget( node->symbol(), mStyle, mAdvancedMenu, this, mVectorLayer );
439 symbolsList->setContext( mContext );
440
441 setWidget( symbolsList );
443 }
444 updateLockButton();
445}
446
448{
449 QgsSymbolLayerModelNode *node = currentNode();
450 if ( !node || node->isLayer() )
451 return;
452 // disconnect to avoid recreating widget
453 disconnect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
454 if ( node->parent() && !node->parent()->isRootNode() )
455 {
456 // it is a sub-symbol
457
458 QgsSymbol *symbol = node->symbol();
459 QgsSymbolLayerModelNode *parent = node->parent();
460
461 mSymbolLayersModel->updateNode( symbol, parent );
462
463 layersTree->expandRecursively( mSymbolLayersModel->node2index( parent->childAt( 0 ) ) );
464 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( parent->childAt( 0 ) ) );
465 }
466 else
467 {
468 //it is the symbol itself
469 reloadSymbol();
470 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
471 layersTree->setCurrentIndex( newIndex );
472 }
474 emitSymbolModified();
475 // connect it back once things are set
476 connect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
477}
478
479void QgsSymbolSelectorWidget::setWidget( QWidget *widget )
480{
481 const int index = stackedWidget->addWidget( widget );
482 stackedWidget->setCurrentIndex( index );
483 if ( mPresentWidget )
484 mPresentWidget->deleteLater();
485 mPresentWidget = widget;
486}
487
488void QgsSymbolSelectorWidget::updateLockButton()
489{
490 QgsSymbolLayer *layer = currentLayer();
491 if ( !layer )
492 return;
493 mLockColorAction->setChecked( layer->isLocked() );
494 mLockSelectionColorAction->setChecked( layer->userFlags() & Qgis::SymbolLayerUserFlag::DisableSelectionRecoloring );
495
496 updateLockButtonIcon();
497}
498
499void QgsSymbolSelectorWidget::updateLockButtonIcon()
500{
501 if ( mLockColorAction->isChecked() && mLockSelectionColorAction->isChecked() )
502 btnLock->setIcon( QgsApplication::getThemeIcon( u"locked.svg"_s ) );
503 else if ( mLockColorAction->isChecked() )
504 btnLock->setIcon( QgsApplication::getThemeIcon( u"mIconColorLocked.svg"_s ) );
505 else if ( mLockSelectionColorAction->isChecked() )
506 btnLock->setIcon( QgsApplication::getThemeIcon( u"mIconSelectLocked.svg"_s ) );
507 else
508 btnLock->setIcon( QgsApplication::getThemeIcon( u"unlocked.svg"_s ) );
509}
510
512{
513 const QModelIndex idx = layersTree->currentIndex();
514
515 QgsSymbolLayerModelNode *newNode = mSymbolLayersModel->addLayer( idx );
516
517 layersTree->expandRecursively( mSymbolLayersModel->node2index( newNode ) );
518 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( newNode ) );
519 updateUi();
521 emitSymbolModified();
522}
523
525{
526 QgsSymbolLayerModelNode *node = currentLayerNode();
527 if ( !node )
528 return;
529
530 mSymbolLayersModel->removeLayer( node );
531
532 updateUi();
534 emitSymbolModified();
535}
536
538{
539 moveLayerByOffset( +1 );
540}
541
543{
544 moveLayerByOffset( -1 );
545}
546
547void QgsSymbolSelectorWidget::moveLayerByOffset( int offset )
548{
549 QgsSymbolLayerModelNode *node = currentLayerNode();
550 if ( !node )
551 return;
552
553 mSymbolLayersModel->moveLayerByOffset( node, offset );
554
555 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( node ) );
556
558 emitSymbolModified();
559 updateUi();
560}
561
563{
564 QgsSymbolLayer *layer = currentLayer();
565 if ( !layer )
566 return;
567 layer->setLocked( mLockColorAction->isChecked() );
568 updateLockButtonIcon();
569 emit symbolModified();
570}
571
573{
574 QgsSymbolLayerModelNode *node = currentLayerNode();
575 if ( !node )
576 return;
577
578 QgsSymbolLayerModelNode *newNode = mSymbolLayersModel->duplicateLayer( node );
579
580 if ( newNode )
581 {
582 layersTree->expandRecursively( mSymbolLayersModel->node2index( newNode ) );
583 layersTree->setCurrentIndex( mSymbolLayersModel->node2index( newNode ) );
584 }
585
586 updateUi();
588 emitSymbolModified();
589}
590
592{
593 QgsSymbolLayerModelNode *node = currentLayerNode();
594
595 mSymbolLayersModel->changeLayer( node, newLayer );
596
597 QModelIndex nodeIndex = mSymbolLayersModel->node2index( node );
598 layersTree->expandRecursively( nodeIndex );
599 layersTree->setCurrentIndex( nodeIndex );
600
602 emitSymbolModified();
603 // Important: This lets the layer have its own layer properties widget
604 layerChanged();
605}
606
607void QgsSymbolSelectorWidget::updateListIcons()
608{
609 mSymbolLayersModel->setScreen( screen() );
610}
611
612
614 : QDialog( parent )
615{
616 setLayout( new QVBoxLayout() );
617
618 mSelectorWidget = new QgsSymbolSelectorWidget( symbol, style, vl, this );
619 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
620
621 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
622 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
623 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsSymbolSelectorDialog::showHelp );
624
625 layout()->addWidget( mSelectorWidget );
626 layout()->addWidget( mButtonBox );
627
628 connect( mSelectorWidget, &QgsPanelWidget::panelAccepted, this, &QDialog::reject );
629
630 mSelectorWidget->setMinimumSize( 460, 560 );
631 setObjectName( u"SymbolSelectorDialog"_s );
633
634 // Can be embedded in renderer properties dialog
635 if ( embedded )
636 {
637 mButtonBox->hide();
638 layout()->setContentsMargins( 0, 0, 0, 0 );
639 }
640 else
641 {
642 setWindowTitle( tr( "Symbol Selector" ) );
643 }
644 mSelectorWidget->setDockMode( embedded );
645}
646
648{
649 return mSelectorWidget->advancedMenu();
650}
651
653{
654 mSelectorWidget->setContext( context );
655}
656
658{
659 return mSelectorWidget->context();
660}
661
663{
664 return mSelectorWidget->symbol();
665}
666
668{
669 // Ignore the ESC key to avoid close the dialog without the properties window
670 if ( !isWindow() && e->key() == Qt::Key_Escape )
671 {
672 e->ignore();
673 }
674 else
675 {
676 QDialog::keyPressEvent( e );
677 }
678}
679
680void QgsSymbolSelectorDialog::reloadSymbol()
681{
682 mSelectorWidget->reloadSymbol();
683}
684
686{
687 mSelectorWidget->loadSymbol( symbol );
688}
689
690void QgsSymbolSelectorDialog::updateUi()
691{
692 mSelectorWidget->updateUi();
693}
694
695void QgsSymbolSelectorDialog::updateLockButton()
696{
697 mSelectorWidget->updateLockButton();
698}
699
700QgsSymbolLayerModelNode *QgsSymbolSelectorDialog::currentLayerNode()
701{
702 return mSelectorWidget->currentLayerNode();
703}
704
705QgsSymbolLayer *QgsSymbolSelectorDialog::currentLayer()
706{
707 return mSelectorWidget->currentLayer();
708}
709
710void QgsSymbolSelectorDialog::moveLayerByOffset( int offset )
711{
712 mSelectorWidget->moveLayerByOffset( offset );
713}
714
715void QgsSymbolSelectorDialog::setWidget( QWidget *widget )
716{
717 mSelectorWidget->setWidget( widget );
718}
719
721{
722 mSelectorWidget->moveLayerDown();
723}
724
726{
727 mSelectorWidget->moveLayerUp();
728}
729
731{
732 mSelectorWidget->addLayer();
733}
734
736{
737 mSelectorWidget->removeLayer();
738}
739
741{
742 mSelectorWidget->lockLayer();
743}
744
746{
747 mSelectorWidget->duplicateLayer();
748}
749
751{
752 mSelectorWidget->layerChanged();
753}
754
756{
757 mSelectorWidget->updateLayerPreview();
758}
759
761{
762 mSelectorWidget->updatePreview();
763}
764
766{
767 mSelectorWidget->symbolChanged();
768}
769
771{
772 mSelectorWidget->changeLayer( layer );
773}
774
775QDialogButtonBox *QgsSymbolSelectorDialog::buttonBox() const
776{
777 return mButtonBox;
778}
779
780void QgsSymbolSelectorDialog::showHelp()
781{
782 QgsHelp::openHelp( u"style_library/symbol_selector.html"_s );
783}
784
785void QgsSymbolSelectorWidget::projectDataChanged()
786{
787 mBlockModified = true;
790 mBlockModified = false;
791}
792
793void QgsSymbolSelectorWidget::modelDataChanged( const QModelIndex &, const QModelIndex &, const QList<int> &roles )
794{
795 if ( roles.contains( Qt::CheckStateRole ) )
796 {
797 emitSymbolModified();
798 layerChanged();
800 }
801}
802
803void QgsSymbolSelectorWidget::layersAboutToBeRemoved( const QList<QgsMapLayer *> &layers )
804{
805 if ( mVectorLayer && layers.contains( mVectorLayer ) )
806 {
807 disconnect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
808 }
809}
810
811void QgsSymbolSelectorWidget::emitSymbolModified()
812{
813 if ( !mBlockModified )
814 {
815 emit symbolModified();
816 }
817}
QFlags< SymbolLayerUserFlag > SymbolLayerUserFlags
Symbol layer user flags.
Definition qgis.h:992
@ FlagIncludeCrosshairsForMarkerSymbols
Include a crosshairs reference image in the background of marker symbol previews.
Definition qgis.h:945
@ DisableSelectionRecoloring
If present, indicates that the symbol layer should not be recolored when rendering selected features.
Definition qgis.h:983
@ Marker
Marker symbol.
Definition qgis.h:672
@ Line
Line symbol.
Definition qgis.h:673
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:7320
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...
Definition qgsgui.cpp:225
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
void remoteImageFetched(const QString &url)
Emitted when the cache has finished retrieving an image file from a remote url.
A widget which allows configuration of the properties of a single QgsSymbolLayer.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
void changeLayer(QgsSymbolLayer *layer)
Emitted when the symbol layer is changed in the widget.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
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.
bool dockMode() const
Returns the dock mode state.
void changed()
Emitted when the widget state changes.
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
void connectChildPanel(QgsPanelWidget *panel)
Connect the given sub panel widgets showPanel signals to this current panels main showPanel event to ...
QgsPanelWidget(QWidget *parent=nullptr)
Base class for any widget that can be shown as an inline panel.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:114
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.
Definition qgsstyle.h:91
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 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.
Symbol selector widget that can be used to select and build a symbol.
void symbolChanged()
Slot to update tree when a new symbol from style.
void addLayer()
Add a symbol layer to the bottom of the stack.
QMenu * advancedMenu()
Returns menu for "advanced" button - create it if doesn't exist and show the advanced button.
void layerChanged()
Called when the layer changes in the widget.
void changeLayer(QgsSymbolLayer *layer)
Alters tree and sets proper widget when Layer Type is changed.
void updatePreview()
Update the preview of the whole symbol in the interface.
QgsSymbolSelectorWidget(QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr)
Symbol selector widget that can be used to select and build a symbol.
void removeLayer()
Remove the current active symbol layer.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
void moveLayerDown()
Move the active symbol layer down.
void symbolModified()
Emitted when a symbol is modified in the widget.
void duplicateLayer()
Duplicates the current symbol layer and places the duplicated layer above the current symbol layer.
void lockLayer()
Lock the current active symbol layer.
void loadSymbol(QgsSymbol *symbol)
Loads the given symbol into the widget.
void updateLayerPreview()
Update the single symbol layer preview in the widget.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void moveLayerUp()
Move the active symbol layer up.
static QgsSymbolSelectorWidget * createWidgetWithSymbolOwnership(std::unique_ptr< QgsSymbol > symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr)
Creates a QgsSymbolSelectorWidget which takes ownership of a symbol and maintains the ownership for t...
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
Abstract base class for all rendered symbols.
Definition qgssymbol.h:227
Qgis::SymbolType type() const
Returns the symbol's type.
Definition qgssymbol.h:296
Q_DECL_DEPRECATED void setLayer(const QgsVectorLayer *layer)
Sets the vector layer associated with the symbol.
A widget which presents symbol-level properties (such as size), and allows selection of symbols from ...
void changed()
Emitted when the symbol is modified in the widget.
Represents a vector layer which manages a vector based dataset.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:8361
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:8360