QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgssymbolslistwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbolslist.cpp
3  ---------------------
4  begin : June 2012
5  copyright : (C) 2012 by Arunmozhi
6  email : aruntheguy at gmail.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 
16 
17 #include "qgssymbolslistwidget.h"
18 
19 #include "qgsstylemanagerdialog.h"
20 #include "qgsstylesavedialog.h"
21 
22 #include "qgssymbol.h"
23 #include "qgsstyle.h"
24 #include "qgssymbollayerutils.h"
25 #include "qgsmarkersymbollayer.h"
26 #include "qgsmapcanvas.h"
27 #include "qgsapplication.h"
28 #include "qgsvectorlayer.h"
29 #include "qgssettings.h"
31 #include "qgsauxiliarystorage.h"
32 #include "qgsstylemodel.h"
33 #include "qgsgui.h"
35 
36 #include <QAction>
37 #include <QString>
38 #include <QStringList>
39 #include <QPainter>
40 #include <QIcon>
41 #include <QStandardItemModel>
42 #include <QColorDialog>
43 #include <QInputDialog>
44 #include <QMessageBox>
45 #include <QMenu>
46 #include <QPushButton>
47 
48 
49 //
50 // QgsReadOnlyStyleModel
51 //
52 
54 QgsReadOnlyStyleModel::QgsReadOnlyStyleModel( QgsStyle *style, QObject *parent )
55  : QgsStyleProxyModel( style, parent )
56 {
57 
58 }
59 
60 Qt::ItemFlags QgsReadOnlyStyleModel::flags( const QModelIndex &index ) const
61 {
62  return QgsStyleProxyModel::flags( index ) & ~Qt::ItemIsEditable;
63 }
64 
65 QVariant QgsReadOnlyStyleModel::data( const QModelIndex &index, int role ) const
66 {
67  if ( role == Qt::FontRole )
68  {
69  // drop font size to get reasonable amount of item name shown
70  QFont f = QgsStyleProxyModel::data( index, role ).value< QFont >();
71  f.setPointSize( 9 );
72  return f;
73  }
74  return QgsStyleProxyModel::data( index, role );
75 }
76 
78 
79 
80 //
81 // QgsSymbolsListWidget
82 //
83 
84 QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent, QgsVectorLayer *layer )
85  : QWidget( parent )
86  , mSymbol( symbol )
87  , mStyle( style )
88  , mLayer( layer )
89 {
90  setupUi( this );
91  connect( mSymbolUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSymbolsListWidget::mSymbolUnitWidget_changed );
92  spinAngle->setClearValue( 0 );
93 
96 
97  mModel = new QgsReadOnlyStyleModel( mStyle, this );
98  mModel->setEntityFilterEnabled( true );
100  if ( mSymbol )
101  {
102  mModel->setSymbolTypeFilterEnabled( true );
103  mModel->setSymbolType( mSymbol->type() );
104  }
105 
106  btnAdvanced->hide(); // advanced button is hidden by default
107  if ( menu ) // show it if there is a menu pointer
108  {
109  mAdvancedMenu = menu;
110  btnAdvanced->show();
111  btnAdvanced->setMenu( mAdvancedMenu );
112  }
113  else
114  {
115  btnAdvanced->setMenu( new QMenu( this ) );
116  }
117  mClipFeaturesAction = new QAction( tr( "Clip Features to Canvas Extent" ), this );
118  mClipFeaturesAction->setCheckable( true );
119  connect( mClipFeaturesAction, &QAction::toggled, this, &QgsSymbolsListWidget::clipFeaturesToggled );
120  mStandardizeRingsAction = new QAction( tr( "Force Right-Hand-Rule Orientation" ), this );
121  mStandardizeRingsAction->setCheckable( true );
122  connect( mStandardizeRingsAction, &QAction::toggled, this, &QgsSymbolsListWidget::forceRHRToggled );
123 
124  double iconSize = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 10;
125  viewSymbols->setIconSize( QSize( static_cast< int >( iconSize ), static_cast< int >( iconSize * 0.9 ) ) ); // ~100, 90 on low dpi
126  double treeIconSize = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 2;
127  mSymbolTreeView->setIconSize( QSize( static_cast< int >( treeIconSize ), static_cast< int >( treeIconSize ) ) );
128 
129  mModel->addDesiredIconSize( viewSymbols->iconSize() );
130  mModel->addDesiredIconSize( mSymbolTreeView->iconSize() );
131  viewSymbols->setModel( mModel );
132  mSymbolTreeView->setModel( mModel );
133 
134  viewSymbols->setSelectionBehavior( QAbstractItemView::SelectRows );
135  mSymbolTreeView->setSelectionModel( viewSymbols->selectionModel() );
136  mSymbolTreeView->setSelectionMode( viewSymbols->selectionMode() );
137 
138  connect( viewSymbols->selectionModel(), &QItemSelectionModel::currentChanged, this, &QgsSymbolsListWidget::setSymbolFromStyle );
139 
141 
142  connect( openStyleManagerButton, &QToolButton::clicked, this, &QgsSymbolsListWidget::openStyleManager );
143 
144  lblSymbolName->clear();
145 
146  connect( mButtonIconView, &QToolButton::toggled, this, [ = ]( bool active )
147  {
148  if ( active )
149  {
150  mSymbolViewStackedWidget->setCurrentIndex( 0 );
151  // note -- we have to save state here and not in destructor, as new symbol list widgets are created before the previous ones are destroyed
152  QgsSettings().setValue( QStringLiteral( "UI/symbolsList/lastIconView" ), 0, QgsSettings::Gui );
153  }
154  } );
155  connect( mButtonListView, &QToolButton::toggled, this, [ = ]( bool active )
156  {
157  if ( active )
158  {
159  QgsSettings().setValue( QStringLiteral( "UI/symbolsList/lastIconView" ), 1, QgsSettings::Gui );
160  mSymbolViewStackedWidget->setCurrentIndex( 1 );
161  }
162  } );
163 
164  // restore previous view
165  QgsSettings settings;
166  const int currentView = settings.value( QStringLiteral( "UI/symbolsList/lastIconView" ), 0, QgsSettings::Gui ).toInt();
167  if ( currentView == 0 )
168  mButtonIconView->setChecked( true );
169  else
170  mButtonListView->setChecked( true );
171 
172  mSymbolTreeView->header()->restoreState( settings.value( QStringLiteral( "UI/symbolsList/treeState" ), QByteArray(), QgsSettings::Gui ).toByteArray() );
173  connect( mSymbolTreeView->header(), &QHeaderView::sectionResized, this, [this]
174  {
175  // note -- we have to save state here and not in destructor, as new symbol list widgets are created before the previous ones are destroyed
176  QgsSettings().setValue( QStringLiteral( "UI/symbolsList/treeState" ), mSymbolTreeView->header()->saveState(), QgsSettings::Gui );
177  } );
178 
179  QgsFilterLineEdit *groupEdit = new QgsFilterLineEdit();
180  groupEdit->setShowSearchIcon( true );
181  groupEdit->setShowClearButton( true );
182  groupEdit->setPlaceholderText( tr( "Filter symbols…" ) );
183  groupsCombo->setLineEdit( groupEdit );
184  populateGroups();
185  connect( groupsCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsSymbolsListWidget::groupsCombo_currentIndexChanged );
186  connect( groupsCombo, &QComboBox::currentTextChanged, this, &QgsSymbolsListWidget::updateModelFilters );
187 
188  if ( mSymbol )
189  {
190  updateSymbolInfo();
191  }
192 
193  // select correct page in stacked widget
194  // there's a correspondence between symbol type number and page numbering => exploit it!
195  stackedWidget->setCurrentIndex( symbol->type() );
197  connect( spinAngle, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSymbolsListWidget::setMarkerAngle );
198  connect( spinSize, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSymbolsListWidget::setMarkerSize );
199  connect( spinWidth, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSymbolsListWidget::setLineWidth );
200 
201  registerDataDefinedButton( mRotationDDBtn, QgsSymbolLayer::PropertyAngle );
203  registerDataDefinedButton( mSizeDDBtn, QgsSymbolLayer::PropertySize );
205  registerDataDefinedButton( mWidthDDBtn, QgsSymbolLayer::PropertyStrokeWidth );
207 
208  connect( this, &QgsSymbolsListWidget::changed, this, &QgsSymbolsListWidget::updateAssistantSymbol );
209  updateAssistantSymbol();
210 
211  btnColor->setAllowOpacity( true );
212  btnColor->setColorDialogTitle( tr( "Select Color" ) );
213  btnColor->setContext( QStringLiteral( "symbology" ) );
214  connect( btnSaveSymbol, &QPushButton::clicked, this, &QgsSymbolsListWidget::saveSymbol );
215 
216  connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsSymbolsListWidget::opacityChanged );
217 }
218 
220 {
221  // This action was added to the menu by this widget, clean it up
222  // The menu can be passed in the constructor, so may live longer than this widget
223  btnAdvanced->menu()->removeAction( mClipFeaturesAction );
224  btnAdvanced->menu()->removeAction( mStandardizeRingsAction );
225 }
226 
227 void QgsSymbolsListWidget::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsSymbolLayer::Property key )
228 {
229  button->setProperty( "propertyKey", key );
230  button->registerExpressionContextGenerator( this );
231 
232  connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsSymbolsListWidget::createAuxiliaryField );
233 }
234 
235 void QgsSymbolsListWidget::createAuxiliaryField()
236 {
237  // try to create an auxiliary layer if not yet created
238  if ( !mLayer->auxiliaryLayer() )
239  {
240  QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
241  dlg.exec();
242  }
243 
244  // return if still not exists
245  if ( !mLayer->auxiliaryLayer() )
246  return;
247 
248  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
249  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() );
251 
252  // create property in auxiliary storage if necessary
253  if ( !mLayer->auxiliaryLayer()->exists( def ) )
254  mLayer->auxiliaryLayer()->addAuxiliaryField( def );
255 
256  // update property with join field name from auxiliary storage
257  QgsProperty property = button->toProperty();
258  property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
259  property.setActive( true );
260  button->updateFieldLists();
261  button->setToProperty( property );
262 
263  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
264  QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( mSymbol );
265  switch ( key )
266  {
268  if ( markerSymbol )
269  markerSymbol->setDataDefinedAngle( button->toProperty() );
270  break;
271 
273  if ( markerSymbol )
274  {
275  markerSymbol->setDataDefinedSize( button->toProperty() );
276  markerSymbol->setScaleMethod( QgsSymbol::ScaleDiameter );
277  }
278  break;
279 
281  if ( lineSymbol )
282  lineSymbol->setDataDefinedWidth( button->toProperty() );
283  break;
284 
285  default:
286  break;
287  }
288 
289  emit changed();
290 }
291 
293 {
294  mContext = context;
295  const auto unitSelectionWidgets { findChildren<QgsUnitSelectionWidget *>() };
296  for ( QgsUnitSelectionWidget *unitWidget : unitSelectionWidgets )
297  {
298  unitWidget->setMapCanvas( mContext.mapCanvas() );
299  }
300 #if 0
301  Q_FOREACH ( QgsPropertyOverrideButton *ddButton, findChildren<QgsPropertyOverrideButton *>() )
302  {
303  if ( ddButton->assistant() )
304  ddButton->assistant()->setMapCanvas( mContext.mapCanvas() );
305  }
306 #endif
307 }
308 
310 {
311  return mContext;
312 }
313 
315 {
316  mUpdatingGroups = true;
317  groupsCombo->blockSignals( true );
318  groupsCombo->clear();
319 
320  groupsCombo->addItem( tr( "Favorites" ), QVariant( "favorite" ) );
321  groupsCombo->addItem( tr( "All Symbols" ), QVariant( "all" ) );
322 
323  int index = 2;
324  QStringList tags = mStyle->tags();
325  if ( tags.count() > 0 )
326  {
327  tags.sort();
328  groupsCombo->insertSeparator( index );
329  const auto constTags = tags;
330  for ( const QString &tag : constTags )
331  {
332  groupsCombo->addItem( tag, QVariant( "tag" ) );
333  index++;
334  }
335  }
336 
337  QStringList groups = mStyle->smartgroupNames();
338  if ( groups.count() > 0 )
339  {
340  groups.sort();
341  groupsCombo->insertSeparator( index + 1 );
342  const auto constGroups = groups;
343  for ( const QString &group : constGroups )
344  {
345  groupsCombo->addItem( group, QVariant( "smartgroup" ) );
346  }
347  }
348  groupsCombo->blockSignals( false );
349 
350  QgsSettings settings;
351  index = settings.value( QStringLiteral( "qgis/symbolsListGroupsIndex" ), 0 ).toInt();
352  groupsCombo->setCurrentIndex( index );
353 
354  mUpdatingGroups = false;
355 
356  updateModelFilters();
357 }
358 
359 void QgsSymbolsListWidget::updateModelFilters()
360 {
361  if ( mUpdatingGroups )
362  return;
363 
364  const QString text = groupsCombo->currentText();
365  const bool isFreeText = text != groupsCombo->itemText( groupsCombo->currentIndex() );
366 
367  if ( isFreeText )
368  {
369  mModel->setFavoritesOnly( false );
370  mModel->setTagId( -1 );
371  mModel->setSmartGroupId( -1 );
372  mModel->setFilterString( groupsCombo->currentText() );
373  }
374  else if ( groupsCombo->currentData().toString() == QLatin1String( "favorite" ) )
375  {
376  mModel->setFavoritesOnly( true );
377  mModel->setTagId( -1 );
378  mModel->setSmartGroupId( -1 );
379  mModel->setFilterString( QString() );
380  }
381  else if ( groupsCombo->currentData().toString() == QLatin1String( "all" ) )
382  {
383  mModel->setFavoritesOnly( false );
384  mModel->setTagId( -1 );
385  mModel->setSmartGroupId( -1 );
386  mModel->setFilterString( QString() );
387  }
388  else if ( groupsCombo->currentData().toString() == QLatin1String( "smartgroup" ) )
389  {
390  mModel->setFavoritesOnly( false );
391  mModel->setTagId( -1 );
392  mModel->setSmartGroupId( mStyle->smartgroupId( text ) );
393  mModel->setFilterString( QString() );
394  }
395  else
396  {
397  mModel->setFavoritesOnly( false );
398  mModel->setTagId( mStyle->tagId( text ) );
399  mModel->setSmartGroupId( -1 );
400  mModel->setFilterString( QString() );
401  }
402 }
403 
404 void QgsSymbolsListWidget::forceRHRToggled( bool checked )
405 {
406  if ( !mSymbol )
407  return;
408 
409  mSymbol->setForceRHR( checked );
410  emit changed();
411 }
412 
414 {
415  // prefer to use global window manager to open the style manager, if possible!
416  // this allows reuse of an existing non-modal window instead of opening a new modal window.
417  // Note that we only use the non-modal dialog if we're open in the panel -- if we're already
418  // open as part of a modal dialog, then we MUST use another modal dialog or the result will
419  // not be focusable!
421  if ( !panel || !panel->dockMode()
423  || !QgsGui::windowManager()->openStandardDialog( QgsWindowManagerInterface::DialogStyleManager ) )
424  {
425  // fallback to modal dialog
426  QgsStyleManagerDialog dlg( mStyle, this );
427  dlg.exec();
428 
429  updateModelFilters(); // probably not needed -- the model should automatically update if any changes were made
430  }
431 }
432 
434 {
435  if ( !mSymbol )
436  return;
437 
438  mSymbol->setClipFeaturesToExtent( checked );
439  emit changed();
440 }
441 
442 void QgsSymbolsListWidget::setSymbolColor( const QColor &color )
443 {
444  mSymbol->setColor( color );
445  emit changed();
446 }
447 
449 {
450  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
451  if ( markerSymbol->angle() == angle )
452  return;
453  markerSymbol->setAngle( angle );
454  emit changed();
455 }
456 
458 {
459  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
460  QgsProperty dd( mRotationDDBtn->toProperty() );
461 
462  spinAngle->setEnabled( !mRotationDDBtn->isActive() );
463 
464  QgsProperty symbolDD( markerSymbol->dataDefinedAngle() );
465 
466  if ( // shall we remove datadefined expressions for layers ?
467  ( !symbolDD && !dd )
468  // shall we set the "en masse" expression for properties ?
469  || dd )
470  {
471  markerSymbol->setDataDefinedAngle( dd );
472  emit changed();
473  }
474 }
475 
477 {
478  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
479  if ( markerSymbol->size() == size )
480  return;
481  markerSymbol->setSize( size );
482  emit changed();
483 }
484 
486 {
487  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
488  QgsProperty dd( mSizeDDBtn->toProperty() );
489 
490  spinSize->setEnabled( !mSizeDDBtn->isActive() );
491 
492  QgsProperty symbolDD( markerSymbol->dataDefinedSize() );
493 
494  if ( // shall we remove datadefined expressions for layers ?
495  ( !symbolDD && !dd )
496  // shall we set the "en masse" expression for properties ?
497  || dd )
498  {
499  markerSymbol->setDataDefinedSize( dd );
500  markerSymbol->setScaleMethod( QgsSymbol::ScaleDiameter );
501  emit changed();
502  }
503 }
504 
506 {
507  QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( mSymbol );
508  if ( lineSymbol->width() == width )
509  return;
510  lineSymbol->setWidth( width );
511  emit changed();
512 }
513 
515 {
516  QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( mSymbol );
517  QgsProperty dd( mWidthDDBtn->toProperty() );
518 
519  spinWidth->setEnabled( !mWidthDDBtn->isActive() );
520 
521  QgsProperty symbolDD( lineSymbol->dataDefinedWidth() );
522 
523  if ( // shall we remove datadefined expressions for layers ?
524  ( !symbolDD && !dd )
525  // shall we set the "en masse" expression for properties ?
526  || dd )
527  {
528  lineSymbol->setDataDefinedWidth( dd );
529  emit changed();
530  }
531 }
532 
533 void QgsSymbolsListWidget::updateAssistantSymbol()
534 {
535  mAssistantSymbol.reset( mSymbol->clone() );
536  if ( mSymbol->type() == QgsSymbol::Marker )
537  mSizeDDBtn->setSymbol( mAssistantSymbol );
538  else if ( mSymbol->type() == QgsSymbol::Line && mLayer )
539  mWidthDDBtn->setSymbol( mAssistantSymbol );
540 }
541 
543 {
544  bool ok;
545  QString name = QInputDialog::getText( this, tr( "Save Symbol" ),
546  tr( "Please enter name for the symbol:" ), QLineEdit::Normal, tr( "New symbol" ), &ok );
547  if ( !ok || name.isEmpty() )
548  return;
549 
550  // check if there is no symbol with same name
551  if ( mStyle->symbolNames().contains( name ) )
552  {
553  int res = QMessageBox::warning( this, tr( "Save Symbol" ),
554  tr( "Symbol with name '%1' already exists. Overwrite?" )
555  .arg( name ),
556  QMessageBox::Yes | QMessageBox::No );
557  if ( res != QMessageBox::Yes )
558  {
559  return;
560  }
561  }
562 
563  // add new symbol to style and re-populate the list
564  mStyle->addSymbol( name, mSymbol->clone() );
565 
566  // make sure the symbol is stored
567  mStyle->saveSymbol( name, mSymbol->clone(), false, QStringList() );
568 }
569 
571 {
572  QgsStyleSaveDialog saveDlg( this );
573  if ( !saveDlg.exec() )
574  return;
575 
576  if ( saveDlg.name().isEmpty() )
577  return;
578 
579  // check if there is no symbol with same name
580  if ( mStyle->symbolNames().contains( saveDlg.name() ) )
581  {
582  int res = QMessageBox::warning( this, tr( "Save Symbol" ),
583  tr( "Symbol with name '%1' already exists. Overwrite?" )
584  .arg( saveDlg.name() ),
585  QMessageBox::Yes | QMessageBox::No );
586  if ( res != QMessageBox::Yes )
587  {
588  return;
589  }
590  mStyle->removeSymbol( saveDlg.name() );
591  }
592 
593  QStringList symbolTags = saveDlg.tags().split( ',' );
594 
595  // add new symbol to style and re-populate the list
596  mStyle->addSymbol( saveDlg.name(), mSymbol->clone() );
597 
598  // make sure the symbol is stored
599  mStyle->saveSymbol( saveDlg.name(), mSymbol->clone(), saveDlg.isFavorite(), symbolTags );
600 }
601 
602 void QgsSymbolsListWidget::mSymbolUnitWidget_changed()
603 {
604  if ( mSymbol )
605  {
606 
607  mSymbol->setOutputUnit( mSymbolUnitWidget->unit() );
608  mSymbol->setMapUnitScale( mSymbolUnitWidget->getMapUnitScale() );
609 
610  emit changed();
611  }
612 }
613 
614 void QgsSymbolsListWidget::opacityChanged( double opacity )
615 {
616  if ( mSymbol )
617  {
618  mSymbol->setOpacity( opacity );
619  emit changed();
620  }
621 }
622 
623 void QgsSymbolsListWidget::updateSymbolColor()
624 {
625  btnColor->blockSignals( true );
626  btnColor->setColor( mSymbol->color() );
627  btnColor->blockSignals( false );
628 }
629 
630 QgsExpressionContext QgsSymbolsListWidget::createExpressionContext() const
631 {
632  if ( mContext.expressionContext() )
633  return QgsExpressionContext( *mContext.expressionContext() );
634 
635  //otherwise create a default symbol context
636  QgsExpressionContext expContext( mContext.globalProjectAtlasMapLayerScopes( layer() ) );
637 
638  // additional scopes
639  const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
640  for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes )
641  {
642  expContext.appendScope( new QgsExpressionContextScope( scope ) );
643  }
644 
645  expContext.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_ORIGINAL_VALUE << QgsExpressionContext::EXPR_SYMBOL_COLOR
649 
650  return expContext;
651 }
652 
653 void QgsSymbolsListWidget::updateSymbolInfo()
654 {
655  updateSymbolColor();
656 
657  const auto overrideButtons {findChildren< QgsPropertyOverrideButton * >()};
658  for ( QgsPropertyOverrideButton *button : overrideButtons )
659  {
660  button->registerExpressionContextGenerator( this );
661  }
662 
663  if ( mSymbol->type() == QgsSymbol::Marker )
664  {
665  QgsMarkerSymbol *markerSymbol = static_cast<QgsMarkerSymbol *>( mSymbol );
666  spinSize->setValue( markerSymbol->size() );
667  spinAngle->setValue( markerSymbol->angle() );
668 
669  if ( mLayer )
670  {
671  QgsProperty ddSize( markerSymbol->dataDefinedSize() );
672  mSizeDDBtn->init( QgsSymbolLayer::PropertySize, ddSize, QgsSymbolLayer::propertyDefinitions(), mLayer, true );
673  spinSize->setEnabled( !mSizeDDBtn->isActive() );
674  QgsProperty ddAngle( markerSymbol->dataDefinedAngle() );
675  mRotationDDBtn->init( QgsSymbolLayer::PropertyAngle, ddAngle, QgsSymbolLayer::propertyDefinitions(), mLayer, true );
676  spinAngle->setEnabled( !mRotationDDBtn->isActive() );
677  }
678  else
679  {
680  mSizeDDBtn->setEnabled( false );
681  mRotationDDBtn->setEnabled( false );
682  }
683  }
684  else if ( mSymbol->type() == QgsSymbol::Line )
685  {
686  QgsLineSymbol *lineSymbol = static_cast<QgsLineSymbol *>( mSymbol );
687  spinWidth->setValue( lineSymbol->width() );
688 
689  if ( mLayer )
690  {
691  QgsProperty dd( lineSymbol->dataDefinedWidth() );
692  mWidthDDBtn->init( QgsSymbolLayer::PropertyStrokeWidth, dd, QgsSymbolLayer::propertyDefinitions(), mLayer, true );
693  spinWidth->setEnabled( !mWidthDDBtn->isActive() );
694  }
695  else
696  {
697  mWidthDDBtn->setEnabled( false );
698  }
699  }
700 
701  mSymbolUnitWidget->blockSignals( true );
702  mSymbolUnitWidget->setUnit( mSymbol->outputUnit() );
703  mSymbolUnitWidget->setMapUnitScale( mSymbol->mapUnitScale() );
704  mSymbolUnitWidget->blockSignals( false );
705 
706  mOpacityWidget->setOpacity( mSymbol->opacity() );
707 
708  // Clean up previous advanced symbol actions
709  const QList<QAction *> actionList( btnAdvanced->menu()->actions() );
710  for ( const auto &action : actionList )
711  {
712  if ( mClipFeaturesAction->text() == action->text() )
713  {
714  btnAdvanced->menu()->removeAction( action );
715  }
716  else if ( mStandardizeRingsAction->text() == action->text() )
717  {
718  btnAdvanced->menu()->removeAction( action );
719  }
720  }
721 
722  if ( mSymbol->type() == QgsSymbol::Line || mSymbol->type() == QgsSymbol::Fill )
723  {
724  //add clip features option for line or fill symbols
725  btnAdvanced->menu()->addAction( mClipFeaturesAction );
726  }
727  if ( mSymbol->type() == QgsSymbol::Fill )
728  {
729  btnAdvanced->menu()->addAction( mStandardizeRingsAction );
730  }
731 
732  btnAdvanced->setVisible( mAdvancedMenu || !btnAdvanced->menu()->isEmpty() );
733 
734  whileBlocking( mClipFeaturesAction )->setChecked( mSymbol->clipFeaturesToExtent() );
735  whileBlocking( mStandardizeRingsAction )->setChecked( mSymbol->forceRHR() );
736 }
737 
738 void QgsSymbolsListWidget::setSymbolFromStyle( const QModelIndex &index )
739 {
740  QString symbolName = mModel->data( mModel->index( index.row(), QgsStyleModel::Name ) ).toString();
741  lblSymbolName->setText( symbolName );
742  // get new instance of symbol from style
743  std::unique_ptr< QgsSymbol > s( mStyle->symbol( symbolName ) );
744  if ( !s )
745  return;
746 
747  // remove all symbol layers from original symbolgroupsCombo
748  while ( mSymbol->symbolLayerCount() )
749  mSymbol->deleteSymbolLayer( 0 );
750  // move all symbol layers to our symbol
751  while ( s->symbolLayerCount() )
752  {
753  QgsSymbolLayer *sl = s->takeSymbolLayer( 0 );
754  mSymbol->appendSymbolLayer( sl );
755  }
756  mSymbol->setOpacity( s->opacity() );
757 
758  updateSymbolInfo();
759  emit changed();
760 }
761 
762 void QgsSymbolsListWidget::groupsCombo_currentIndexChanged( int index )
763 {
764  QgsSettings settings;
765  settings.setValue( QStringLiteral( "qgis/symbolsListGroupsIndex" ), index );
766 }
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
static const QString EXPR_CLUSTER_COLOR
Inbuilt variable name for cluster color variable.
Meters value as Map units.
Definition: qgsunittypes.h:120
QList< QgsExpressionContextScope * > globalProjectAtlasMapLayerScopes(const QgsMapLayer *layer) const
Returns list of scopes: global, project, atlas, map, layer.
void setFilterString(const QString &filter)
Sets a filter string, such that only symbol entities with names matching the specified string will be...
void setLineWidth(double width)
static QgsWindowManagerInterface * windowManager()
Returns the global window manager, if set.
Definition: qgsgui.cpp:113
QString tags() const
returns the text value of the tags element
bool dockMode()
Returns the dock mode state.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
void setSymbolFromStyle(const QModelIndex &index)
A dialog allowing users to customize and populate a QgsStyle.
void setSmartGroupId(int id)
Sets a smart group id to filter style entities by.
void setMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol.
Definition: qgssymbol.cpp:284
Calculate scale by the diameter.
Definition: qgssymbol.h:97
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
a dialog for setting properties of a newly saved style.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:139
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
bool appendSymbolLayer(QgsSymbolLayer *layer)
Appends a symbol layer at the end of the current symbol layer list.
Definition: qgssymbol.cpp:376
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setTagId(int id)
Sets a tag id to filter style entities by.
QgsMapUnitScale mapUnitScale() const
Returns the map unit scale for the symbol.
Definition: qgssymbol.cpp:251
QString name() const
returns the text value of the name element
void setSize(double size)
Sets the size for the whole symbol.
Definition: qgssymbol.cpp:1318
bool clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context&#39;s extent...
Definition: qgssymbol.h:380
void setSymbolType(QgsSymbol::SymbolType type)
Sets the symbol type filter.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Definition: qgssymbol.h:150
Base class for any widget that can be shown as a inline panel.
void setMarkerSize(double size)
bool deleteSymbolLayer(int index)
Removes and deletes the symbol layer at the specified index.
Definition: qgssymbol.cpp:386
void setDataDefinedAngle(const QgsProperty &property)
Set data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1242
Line symbol.
Definition: qgssymbol.h:86
void setAngle(double symbolAngle)
Sets the angle for the whole symbol.
Definition: qgssymbol.cpp:1204
void setFavoritesOnly(bool favoritesOnly)
Sets whether the model should show only favorited entities.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:184
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:766
void populateGroups()
Pupulates the groups combo box with available tags and smartgroups.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:966
QgsUnitTypes::RenderUnit outputUnit() const
Returns the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:230
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:275
void setSymbolTypeFilterEnabled(bool enabled)
Sets whether filtering by symbol type is enabled.
void createAuxiliaryField()
Emitted when creating a new auxiliary field.
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1271
A dialog to create a new auxiliary layer.
void setField(const QString &field)
Sets the field name the property references.
void setEntityFilterEnabled(bool enabled)
Sets whether filtering by entity type is enabled.
void addDesiredIconSize(QSize size)
Adds an additional icon size to generate for Qt::DecorationRole data.
A button for controlling property overrides which may apply to a widget.
QStringList symbolNames()
Returns a list of names of symbols.
Definition: qgsstyle.cpp:191
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
bool forceRHR() const
Returns true if polygon features drawn by the symbol will be reoriented to follow the standard right-...
Definition: qgssymbol.h:402
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
void setToProperty(const QgsProperty &property)
Sets the widget to reflect the current state of a QgsProperty.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:346
void setWidth(double width)
Sets the width for the whole line symbol.
Definition: qgssymbol.cpp:1664
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
Definition: qgssymbol.cpp:1691
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void groupsModified()
Emitted every time a tag or smartgroup has been added, removed, or renamed.
void setSymbolColor(const QColor &color)
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
QLineEdit subclass with built in support for clearing the widget&#39;s value and handling custom null val...
QColor color() const
Returns the symbol&#39;s color.
Definition: qgssymbol.cpp:480
void setMarkerAngle(double angle)
void setScaleMethod(QgsSymbol::ScaleMethod scaleMethod)
Definition: qgssymbol.cpp:1532
Single scope for storing variables and functions for use within a QgsExpressionContext.
A store for object properties.
Definition: qgsproperty.h:229
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
A QSortFilterProxyModel subclass for showing filtered symbol and color ramps entries from a QgsStyle ...
void setDataDefinedWidth(const QgsProperty &property)
Set data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1726
const QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition for a property.
Definition: qgsproperty.h:46
int smartgroupId(const QString &smartgroup)
Returns the DB id for the given smartgroup name.
Definition: qgsstyle.cpp:1223
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1476
QStringList smartgroupNames()
Returns the smart groups list.
Definition: qgsstyle.cpp:1305
int tagId(const QString &tag)
Returns the DB id for the given tag name.
Definition: qgsstyle.cpp:1218
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
void changed()
Emitted when property definition changes.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
void clipFeaturesToggled(bool checked)
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
bool addSymbol(const QString &name, QgsSymbol *symbol, bool update=false)
Adds a symbol to style and takes symbol&#39;s ownership.
Definition: qgsstyle.cpp:88
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QStringList tags() const
Returns a list of all tags in the style database.
Definition: qgsstyle.cpp:647
Fill symbol.
Definition: qgssymbol.h:87
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:212
Name column.
Definition: qgsstylemodel.h:50
Points (e.g., for font sizes)
Definition: qgsunittypes.h:117
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:120
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
Definition: qgssymbol.cpp:1342
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
int propertyKey() const
Returns the property key linked to the button.
static const QString EXPR_CLUSTER_SIZE
Inbuilt variable name for cluster size variable.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
bool isFavorite() const
returns whether the favorite element is checked
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:175
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void setDataDefinedSize(const QgsProperty &property)
Set data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1439
bool saveSymbol(const QString &name, QgsSymbol *symbol, bool favorite, const QStringList &tags)
Adds the symbol to the DB with the tags.
Definition: qgsstyle.cpp:112
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context&#39;s extent...
Definition: qgssymbol.h:369
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:339
bool removeSymbol(const QString &name)
Removes symbol from style (and delete it)
Definition: qgsstyle.cpp:143
void setEntityFilter(QgsStyle::StyleEntity filter)
Sets the style entity type filter.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
void setForceRHR(bool force)
Sets whether polygon features drawn by the symbol should be reoriented to follow the standard right-h...
Definition: qgssymbol.h:391
A widget displaying a combobox allowing the user to choose between various display units...
bool addAuxiliaryField(const QgsPropertyDefinition &definition)
Adds an auxiliary field for the given property.
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
Represents a vector layer which manages a vector based data sets.
void updateFieldLists()
Updates list of fields.
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1762
double angle() const
Returns the marker angle for the whole symbol.
Definition: qgssymbol.cpp:1217
QgsSymbolsListWidget(QgsSymbol *symbol, QgsStyle *style, QMenu *menu, QWidget *parent, QgsVectorLayer *layer=nullptr)
Constructor for QgsSymbolsListWidget.
Property
Data definable properties.
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:470