QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
18 #include "qgsstyle.h"
19 #include "qgssymbol.h"
20 #include "qgssymbollayer.h"
21 #include "qgssymbollayerutils.h"
22 #include "qgssymbollayerregistry.h"
23 
24 // the widgets
25 #include "qgssymbolslistwidget.h"
27 #include "qgssymbollayerwidget.h"
30 
31 #include "qgslogger.h"
32 #include "qgsapplication.h"
33 #include "qgssettings.h"
34 #include "qgsfeatureiterator.h"
35 #include "qgsvectorlayer.h"
36 #include "qgssvgcache.h"
37 
38 #include <QColorDialog>
39 #include <QPainter>
40 #include <QStandardItemModel>
41 #include <QInputDialog>
42 #include <QMessageBox>
43 #include <QKeyEvent>
44 #include <QMenu>
45 
46 #include <QWidget>
47 #include <QFile>
48 #include <QStandardItem>
49 
51 
52 static const int SYMBOL_LAYER_ITEM_TYPE = QStandardItem::UserType + 1;
53 
54 DataDefinedRestorer::DataDefinedRestorer( QgsSymbol *symbol, const QgsSymbolLayer *symbolLayer )
55 
56 {
57  if ( symbolLayer->type() == QgsSymbol::Marker && symbol->type() == QgsSymbol::Marker )
58  {
59  Q_ASSERT( symbol->type() == QgsSymbol::Marker );
60  mMarker = static_cast<QgsMarkerSymbol *>( symbol );
61  mMarkerSymbolLayer = static_cast<const QgsMarkerSymbolLayer *>( symbolLayer );
62  mDDSize = mMarker->dataDefinedSize();
63  mDDAngle = mMarker->dataDefinedAngle();
64  // check if restore is actually needed
65  if ( !mDDSize && !mDDAngle )
66  mMarker = nullptr;
67  }
68  else if ( symbolLayer->type() == QgsSymbol::Line && symbol->type() == QgsSymbol::Line )
69  {
70  mLine = static_cast<QgsLineSymbol *>( symbol );
71  mLineSymbolLayer = static_cast<const QgsLineSymbolLayer *>( symbolLayer );
72  mDDWidth = mLine->dataDefinedWidth();
73  // check if restore is actually needed
74  if ( !mDDWidth )
75  mLine = nullptr;
76  }
77  save();
78 }
79 
80 void DataDefinedRestorer::save()
81 {
82  if ( mMarker )
83  {
84  mSize = mMarkerSymbolLayer->size();
85  mAngle = mMarkerSymbolLayer->angle();
86  mMarkerOffset = mMarkerSymbolLayer->offset();
87  }
88  else if ( mLine )
89  {
90  mWidth = mLineSymbolLayer->width();
91  mLineOffset = mLineSymbolLayer->offset();
92  }
93 }
94 
95 void DataDefinedRestorer::restore()
96 {
97  if ( mMarker )
98  {
99  if ( mDDSize &&
100  ( mSize != mMarkerSymbolLayer->size() || mMarkerOffset != mMarkerSymbolLayer->offset() ) )
101  mMarker->setDataDefinedSize( mDDSize );
102  if ( mDDAngle &&
103  mAngle != mMarkerSymbolLayer->angle() )
104  mMarker->setDataDefinedAngle( mDDAngle );
105  }
106  else if ( mLine )
107  {
108  if ( mDDWidth &&
109  ( mWidth != mLineSymbolLayer->width() || mLineOffset != mLineSymbolLayer->offset() ) )
110  mLine->setDataDefinedWidth( mDDWidth );
111  }
112  save();
113 }
114 
115 // Hybrid item which may represent a symbol or a layer
116 // Check using item->isLayer()
117 class SymbolLayerItem : public QStandardItem
118 {
119  public:
120  explicit SymbolLayerItem( QgsSymbolLayer *layer )
121  {
122  setLayer( layer );
123  }
124 
125  explicit SymbolLayerItem( QgsSymbol *symbol )
126  {
127  setSymbol( symbol );
128  }
129 
130  void setLayer( QgsSymbolLayer *layer )
131  {
132  mLayer = layer;
133  mIsLayer = true;
134  mSymbol = nullptr;
135  updatePreview();
136  }
137 
138  void setSymbol( QgsSymbol *symbol )
139  {
140  mSymbol = symbol;
141  mIsLayer = false;
142  mLayer = nullptr;
143  updatePreview();
144  }
145 
146  void updatePreview()
147  {
148  QIcon icon;
149  if ( mIsLayer )
150  icon = QgsSymbolLayerUtils::symbolLayerPreviewIcon( mLayer, QgsUnitTypes::RenderMillimeters, QSize( 16, 16 ) ); //todo: make unit a parameter
151  else
152  icon = QgsSymbolLayerUtils::symbolPreviewIcon( mSymbol, QSize( 16, 16 ) );
153  setIcon( icon );
154 
155  if ( parent() )
156  static_cast<SymbolLayerItem *>( parent() )->updatePreview();
157  }
158 
159  int type() const override { return SYMBOL_LAYER_ITEM_TYPE; }
160  bool isLayer() { return mIsLayer; }
161 
162  // returns the symbol pointer; helpful in determining a layer's parent symbol
163  QgsSymbol *symbol()
164  {
165  return mSymbol;
166  }
167 
168  QgsSymbolLayer *layer()
169  {
170  return mLayer;
171  }
172 
173  QVariant data( int role ) const override
174  {
175  if ( role == Qt::DisplayRole || role == Qt::EditRole )
176  {
177  if ( mIsLayer )
178  return QgsApplication::symbolLayerRegistry()->symbolLayerMetadata( mLayer->layerType() )->visibleName();
179  else
180  {
181  switch ( mSymbol->type() )
182  {
183  case QgsSymbol::Marker :
184  return QCoreApplication::translate( "SymbolLayerItem", "Marker", nullptr, QCoreApplication::UnicodeUTF8 );
185  case QgsSymbol::Fill :
186  return QCoreApplication::translate( "SymbolLayerItem", "Fill", nullptr, QCoreApplication::UnicodeUTF8 );
187  case QgsSymbol::Line :
188  return QCoreApplication::translate( "SymbolLayerItem", "Line", nullptr, QCoreApplication::UnicodeUTF8 );
189  default:
190  return "Symbol";
191  }
192  }
193  }
194  else if ( role == Qt::ForegroundRole && mIsLayer )
195  {
196  QBrush brush( Qt::black, Qt::SolidPattern );
197  if ( !mLayer->enabled() )
198  {
199  brush.setColor( Qt::lightGray );
200  }
201  return brush;
202  }
203 
204 // if ( role == Qt::SizeHintRole )
205 // return QVariant( QSize( 32, 32 ) );
206  if ( role == Qt::CheckStateRole )
207  return QVariant(); // could be true/false
208  return QStandardItem::data( role );
209  }
210 
211  protected:
212  QgsSymbolLayer *mLayer = nullptr;
213  QgsSymbol *mSymbol = nullptr;
214  bool mIsLayer;
215 };
216 
218 
220 
222  : QgsPanelWidget( parent )
223  , mVectorLayer( vl )
224 {
225 #ifdef Q_OS_MAC
226  setWindowModality( Qt::WindowModal );
227 #endif
228  mStyle = style;
229  mSymbol = symbol;
230  mPresentWidget = nullptr;
231 
232  setupUi( this );
233  this->layout()->setContentsMargins( 0, 0, 0, 0 );
234 
235  // setup icons
236  btnAddLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
237  btnRemoveLayer->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
238  QIcon iconLock;
239  iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Normal, QIcon::On );
240  iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "locked.svg" ) ), QSize(), QIcon::Active, QIcon::On );
241  iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Normal, QIcon::Off );
242  iconLock.addFile( QgsApplication::iconPath( QStringLiteral( "unlocked.svg" ) ), QSize(), QIcon::Active, QIcon::Off );
243  btnLock->setIcon( iconLock );
244  btnDuplicate->setIcon( QIcon( QgsApplication::iconPath( "mActionDuplicateLayer.svg" ) ) );
245  btnUp->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowUp.svg" ) ) );
246  btnDown->setIcon( QIcon( QgsApplication::iconPath( "mActionArrowDown.svg" ) ) );
247 
248  model = new QStandardItemModel( layersTree );
249  // Set the symbol
250  layersTree->setModel( model );
251  layersTree->setHeaderHidden( true );
252 
253  //get first feature from layer for previews
254  if ( mVectorLayer )
255  {
257  it.nextFeature( mPreviewFeature );
259  mPreviewExpressionContext.setFeature( mPreviewFeature );
260  }
261  else
262  {
263  mPreviewExpressionContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
264  }
265 
266  QItemSelectionModel *selModel = layersTree->selectionModel();
267  connect( selModel, &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
268 
269  loadSymbol( symbol, static_cast<SymbolLayerItem *>( model->invisibleRootItem() ) );
270  updatePreview();
271 
272  connect( btnUp, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerUp );
273  connect( btnDown, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::moveLayerDown );
274  connect( btnAddLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::addLayer );
275  connect( btnRemoveLayer, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::removeLayer );
276  connect( btnLock, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::lockLayer );
277  connect( btnDuplicate, &QAbstractButton::clicked, this, &QgsSymbolSelectorWidget::duplicateLayer );
279 
280  updateUi();
281 
282  // set symbol as active item in the tree
283  QModelIndex newIndex = layersTree->model()->index( 0, 0 );
284  layersTree->setCurrentIndex( newIndex );
285 
286  setPanelTitle( tr( "Symbol Selector" ) );
287 
289  {
290  // when a remote svg has been fetched, update the widget's previews
291  // this is required if the symbol utilizes remote svgs, and the current previews
292  // have been generated using the temporary "downloading" svg. In this case
293  // we require the preview to be regenerated to use the correct fetched
294  // svg
295  symbolChanged();
296  updatePreview();
297  } );
298 }
299 
301 {
302  if ( !mAdvancedMenu )
303  {
304  mAdvancedMenu = new QMenu( this );
305  // Brute force method to activate the Advanced menu
306  layerChanged();
307  }
308  return mAdvancedMenu;
309 }
310 
312 {
313  mContext = context;
314 
315  if ( mContext.expressionContext() )
316  {
317  mPreviewExpressionContext = *mContext.expressionContext();
318  if ( mVectorLayer )
319  mPreviewExpressionContext.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
320 
321  mPreviewExpressionContext.setFeature( mPreviewFeature );
322  }
323 
324  QWidget *widget = stackedWidget->currentWidget();
325  QgsLayerPropertiesWidget *layerProp = dynamic_cast< QgsLayerPropertiesWidget * >( widget );
326  QgsSymbolsListWidget *listWidget = dynamic_cast< QgsSymbolsListWidget * >( widget );
327 
328  if ( layerProp )
329  layerProp->setContext( context );
330  if ( listWidget )
331  listWidget->setContext( context );
332 
333  layerChanged();
334  updatePreview();
335 }
336 
338 {
339  return mContext;
340 }
341 
342 void QgsSymbolSelectorWidget::loadSymbol( QgsSymbol *symbol, SymbolLayerItem *parent )
343 {
344  SymbolLayerItem *symbolItem = new SymbolLayerItem( symbol );
345  QFont boldFont = symbolItem->font();
346  boldFont.setBold( true );
347  symbolItem->setFont( boldFont );
348  parent->appendRow( symbolItem );
349 
350  int count = symbol->symbolLayerCount();
351  for ( int i = count - 1; i >= 0; i-- )
352  {
353  SymbolLayerItem *layerItem = new SymbolLayerItem( symbol->symbolLayer( i ) );
354  layerItem->setEditable( false );
355  symbolItem->appendRow( layerItem );
356  if ( symbol->symbolLayer( i )->subSymbol() )
357  {
358  loadSymbol( symbol->symbolLayer( i )->subSymbol(), layerItem );
359  }
360  layersTree->setExpanded( layerItem->index(), true );
361  }
362  layersTree->setExpanded( symbolItem->index(), true );
363 }
364 
365 
367 {
368  model->clear();
369  loadSymbol( mSymbol, static_cast<SymbolLayerItem *>( model->invisibleRootItem() ) );
370 }
371 
373 {
374  QModelIndex currentIdx = layersTree->currentIndex();
375  if ( !currentIdx.isValid() )
376  return;
377 
378  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( currentIdx ) );
379  if ( !item->isLayer() )
380  {
381  btnUp->setEnabled( false );
382  btnDown->setEnabled( false );
383  btnRemoveLayer->setEnabled( false );
384  btnLock->setEnabled( false );
385  btnDuplicate->setEnabled( false );
386  return;
387  }
388 
389  int rowCount = item->parent()->rowCount();
390  int currentRow = item->row();
391 
392  btnUp->setEnabled( currentRow > 0 );
393  btnDown->setEnabled( currentRow < rowCount - 1 );
394  btnRemoveLayer->setEnabled( rowCount > 1 );
395  btnLock->setEnabled( true );
396  btnDuplicate->setEnabled( true );
397 }
398 
400 {
401  QImage preview = mSymbol->bigSymbolPreviewImage( &mPreviewExpressionContext );
402  lblPreview->setPixmap( QPixmap::fromImage( preview ) );
403  // Hope this is a appropriate place
404  emit symbolModified();
405 }
406 
408 {
409  // get current layer item and update its icon
410  SymbolLayerItem *item = currentLayerItem();
411  if ( item )
412  item->updatePreview();
413  // update also preview of the whole symbol
414  updatePreview();
415 }
416 
418 {
419  QModelIndex idx = layersTree->currentIndex();
420  if ( !idx.isValid() )
421  return nullptr;
422 
423  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( idx ) );
424  if ( !item->isLayer() )
425  return nullptr;
426 
427  return item;
428 }
429 
431 {
432  QModelIndex idx = layersTree->currentIndex();
433  if ( !idx.isValid() )
434  return nullptr;
435 
436  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( idx ) );
437  if ( item->isLayer() )
438  return item->layer();
439 
440  return nullptr;
441 }
442 
444 {
445  updateUi();
446 
447  SymbolLayerItem *currentItem = static_cast<SymbolLayerItem *>( model->itemFromIndex( layersTree->currentIndex() ) );
448  if ( !currentItem )
449  return;
450 
451  if ( currentItem->isLayer() )
452  {
453  SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( currentItem->parent() );
454  mDataDefineRestorer.reset( new DataDefinedRestorer( parent->symbol(), currentItem->layer() ) );
455  QgsLayerPropertiesWidget *layerProp = new QgsLayerPropertiesWidget( currentItem->layer(), parent->symbol(), mVectorLayer );
456  layerProp->setDockMode( this->dockMode() );
457  layerProp->setContext( mContext );
458  setWidget( layerProp );
459  connect( layerProp, &QgsLayerPropertiesWidget::changed, mDataDefineRestorer.get(), &DataDefinedRestorer::restore );
461  // This connection when layer type is changed
463 
464  connectChildPanel( layerProp );
465  }
466  else
467  {
468  mDataDefineRestorer.reset();
469  // then it must be a symbol
470  currentItem->symbol()->setLayer( mVectorLayer );
471  // Now populate symbols of that type using the symbols list widget:
472  QgsSymbolsListWidget *symbolsList = new QgsSymbolsListWidget( currentItem->symbol(), mStyle, mAdvancedMenu, this, mVectorLayer );
473  symbolsList->setContext( mContext );
474 
475  setWidget( symbolsList );
477  }
479 }
480 
482 {
483  SymbolLayerItem *currentItem = static_cast<SymbolLayerItem *>( model->itemFromIndex( layersTree->currentIndex() ) );
484  if ( !currentItem || currentItem->isLayer() )
485  return;
486  // disconnect to avoid recreating widget
487  disconnect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
488  if ( currentItem->parent() )
489  {
490  // it is a sub-symbol
491  QgsSymbol *symbol = currentItem->symbol();
492  SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( currentItem->parent() );
493  parent->removeRow( 0 );
494  loadSymbol( symbol, parent );
495  layersTree->setCurrentIndex( parent->child( 0 )->index() );
496  parent->updatePreview();
497  }
498  else
499  {
500  //it is the symbol itself
501  loadSymbol();
502  QModelIndex newIndex = layersTree->model()->index( 0, 0 );
503  layersTree->setCurrentIndex( newIndex );
504  }
505  updatePreview();
506  // connect it back once things are set
507  connect( layersTree->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolSelectorWidget::layerChanged );
508 }
509 
510 void QgsSymbolSelectorWidget::setWidget( QWidget *widget )
511 {
512  int index = stackedWidget->addWidget( widget );
513  stackedWidget->setCurrentIndex( index );
514  if ( mPresentWidget )
515  mPresentWidget->deleteLater();
516  mPresentWidget = widget;
517 }
518 
520 {
521  QgsSymbolLayer *layer = currentLayer();
522  if ( !layer )
523  return;
524  btnLock->setChecked( layer->isLocked() );
525 }
526 
528 {
529  QModelIndex idx = layersTree->currentIndex();
530  if ( !idx.isValid() )
531  return;
532 
533  int insertIdx = -1;
534  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( idx ) );
535  if ( item->isLayer() )
536  {
537  insertIdx = item->row();
538  item = static_cast<SymbolLayerItem *>( item->parent() );
539  }
540 
541  QgsSymbol *parentSymbol = item->symbol();
542 
543  // save data-defined values at marker level
544  QgsProperty ddSize( parentSymbol->type() == QgsSymbol::Marker
545  ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedSize()
546  : QgsProperty() );
547  QgsProperty ddAngle( parentSymbol->type() == QgsSymbol::Marker
548  ? static_cast<QgsMarkerSymbol *>( parentSymbol )->dataDefinedAngle()
549  : QgsProperty() );
550  QgsProperty ddWidth( parentSymbol->type() == QgsSymbol::Line
551  ? static_cast<QgsLineSymbol *>( parentSymbol )->dataDefinedWidth()
552  : QgsProperty() );
553 
555  if ( insertIdx == -1 )
556  parentSymbol->appendSymbolLayer( newLayer );
557  else
558  parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );
559 
560  // restore data-defined values at marker level
561  if ( ddSize )
562  static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedSize( ddSize );
563  if ( ddAngle )
564  static_cast<QgsMarkerSymbol *>( parentSymbol )->setDataDefinedAngle( ddAngle );
565  if ( ddWidth )
566  static_cast<QgsLineSymbol *>( parentSymbol )->setDataDefinedWidth( ddWidth );
567 
568  SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer );
569  item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
570  item->updatePreview();
571 
572  layersTree->setCurrentIndex( model->indexFromItem( newLayerItem ) );
573  updateUi();
574  updatePreview();
575 }
576 
578 {
579  SymbolLayerItem *item = currentLayerItem();
580  int row = item->row();
581  SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
582 
583  int layerIdx = parent->rowCount() - row - 1; // IMPORTANT
584  QgsSymbol *parentSymbol = parent->symbol();
585  QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
586 
587  parent->removeRow( row );
588  parent->updatePreview();
589 
590  QModelIndex newIdx = parent->child( 0 )->index();
591  layersTree->setCurrentIndex( newIdx );
592 
593  updateUi();
594  updatePreview();
595  //finally delete the removed layer pointer
596  delete tmpLayer;
597 }
598 
600 {
601  moveLayerByOffset( + 1 );
602 }
603 
605 {
606  moveLayerByOffset( -1 );
607 }
608 
610 {
611  SymbolLayerItem *item = currentLayerItem();
612  if ( !item )
613  return;
614  int row = item->row();
615 
616  SymbolLayerItem *parent = static_cast<SymbolLayerItem *>( item->parent() );
617  QgsSymbol *parentSymbol = parent->symbol();
618 
619  int layerIdx = parent->rowCount() - row - 1;
620  // switch layers
621  QgsSymbolLayer *tmpLayer = parentSymbol->takeSymbolLayer( layerIdx );
622  parentSymbol->insertSymbolLayer( layerIdx - offset, tmpLayer );
623 
624  QList<QStandardItem *> rowItems = parent->takeRow( row );
625  parent->insertRows( row + offset, rowItems );
626  parent->updatePreview();
627 
628  QModelIndex newIdx = rowItems[ 0 ]->index();
629  layersTree->setCurrentIndex( newIdx );
630 
631  updatePreview();
632  updateUi();
633 }
634 
636 {
637  QgsSymbolLayer *layer = currentLayer();
638  if ( !layer )
639  return;
640  layer->setLocked( btnLock->isChecked() );
641  emit symbolModified();
642 }
643 
645 {
646  QModelIndex idx = layersTree->currentIndex();
647  if ( !idx.isValid() )
648  return;
649 
650  SymbolLayerItem *item = static_cast<SymbolLayerItem *>( model->itemFromIndex( idx ) );
651  if ( !item->isLayer() )
652  return;
653 
654  QgsSymbolLayer *source = item->layer();
655 
656  int insertIdx = item->row();
657  item = static_cast<SymbolLayerItem *>( item->parent() );
658 
659  QgsSymbol *parentSymbol = item->symbol();
660 
661  QgsSymbolLayer *newLayer = source->clone();
662  if ( insertIdx == -1 )
663  parentSymbol->appendSymbolLayer( newLayer );
664  else
665  parentSymbol->insertSymbolLayer( item->rowCount() - insertIdx, newLayer );
666 
667  SymbolLayerItem *newLayerItem = new SymbolLayerItem( newLayer );
668  item->insertRow( insertIdx == -1 ? 0 : insertIdx, newLayerItem );
669  if ( newLayer->subSymbol() )
670  {
671  loadSymbol( newLayer->subSymbol(), newLayerItem );
672  layersTree->setExpanded( newLayerItem->index(), true );
673  }
674  item->updatePreview();
675 
676  layersTree->setCurrentIndex( model->indexFromItem( newLayerItem ) );
677  updateUi();
678  updatePreview();
679 }
680 
682 {
683  SymbolLayerItem *item = currentLayerItem();
684  QgsSymbolLayer *layer = item->layer();
685 
686  if ( layer->subSymbol() )
687  {
688  item->removeRow( 0 );
689  }
690  // update symbol layer item
691  item->setLayer( newLayer );
692  // When it is a marker symbol
693  if ( newLayer->subSymbol() )
694  {
695  loadSymbol( newLayer->subSymbol(), item );
696  layersTree->setExpanded( item->index(), true );
697  }
698 
699  // Change the symbol at last to avoid deleting item's layer
700  QgsSymbol *symbol = static_cast<SymbolLayerItem *>( item->parent() )->symbol();
701  int layerIdx = item->parent()->rowCount() - item->row() - 1;
702  symbol->changeSymbolLayer( layerIdx, newLayer );
703 
704  item->updatePreview();
705  updatePreview();
706  // Important: This lets the layer have its own layer properties widget
707  layerChanged();
708 }
709 
710 QgsSymbolSelectorDialog::QgsSymbolSelectorDialog( QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent, bool embedded )
711  : QDialog( parent )
712 {
713  setLayout( new QVBoxLayout() );
714  mSelectorWidget = new QgsSymbolSelectorWidget( symbol, style, vl, this );
715  mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
716 
717  connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
718  connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
719  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsSymbolSelectorDialog::showHelp );
720 
721  layout()->addWidget( mSelectorWidget );
722  layout()->addWidget( mButtonBox );
723 
724  QgsSettings settings;
725  restoreGeometry( settings.value( QStringLiteral( "Windows/SymbolSelectorWidget/geometry" ) ).toByteArray() );
726 
727  // can be embedded in renderer properties dialog
728  if ( embedded )
729  {
730  mButtonBox->hide();
731  layout()->setContentsMargins( 0, 0, 0, 0 );
732  }
733  else
734  {
735  setWindowTitle( tr( "Symbol Selector" ) );
736  }
737  mSelectorWidget->setDockMode( embedded );
738 }
739 
741 {
742  QgsSettings settings;
743  settings.setValue( QStringLiteral( "Windows/SymbolSelectorWidget/geometry" ), saveGeometry() );
744 }
745 
747 {
748  return mSelectorWidget->advancedMenu();
749 }
750 
752 {
753  mContext = context;
754 }
755 
757 {
758  return mContext;
759 }
760 
762 {
763  return mSelectorWidget->symbol();
764 }
765 
767 {
768  // Ignore the ESC key to avoid close the dialog without the properties window
769  if ( !isWindow() && e->key() == Qt::Key_Escape )
770  {
771  e->ignore();
772  }
773  else
774  {
775  QDialog::keyPressEvent( e );
776  }
777 }
778 
780 {
781  mSelectorWidget->loadSymbol();
782 }
783 
784 void QgsSymbolSelectorDialog::loadSymbol( QgsSymbol *symbol, SymbolLayerItem *parent )
785 {
786  mSelectorWidget->loadSymbol( symbol, parent );
787 }
788 
790 {
791  mSelectorWidget->updateUi();
792 }
793 
795 {
796  mSelectorWidget->updateLockButton();
797 }
798 
800 {
801  return mSelectorWidget->currentLayerItem();
802 }
803 
805 {
806  return mSelectorWidget->currentLayer();
807 }
808 
810 {
811  mSelectorWidget->moveLayerByOffset( offset );
812 }
813 
814 void QgsSymbolSelectorDialog::setWidget( QWidget *widget )
815 {
816  mSelectorWidget->setWidget( widget );
817 }
818 
820 {
821  mSelectorWidget->moveLayerDown();
822 }
823 
825 {
826  mSelectorWidget->moveLayerUp();
827 }
828 
830 {
831  mSelectorWidget->addLayer();
832 }
833 
835 {
836  mSelectorWidget->removeLayer();
837 }
838 
840 {
841  mSelectorWidget->lockLayer();
842 }
843 
845 {
846  mSelectorWidget->duplicateLayer();
847 }
848 
850 {
851  mSelectorWidget->layerChanged();
852 }
853 
855 {
856  mSelectorWidget->updateLayerPreview();
857 }
858 
860 {
861  mSelectorWidget->updatePreview();
862 }
863 
865 {
866  mSelectorWidget->symbolChanged();
867 }
868 
870 {
871  mSelectorWidget->changeLayer( layer );
872 }
873 
874 void QgsSymbolSelectorDialog::showHelp()
875 {
876  QgsHelp::openHelp( QStringLiteral( "working_with_vector/style_library.html#the-symbol-selector" ) );
877 }
void duplicateLayer()
Duplicates the current symbol layer and places the duplicated layer above the current symbol layer...
bool insertSymbolLayer(int index, QgsSymbolLayer *layer)
Insert symbol layer to specified index Ownership will be transferred.
Definition: qgssymbol.cpp:337
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application&#39;s symbol layer registry, used for managing symbol layers. ...
static QgsSvgCache * svgCache()
Returns the application&#39;s SVG cache, used for caching SVG images and handling parameter replacement w...
Wrapper for iterator of features from vector data provider or vector layer.
void connectChildPanel(QgsPanelWidget *panel)
Connect the given sub panel widgets showPanel signals to this current panels main showPanel event to ...
void updateLockButton()
Update the lock button states based on the current symbol layer.
void setLocked(bool locked)
void removeLayer()
Remove the current active symbol layer.
void loadSymbol()
Reload the current symbol in the view.
bool dockMode()
Returns the dock mode state.
virtual QgsSymbol * subSymbol()
Returns the symbol&#39;s sub symbol, if present.
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
bool appendSymbolLayer(QgsSymbolLayer *layer)
Append symbol layer at the end of the list Ownership will be transferred.
Definition: qgssymbol.cpp:350
QgsSymbolSelectorDialog(QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr, bool embedded=false)
Constructor for QgsSymbolSelectorDialog.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void updateLayerPreview()
Update the single symbol layer preview in the widget.
static QgsSymbolLayer * defaultSymbolLayer(QgsSymbol::SymbolType type)
create a new instance of symbol layer for specified symbol type with default settings ...
void lockLayer()
Lock the current active symbol layer.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
void symbolModified()
Emiited when a symbol is modified in the widget.
int symbolLayerCount() const
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:143
Base class for any widget that can be shown as a inline panel.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
bool isLocked() const
Line symbol.
Definition: qgssymbol.h:86
void symbolChanged()
Slot to update tree when a new symbol from style.
void layerChanged()
Called when the layer changes 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 ...
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
static QIcon symbolLayerPreviewIcon(QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit u, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to an icon.
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
void addLayer()
Add a symbol layer to the bottom of the stack.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
static QIcon symbolPreviewIcon(QgsSymbol *symbol, QSize size, int padding=0)
Returns an icon preview for a color ramp.
QgsSymbolLayerAbstractMetadata * symbolLayerMetadata(const QString &name) const
Returns metadata for specified symbol layer. Returns NULL if not found.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void symbolChanged()
Slot to update tree when a new symbol from style.
QgsSymbol::SymbolType type() const
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Symbol selector widget that can be used to select and build a symbol.
void moveLayerUp()
Move the active symbol layer up.
QMenu * advancedMenu()
Returns menu for "advanced" button - create it if doesn&#39;t exist and show the advanced button...
A store for object properties.
Definition: qgsproperty.h:229
QgsSymbolLayer * symbolLayer(int layer)
Returns a specific symbol layers contained in the symbol.
Definition: qgssymbol.cpp:332
void widgetChanged()
Emitted when the widget state changes.
void updateUi()
Update the state of the UI based on the currently set symbol layer.
void changeLayer(QgsSymbolLayer *layer)
alters tree and sets proper widget when Layer Type is changed
QMenu * advancedMenu()
Returns menu for "advanced" button - create it if doesn&#39;t exist and show the advanced button...
QgsSymbolLayer * currentLayer()
The current symbol layer that is active in the interface.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
void setWidget(QWidget *widget)
Set the properties widget for the active symbol layer.
SymbolLayerItem * currentLayerItem()
SymbolLayerItem * currentLayerItem()
bool changeSymbolLayer(int index, QgsSymbolLayer *layer)
delete layer at specified index and set a new one
Definition: qgssymbol.cpp:380
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
Marker symbol.
Definition: qgssymbol.h:85
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
Fill symbol.
Definition: qgssymbol.h:87
Abstract base class for marker symbol layers.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
SymbolType type() const
Definition: qgssymbol.h:113
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void duplicateLayer()
Duplicates the current symbol layer and places the duplicated layer above the current symbol layer...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void changeLayer(QgsSymbolLayer *layer)
alters tree and sets proper widget when Layer Type is changed
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:35
void changeLayer(QgsSymbolLayer *)
QgsSymbolLayer * takeSymbolLayer(int index)
Remove symbol layer from the list and return pointer to it.
Definition: qgssymbol.cpp:371
void moveLayerDown()
Move the active symbol layer down.
void remoteSvgFetched(const QString &url)
Emitted when the cache has finished retrieving an SVG file from a remote url.
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
void keyPressEvent(QKeyEvent *e) override
QImage bigSymbolPreviewImage(QgsExpressionContext *expressionContext=nullptr)
Returns a large (roughly 100x100 pixel) preview image for the symbol.
Definition: qgssymbol.cpp:525
QgsSymbolSelectorWidget(QgsSymbol *symbol, QgsStyle *style, QgsVectorLayer *vl, QWidget *parent=nullptr)
Symbol selector widget that can be used to select and build a symbol.
Represents a vector layer which manages a vector based data sets.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
void updatePreview()
Update the preview of the whole symbol in the interface.
void moveLayerByOffset(int offset)
Move the current active layer by a set offset in the list.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...