QGIS API Documentation 3.41.0-Master (af5edcb665c)
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#include "moc_qgssymbolselectordialog.cpp"
18
19#include "qgsstyle.h"
20#include "qgssymbol.h"
21#include "qgssymbollayer.h"
22#include "qgssymbollayerutils.h"
25
26// the widgets
29#include "qgsapplication.h"
30#include "qgsvectorlayer.h"
31#include "qgssvgcache.h"
32#include "qgsimagecache.h"
33#include "qgsproject.h"
34#include "qgsguiutils.h"
35#include "qgsgui.h"
36#include "qgsmarkersymbol.h"
37#include "qgslinesymbol.h"
38#include "qscreen.h"
39
40#include <QColorDialog>
41#include <QPainter>
42#include <QStandardItemModel>
43#include <QInputDialog>
44#include <QMessageBox>
45#include <QKeyEvent>
46#include <QMenu>
47
48#include <QWidget>
49#include <QFile>
50#include <QStandardItem>
51
53
54static const int SYMBOL_LAYER_ITEM_TYPE = QStandardItem::UserType + 1;
55
56DataDefinedRestorer::DataDefinedRestorer( QgsSymbol *symbol, const QgsSymbolLayer *symbolLayer )
57
58{
59 if ( symbolLayer->type() == Qgis::SymbolType::Marker && symbol->type() == Qgis::SymbolType::Marker )
60 {
61 Q_ASSERT( symbol->type() == Qgis::SymbolType::Marker );
62 mMarker = static_cast<QgsMarkerSymbol *>( symbol );
63 mMarkerSymbolLayer = static_cast<const QgsMarkerSymbolLayer *>( symbolLayer );
64 mDDSize = mMarker->dataDefinedSize();
65 mDDAngle = mMarker->dataDefinedAngle();
66 // check if restore is actually needed
67 if ( !mDDSize && !mDDAngle )
68 mMarker = nullptr;
69 }
70 else if ( symbolLayer->type() == Qgis::SymbolType::Line && symbol->type() == Qgis::SymbolType::Line )
71 {
72 mLine = static_cast<QgsLineSymbol *>( symbol );
73 mLineSymbolLayer = static_cast<const QgsLineSymbolLayer *>( symbolLayer );
74 mDDWidth = mLine->dataDefinedWidth();
75 // check if restore is actually needed
76 if ( !mDDWidth )
77 mLine = nullptr;
78 }
79 save();
80}
81
82void DataDefinedRestorer::save()
83{
84 if ( mMarker )
85 {
86 mSize = mMarkerSymbolLayer->size();
87 mAngle = mMarkerSymbolLayer->angle();
88 mMarkerOffset = mMarkerSymbolLayer->offset();
89 }
90 else if ( mLine )
91 {
92 mWidth = mLineSymbolLayer->width();
93 mLineOffset = mLineSymbolLayer->offset();
94 }
95}
96
97void DataDefinedRestorer::restore()
98{
99 if ( mMarker )
100 {
101 if ( mDDSize && ( mSize != mMarkerSymbolLayer->size() || mMarkerOffset != mMarkerSymbolLayer->offset() ) )
102 mMarker->setDataDefinedSize( mDDSize );
103 if ( mDDAngle && mAngle != mMarkerSymbolLayer->angle() )
104 mMarker->setDataDefinedAngle( mDDAngle );
105 }
106 else if ( mLine )
107 {
108 if ( mDDWidth && ( mWidth != mLineSymbolLayer->width() || mLineOffset != mLineSymbolLayer->offset() ) )
109 mLine->setDataDefinedWidth( mDDWidth );
110 }
111 save();
112}
113
114// Hybrid item which may represent a symbol or a layer
115// Check using item->isLayer()
116class SymbolLayerItem : public QStandardItem
117{
118 public:
119 explicit SymbolLayerItem( QgsSymbolLayer *layer, Qgis::SymbolType symbolType, QgsVectorLayer *vectorLayer, QScreen *screen )
120 : mVectorLayer( vectorLayer )
121 , mScreen( screen )
122 {
123 setLayer( layer, symbolType );
124 }
125
126 explicit SymbolLayerItem( QgsSymbol *symbol, QgsVectorLayer *vectorLayer, QScreen *screen )
127 : mVectorLayer( vectorLayer )
128 , mScreen( screen )
129 {
130 setSymbol( symbol );
131 }
132
133 void setLayer( QgsSymbolLayer *layer, Qgis::SymbolType symbolType )
134 {
135 mLayer = layer;
136 mIsLayer = true;
137 mSymbol = nullptr;
138 mSymbolType = symbolType;
139 updatePreview();
140 }
141
142 void setSymbol( QgsSymbol *symbol )
143 {
144 mSymbol = symbol;
145 mIsLayer = false;
146 mLayer = nullptr;
147 updatePreview();
148 }
149
150 void updatePreview()
151 {
152 if ( !mSize.isValid() )
153 {
154 const int size = QgsGuiUtils::scaleIconSize( 16 );
155 mSize = QSize( size, size );
156 }
157 QIcon icon;
158 if ( mIsLayer )
159 icon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( mLayer, Qgis::RenderUnit::Millimeters, mSize, QgsMapUnitScale(), mSymbol ? mSymbol->type() : mSymbolType, mVectorLayer, QgsScreenProperties( mScreen.data() ) );
160 else
161 {
162 QgsExpressionContext expContext;
164 icon = QIcon( QgsSymbolLayerUtils::symbolPreviewPixmap( mSymbol, mSize, 0, nullptr, false, &expContext, nullptr, QgsScreenProperties( mScreen.data() ) ) );
165 }
166 setIcon( icon );
167
168 if ( auto *lParent = parent() )
169 static_cast<SymbolLayerItem *>( lParent )->updatePreview();
170 }
171
172 int type() const override { return SYMBOL_LAYER_ITEM_TYPE; }
173 bool isLayer() { return mIsLayer; }
174
175 // returns the symbol pointer; helpful in determining a layer's parent symbol
176 QgsSymbol *symbol()
177 {
178 return mSymbol;
179 }
180
181 QgsSymbolLayer *layer()
182 {
183 return mLayer;
184 }
185
186 QVariant data( int role ) const override
187 {
188 if ( role == Qt::DisplayRole || role == Qt::EditRole )
189 {
190 if ( mIsLayer )
191 {
193 if ( m )
194 return m->visibleName();
195 else
196 return QString();
197 }
198 else
199 {
200 switch ( mSymbol->type() )
201 {
203 return QCoreApplication::translate( "SymbolLayerItem", "Marker" );
205 return QCoreApplication::translate( "SymbolLayerItem", "Fill" );
207 return QCoreApplication::translate( "SymbolLayerItem", "Line" );
208 default:
209 return "Symbol";
210 }
211 }
212 }
213 else if ( role == Qt::ForegroundRole && mIsLayer )
214 {
215 if ( !mLayer->enabled() )
216 {
217 QPalette pal = qApp->palette();
218 QBrush brush = QStandardItem::data( role ).value<QBrush>();
219 brush.setColor( pal.color( QPalette::Disabled, QPalette::WindowText ) );
220 return brush;
221 }
222 else
223 {
224 return QVariant();
225 }
226 }
227
228 // if ( role == Qt::SizeHintRole )
229 // return QVariant( QSize( 32, 32 ) );
230 if ( role == Qt::CheckStateRole )
231 return QVariant(); // could be true/false
232 return QStandardItem::data( role );
233 }
234
235 protected:
236 QgsSymbolLayer *mLayer = nullptr;
237 QgsSymbol *mSymbol = nullptr;
238 QPointer<QgsVectorLayer> mVectorLayer;
239 bool mIsLayer = false;
240 QSize mSize;
242 QPointer<QScreen> mScreen;
243};
244
246
248
250 : QgsPanelWidget( parent )
251 , mStyle( style )
252 , mSymbol( symbol )
253 , mVectorLayer( vl )
254{
255#ifdef Q_OS_MAC
256 setWindowModality( Qt::WindowModal );
257#endif
258
259 setupUi( this );
260 this->layout()->setContentsMargins( 0, 0, 0, 0 );
261
262 layersTree->setMaximumHeight( static_cast<int>( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 7 ) );
263 layersTree->setMinimumHeight( layersTree->maximumHeight() );
264 lblPreview->setMaximumWidth( layersTree->maximumHeight() );
265
266 // setup icons
267 btnAddLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
268 btnRemoveLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
269 QIcon iconLock;
270 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
271 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
272 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
273 iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
274
275 QIcon iconColorLock;
276 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorLocked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
277 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorLocked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
278 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorUnlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
279 iconColorLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconColorUnlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
280
281 mLockColorAction = new QAction( tr( "Lock Color" ), this );
282 mLockColorAction->setToolTip( tr( "Avoid changing the color of the layer when the symbol color is changed" ) );
283 mLockColorAction->setCheckable( true );
284 mLockColorAction->setIcon( iconColorLock );
285
286 QIcon iconSelectLock;
287 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectLocked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
288 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectLocked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
289 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectUnlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
290 iconSelectLock.addFile( QgsApplication::iconPath( QStringLiteral( "mIconSelectUnlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
291
292 mLockSelectionColorAction = new QAction( tr( "Lock Color When Selected" ), this );
293 mLockSelectionColorAction->setToolTip( tr( "Avoid changing the color of the layer when a feature is selected" ) );
294 mLockSelectionColorAction->setCheckable( true );
295 mLockSelectionColorAction->setIcon( iconSelectLock );
296
297 QMenu *lockMenu = new QMenu( this );
298 lockMenu->addAction( mLockColorAction );
299 lockMenu->addAction( mLockSelectionColorAction );
300 btnLock->setMenu( lockMenu );
301 btnLock->setPopupMode( QToolButton::InstantPopup );
302
303 btnDuplicate->setIcon( QIcon( QgsApplication::iconPath( "mActionDuplicateLayer.svg" ) ) );
304 btnUp->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
305 btnDown->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
306
307 mSymbolLayersModel = new QStandardItemModel( layersTree );
308 // Set the symbol
309 layersTree->setModel( mSymbolLayersModel );
310 layersTree->setHeaderHidden( true );
311
312 //get first feature from layer for previews
313 if ( mVectorLayer )
314 {
315#if 0 // this is too expensive to do for many providers. TODO revisit when support for connection timeouts is complete across all providers
316 // short timeout for request - it doesn't really matter if we don't get the feature, and this call is blocking UI
317 QgsFeatureIterator it = mVectorLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ).setConnectionTimeout( 100 ) );
318 it.nextFeature( mPreviewFeature );
319#endif
320 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) );
321#if 0
322 mPreviewExpressionContext.setFeature( mPreviewFeature );
323#endif
324 }
325 else
326 {
327 mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
328 }
329
330 QItemSelectionModel *selModel = layersTree->selectionModel();
331 connect( selModel, &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
332
333 loadSymbol( mSymbol, static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() ) );
335
336 connect( btnUp, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerUp );
337 connect( btnDown, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerDown );
338 connect( btnAddLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::addLayer );
339 connect( btnRemoveLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::removeLayer );
340 connect( mLockColorAction, &QAction::toggled, this, &QgsSymbolSelectorWidget::lockLayer );
341 connect( mLockSelectionColorAction, &QAction::toggled, this, [=]( bool checked ) {
342 QgsSymbolLayer *layer = currentLayer();
343 if ( !layer )
344 return;
345
346 Qgis::SymbolLayerUserFlags flags = layer->userFlags();
348 layer->setUserFlags( flags );
349 updateLockButtonIcon();
350 emit symbolModified();
351 } );
352 connect( btnDuplicate, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::duplicateLayer );
354
355 updateLockButtonIcon();
356
357 updateUi();
358
359 // set symbol as active item in the tree
360 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
361 layersTree->setCurrentIndex( newIndex );
362
363 setPanelTitle( tr( "Symbol Selector" ) );
364
365 // when a remote svg has been fetched, update the widget's previews
366 // this is required if the symbol utilizes remote svgs, and the current previews
367 // have been generated using the temporary "downloading" svg. In this case
368 // we require the preview to be regenerated to use the correct fetched
369 // svg
370 connect( QgsApplication::svgCache(), &QgsSvgCache::remoteSvgFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
371
372 // when a remote image has been fetched, update the widget's previews
373 // this is required if the symbol utilizes remote images, and the current previews
374 // have been generated using the temporary "downloading" image. In this case
375 // we require the preview to be regenerated to use the correct fetched
376 // image
377 connect( QgsApplication::imageCache(), &QgsImageCache::remoteImageFetched, this, &QgsSymbolSelectorWidget::projectDataChanged );
378
379 // if project color scheme changes, we need to redraw symbols - they may use project colors and accordingly
380 // need updating to reflect the new colors
381 connect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
382
383 connect( QgsProject::instance(), static_cast<void ( QgsProject::* )( const QList<QgsMapLayer *> &layers )>( &QgsProject::layersWillBeRemoved ), this, &QgsSymbolSelectorWidget::layersAboutToBeRemoved );
384}
385
386QgsSymbolSelectorWidget *QgsSymbolSelectorWidget::createWidgetWithSymbolOwnership( std::unique_ptr<QgsSymbol> symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent )
387{
388 QgsSymbolSelectorWidget *widget = new QgsSymbolSelectorWidget( symbol.get(), style, vl, parent );
389 // transfer ownership of symbol to widget, so that we are guaranteed it will last for the duration of the widget
390 widget->mOwnedSymbol = std::move( symbol );
391 return widget;
392}
393
395{
396 if ( !mAdvancedMenu )
397 {
398 mAdvancedMenu = new QMenu( this );
399 // Brute force method to activate the Advanced menu
400 layerChanged();
401 }
402 return mAdvancedMenu;
403}
404
406{
407 mContext = context;
408
409 if ( auto *lExpressionContext = mContext.expressionContext() )
410 {
411 mPreviewExpressionContext = *lExpressionContext;
412 if ( mVectorLayer )
413 mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
414
415 mPreviewExpressionContext.setFeature( mPreviewFeature );
416 }
417
418 QWidget *widget = stackedWidget->currentWidget();
419 if ( QgsLayerPropertiesWidget *layerProp = qobject_cast<QgsLayerPropertiesWidget *>( widget ) )
420 layerProp->setContext( context );
421 else if ( QgsSymbolsListWidget *listWidget = qobject_cast<QgsSymbolsListWidget *>( widget ) )
422 listWidget->setContext( context );
423
424 layerChanged();
426}
427
429{
430 return mContext;
431}
432
433void QgsSymbolSelectorWidget::loadSymbol( QgsSymbol *symbol, SymbolLayerItem *parent )
434{
435 if ( !symbol )
436 return;
437
438 if ( !parent )
439 {
440 mSymbol = symbol;
441 mSymbolLayersModel->clear();
442 parent = static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() );
443 }
444
445 SymbolLayerItem *symbolItem = new SymbolLayerItem( symbol, mVectorLayer, screen() );
446 QFont boldFont = symbolItem->font();
447 boldFont.setBold( true );
448 symbolItem->setFont( boldFont );
449 parent->appendRow( symbolItem );
450
451 const int count = symbol->symbolLayerCount();
452 for ( int i = count - 1; i >= 0; i-- )
453 {
454 SymbolLayerItem *layerItem = new SymbolLayerItem( symbol->symbolLayer( i ), symbol->type(), mVectorLayer, screen() );
455 layerItem->setEditable( false );
456 symbolItem->appendRow( layerItem );
457 if ( symbol->symbolLayer( i )->subSymbol() )
458 {
459 loadSymbol( symbol->symbolLayer( i )->subSymbol(), layerItem );
460 }
461 layersTree->setExpanded( layerItem->index(), true );
462 }
463 layersTree->setExpanded( symbolItem->index(), true );
464
465 if ( mSymbol == symbol && !layersTree->currentIndex().isValid() )
466 {
467 // make sure root item for symbol is selected in tree
468 layersTree->setCurrentIndex( symbolItem->index() );
469 }
470}
471
472void QgsSymbolSelectorWidget::reloadSymbol()
473{
474 mSymbolLayersModel->clear();
475 loadSymbol( mSymbol, static_cast<SymbolLayerItem *>( mSymbolLayersModel->invisibleRootItem() ) );
476}
477
478void QgsSymbolSelectorWidget::updateUi()
479{
480 const QModelIndex currentIdx = layersTree->currentIndex();
481 if ( !currentIdx.isValid() )
482 return;
483
484 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( currentIdx ) );
485 if ( !item->isLayer() )
486 {
487 btnUp->setEnabled( false );
488 btnDown->setEnabled( false );
489 btnRemoveLayer->setEnabled( false );
490 btnLock->setEnabled( false );
491 btnDuplicate->setEnabled( false );
492 return;
493 }
494
495 const int rowCount = item->parent()->rowCount();
496 const int currentRow = item->row();
497
498 btnUp->setEnabled( currentRow > 0 );
499 btnDown->setEnabled( currentRow < rowCount - 1 );
500 btnRemoveLayer->setEnabled( rowCount > 1 );
501 btnLock->setEnabled( true );
502 btnDuplicate->setEnabled( true );
503}
504
506{
507 if ( !mSymbol )
508 return;
509
510 std::unique_ptr<QgsSymbol> symbolClone( mSymbol->clone() );
511 const QImage preview = symbolClone->bigSymbolPreviewImage( &mPreviewExpressionContext, Qgis::SymbolPreviewFlag::FlagIncludeCrosshairsForMarkerSymbols, QgsScreenProperties( screen() ) );
512 lblPreview->setPixmap( QPixmap::fromImage( preview ) );
513 // Hope this is a appropriate place
514 if ( !mBlockModified )
515 emit symbolModified();
516}
517
519{
520 // get current layer item and update its icon
521 SymbolLayerItem *item = currentLayerItem();
522 if ( item )
523 item->updatePreview();
524 // update also preview of the whole symbol
526}
527
528SymbolLayerItem *QgsSymbolSelectorWidget::currentLayerItem()
529{
530 const QModelIndex idx = layersTree->currentIndex();
531 if ( !idx.isValid() )
532 return nullptr;
533
534 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
535 if ( !item->isLayer() )
536 return nullptr;
537
538 return item;
539}
540
541QgsSymbolLayer *QgsSymbolSelectorWidget::currentLayer()
542{
543 const QModelIndex idx = layersTree->currentIndex();
544 if ( !idx.isValid() )
545 return nullptr;
546
547 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
548 if ( item->isLayer() )
549 return item->layer();
550
551 return nullptr;
552}
553
555{
556 updateUi();
557
558 SymbolLayerItem *currentItem = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( layersTree->currentIndex() ) );
559 if ( !currentItem )
560 return;
561
562 if ( currentItem->isLayer() )
563 {
564 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( currentItem->parent() );
565 mDataDefineRestorer.reset( new DataDefinedRestorer( parent->symbol(), currentItem->layer() ) );
566 QgsLayerPropertiesWidget *layerProp = new QgsLayerPropertiesWidget( currentItem->layer(), parent->symbol(), mVectorLayer );
567 layerProp->setDockMode( this->dockMode() );
568 layerProp->setContext( mContext );
569 setWidget( layerProp );
570 connect( layerProp, &QgsLayerPropertiesWidget::changed, mDataDefineRestorer.get(), &DataDefinedRestorer::restore );
572 // This connection when layer type is changed
574
575 connectChildPanel( layerProp );
576 }
577 else
578 {
579 // then it must be a symbol
580 mDataDefineRestorer.reset();
582 currentItem->symbol()->setLayer( mVectorLayer );
584 // Now populate symbols of that type using the symbols list widget:
585 QgsSymbolsListWidget *symbolsList = new QgsSymbolsListWidget( currentItem->symbol(), mStyle, mAdvancedMenu, this, mVectorLayer );
586 symbolsList->setContext( mContext );
587
588 setWidget( symbolsList );
590 }
591 updateLockButton();
592}
593
595{
596 SymbolLayerItem *currentItem = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( layersTree->currentIndex() ) );
597 if ( !currentItem || currentItem->isLayer() )
598 return;
599 // disconnect to avoid recreating widget
600 disconnect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
601 if ( currentItem->parent() )
602 {
603 // it is a sub-symbol
604 QgsSymbol *symbol = currentItem->symbol();
605 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( currentItem->parent() );
606 parent->removeRow( 0 );
607 loadSymbol( symbol, parent );
608 layersTree->setCurrentIndex( parent->child( 0 )->index() );
609 parent->updatePreview();
610 }
611 else
612 {
613 //it is the symbol itself
614 reloadSymbol();
615 const QModelIndex newIndex = layersTree->model()->index( 0, 0 );
616 layersTree->setCurrentIndex( newIndex );
617 }
619 // connect it back once things are set
620 connect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
621}
622
623void QgsSymbolSelectorWidget::setWidget( QWidget *widget )
624{
625 const int index = stackedWidget->addWidget( widget );
626 stackedWidget->setCurrentIndex( index );
627 if ( mPresentWidget )
628 mPresentWidget->deleteLater();
629 mPresentWidget = widget;
630}
631
632void QgsSymbolSelectorWidget::updateLockButton()
633{
634 QgsSymbolLayer *layer = currentLayer();
635 if ( !layer )
636 return;
637 mLockColorAction->setChecked( layer->isLocked() );
638 mLockSelectionColorAction->setChecked( layer->userFlags() & Qgis::SymbolLayerUserFlag::DisableSelectionRecoloring );
639
640 updateLockButtonIcon();
641}
642
643void QgsSymbolSelectorWidget::updateLockButtonIcon()
644{
645 if ( mLockColorAction->isChecked() && mLockSelectionColorAction->isChecked() )
646 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "locked.svg" ) ) );
647 else if ( mLockColorAction->isChecked() )
648 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconColorLocked.svg" ) ) );
649 else if ( mLockSelectionColorAction->isChecked() )
650 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconSelectLocked.svg" ) ) );
651 else
652 btnLock->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "unlocked.svg" ) ) );
653}
654
656{
657 const QModelIndex idx = layersTree->currentIndex();
658 if ( !idx.isValid() )
659 return;
660
661 int insertIdx = -1;
662 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
663 if ( item->isLayer() )
664 {
665 insertIdx = item->row();
666 item = static_cast<SymbolLayerItem *>( item->parent() );
667 }
668
669 QgsSymbol *parentSymbol = item->symbol();
670
671 // save data-defined values at marker level
672 const QgsProperty ddSize( parentSymbol->type() == Qgis::SymbolType::Marker ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedSize() : QgsProperty() );
673 const QgsProperty ddAngle( parentSymbol->type() == Qgis::SymbolType::Marker ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedAngle() : QgsProperty() );
674 const QgsProperty ddWidth( parentSymbol->type() == Qgis::SymbolType::Line ? static_cast<QgsLineSymbol *>( parentSymbol )->dataDefinedWidth() : QgsProperty() );
675
677 if ( insertIdx == -1 )
678 parentSymbol->appendSymbolLayer( newLayer );
679 else
680 parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );
681
682 // restore data-defined values at marker level
683 if ( ddSize )
684 static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedSize( ddSize );
685 if ( ddAngle )
686 static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedAngle( ddAngle );
687 if ( ddWidth )
688 static_cast<QgsLineSymbol *>( parentSymbol )->setDataDefinedWidth( ddWidth );
689
690 SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer, parentSymbol->type(), mVectorLayer, screen() );
691 item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
692 item->updatePreview();
693
694 layersTree->setCurrentIndex( mSymbolLayersModel->indexFromItem( newLayerItem ) );
695 updateUi();
697}
698
700{
701 SymbolLayerItem *item = currentLayerItem();
702 const int row = item->row();
703 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
704
705 const int layerIdx = parent->rowCount() - row - 1; // IMPORTANT
706 QgsSymbol *parentSymbol = parent->symbol();
707 QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
708
709 parent->removeRow( row );
710 parent->updatePreview();
711
712 const QModelIndex newIdx = parent->child( 0 )->index();
713 layersTree->setCurrentIndex( newIdx );
714
715 updateUi();
717 //finally delete the removed layer pointer
718 delete tmpLayer;
719}
720
722{
723 moveLayerByOffset( +1 );
724}
725
727{
728 moveLayerByOffset( -1 );
729}
730
731void QgsSymbolSelectorWidget::moveLayerByOffset( int offset )
732{
733 SymbolLayerItem *item = currentLayerItem();
734 if ( !item )
735 return;
736 const int row = item->row();
737
738 SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
739 QgsSymbol *parentSymbol = parent->symbol();
740
741 const int layerIdx = parent->rowCount() - row - 1;
742 // switch layers
743 QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
744 parentSymbol->insertSymbolLayer( layerIdx - offset, tmpLayer );
745
746 QList<QStandardItem *> rowItems = parent->takeRow( row );
747 parent->insertRows( row + offset, rowItems );
748 parent->updatePreview();
749
750 const QModelIndex newIdx = rowItems[0]->index();
751 layersTree->setCurrentIndex( newIdx );
752
754 updateUi();
755}
756
758{
759 QgsSymbolLayer *layer = currentLayer();
760 if ( !layer )
761 return;
762 layer->setLocked( mLockColorAction->isChecked() );
763 updateLockButtonIcon();
764 emit symbolModified();
765}
766
768{
769 const QModelIndex idx = layersTree->currentIndex();
770 if ( !idx.isValid() )
771 return;
772
773 SymbolLayerItem *item = static_cast<SymbolLayerItem *>( mSymbolLayersModel->itemFromIndex( idx ) );
774 if ( !item->isLayer() )
775 return;
776
777 QgsSymbolLayer *source = item->layer();
778
779 const int insertIdx = item->row();
780 item = static_cast<SymbolLayerItem *>( item->parent() );
781
782 QgsSymbol *parentSymbol = item->symbol();
783
784 QgsSymbolLayer *newLayer = source->clone();
786 if ( insertIdx == -1 )
787 parentSymbol->appendSymbolLayer( newLayer );
788 else
789 parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );
790
791 SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer, parentSymbol->type(), mVectorLayer, screen() );
792 item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
793 if ( newLayer->subSymbol() )
794 {
795 loadSymbol( newLayer->subSymbol(), newLayerItem );
796 layersTree->setExpanded( newLayerItem->index(), true );
797 }
798 item->updatePreview();
799
800 layersTree->setCurrentIndex( mSymbolLayersModel->indexFromItem( newLayerItem ) );
801 updateUi();
803}
804
806{
807 SymbolLayerItem *item = currentLayerItem();
808
809 if ( item->rowCount() > 0 )
810 {
811 item->removeRow( 0 );
812 }
813 QgsSymbol *symbol = static_cast<SymbolLayerItem *>( item->parent() )->symbol();
814
815 // update symbol layer item
816 item->setLayer( newLayer, symbol->type() );
817 // When it is a marker symbol
818 if ( newLayer->subSymbol() )
819 {
820 loadSymbol( newLayer->subSymbol(), item );
821 layersTree->setExpanded( item->index(), true );
822 }
823
824 // Change the symbol at last to avoid deleting item's layer
825 const int layerIdx = item->parent()->rowCount() - item->row() - 1;
826 symbol->changeSymbolLayer( layerIdx, newLayer );
827
828 item->updatePreview();
830 // Important: This lets the layer have its own layer properties widget
831 layerChanged();
832}
833
834QgsSymbolSelectorDialog::QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent, bool embedded )
835 : QDialog( parent )
836{
837 setLayout( new QVBoxLayout() );
838
839 mSelectorWidget = new QgsSymbolSelectorWidget( symbol, style, vl, this );
840 mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
841
842 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
843 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
844 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsSymbolSelectorDialog::showHelp );
845
846 layout()->addWidget( mSelectorWidget );
847 layout()->addWidget( mButtonBox );
848
849 connect( mSelectorWidget, &QgsPanelWidget::panelAccepted, this, &QDialog::reject );
850
851 mSelectorWidget->setMinimumSize( 460, 560 );
852 setObjectName( QStringLiteral( "SymbolSelectorDialog" ) );
854
855 // Can be embedded in renderer properties dialog
856 if ( embedded )
857 {
858 mButtonBox->hide();
859 layout()->setContentsMargins( 0, 0, 0, 0 );
860 }
861 else
862 {
863 setWindowTitle( tr( "Symbol Selector" ) );
864 }
865 mSelectorWidget->setDockMode( embedded );
866}
867
869{
870 return mSelectorWidget->advancedMenu();
871}
872
874{
875 mContext = context;
876}
877
879{
880 return mContext;
881}
882
884{
885 return mSelectorWidget->symbol();
886}
887
889{
890 // Ignore the ESC key to avoid close the dialog without the properties window
891 if ( !isWindow() && e->key() == Qt::Key_Escape )
892 {
893 e->ignore();
894 }
895 else
896 {
897 QDialog::keyPressEvent( e );
898 }
899}
900
901void QgsSymbolSelectorDialog::reloadSymbol()
902{
903 mSelectorWidget->reloadSymbol();
904}
905
906void QgsSymbolSelectorDialog::loadSymbol( QgsSymbol *symbol, SymbolLayerItem *parent )
907{
908 mSelectorWidget->loadSymbol( symbol, parent );
909}
910
911void QgsSymbolSelectorDialog::updateUi()
912{
913 mSelectorWidget->updateUi();
914}
915
916void QgsSymbolSelectorDialog::updateLockButton()
917{
918 mSelectorWidget->updateLockButton();
919}
920
921SymbolLayerItem *QgsSymbolSelectorDialog::currentLayerItem()
922{
923 return mSelectorWidget->currentLayerItem();
924}
925
926QgsSymbolLayer *QgsSymbolSelectorDialog::currentLayer()
927{
928 return mSelectorWidget->currentLayer();
929}
930
931void QgsSymbolSelectorDialog::moveLayerByOffset( int offset )
932{
933 mSelectorWidget->moveLayerByOffset( offset );
934}
935
936void QgsSymbolSelectorDialog::setWidget( QWidget *widget )
937{
938 mSelectorWidget->setWidget( widget );
939}
940
942{
943 mSelectorWidget->moveLayerDown();
944}
945
947{
948 mSelectorWidget->moveLayerUp();
949}
950
952{
953 mSelectorWidget->addLayer();
954}
955
957{
958 mSelectorWidget->removeLayer();
959}
960
962{
963 mSelectorWidget->lockLayer();
964}
965
967{
968 mSelectorWidget->duplicateLayer();
969}
970
972{
973 mSelectorWidget->layerChanged();
974}
975
980
982{
983 mSelectorWidget->updatePreview();
984}
985
987{
988 mSelectorWidget->symbolChanged();
989}
990
992{
993 mSelectorWidget->changeLayer( layer );
994}
995
996QDialogButtonBox *QgsSymbolSelectorDialog::buttonBox() const
997{
998 return mButtonBox;
999}
1000
1001void QgsSymbolSelectorDialog::showHelp()
1002{
1003 QgsHelp::openHelp( QStringLiteral( "style_library/symbol_selector.html" ) );
1004}
1005
1006void QgsSymbolSelectorWidget::projectDataChanged()
1007{
1008 mBlockModified = true;
1009 symbolChanged();
1010 updatePreview();
1011 mBlockModified = false;
1012}
1013
1014void QgsSymbolSelectorWidget::layersAboutToBeRemoved( const QList<QgsMapLayer *> &layers )
1015{
1016 if ( mVectorLayer && layers.contains( mVectorLayer ) )
1017 {
1018 disconnect( QgsProject::instance(), &QgsProject::projectColorsChanged, this, &QgsSymbolSelectorWidget::projectDataChanged );
1019 }
1020}
QFlags< SymbolLayerUserFlag > SymbolLayerUserFlags
Symbol layer user flags.
Definition qgis.h:844
@ Millimeters
Millimeters.
@ 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.
SymbolType
Symbol types.
Definition qgis.h:574
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:5775
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application's symbol layer registry, used for managing symbol layers.
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.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
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.
This class 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:210
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:39
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 ...
void changed()
Emitted when the symbol layer configuration is changed in the widget.
Abstract base class for line symbol layers.
A line symbol type, for rendering LineString and MultiLineString geometries.
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Struct for storing maximum and minimum scales for measurements in map units.
Abstract base class for marker symbol layers.
A marker symbol type, for rendering Point and MultiPoint geometries.
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Base class for any widget that can be shown as a inline panel.
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 ...
void widgetChanged()
Emitted when the widget state changes.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
bool dockMode()
Returns the dock mode state.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:107
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 store for object properties.
Stores properties relating to a screen.
void remoteSvgFetched(const QString &url)
Emitted when the cache has finished retrieving an SVG file from a remote url.
Stores metadata about one symbol layer class.
QgsSymbolLayerAbstractMetadata * symbolLayerMetadata(const QString &name) const
Returns metadata for specified symbol layer. Returns nullptr if not found.
static QgsSymbolLayer * defaultSymbolLayer(Qgis::SymbolType type)
create a new instance of symbol layer for specified symbol type with default settings
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 QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr, const QgsScreenProperties &screen=QgsScreenProperties())
Returns a pixmap preview for a color ramp.
static void resetSymbolLayerIds(QgsSymbol *symbol)
Regenerate recursively unique id from all symbol symbol layers.
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
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.
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
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 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.
void loadSymbol(QgsSymbol *symbol, SymbolLayerItem *parent=nullptr)
Loads the given symbol into the widget.
Symbol selector widget that can be used to select and build a symbol.
void loadSymbol(QgsSymbol *symbol, SymbolLayerItem *parent=nullptr)
Loads the given symbol into the widget.
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 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,...
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
bool appendSymbolLayer(QgsSymbolLayer *layer)
Appends a symbol layer at the end of the current symbol layer list.
bool insertSymbolLayer(int index, QgsSymbolLayer *layer)
Inserts a symbol layer to specified index.
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
Deletes the current layer at the specified index and replaces it with layer.
QgsSymbolLayer * takeSymbolLayer(int index)
Removes a symbol layer from the list and returns a pointer to it.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition qgssymbol.h:353
Qgis::SymbolType type() const
Returns the symbol's type.
Definition qgssymbol.h:294
void changed()
Emitted when the symbol is modified in the widget.
Represents a vector layer which manages a vector based data sets.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:6643
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6642