QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsstylemanagerdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsstylemanagerdialog.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 
16 #include "qgsstylemanagerdialog.h"
17 #include "qgsstylesavedialog.h"
18 
19 #include "qgssymbol.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgscolorramp.h"
22 
31 #include "qgssettings.h"
32 #include "qgsstylemodel.h"
33 #include "qgsmessagebar.h"
34 
35 #include <QAction>
36 #include <QFile>
37 #include <QFileDialog>
38 #include <QInputDialog>
39 #include <QMessageBox>
40 #include <QPushButton>
41 #include <QStandardItemModel>
42 #include <QMenu>
43 
44 #include "qgsapplication.h"
45 #include "qgslogger.h"
46 
47 //
48 // QgsCheckableStyleModel
49 //
50 
52 QgsCheckableStyleModel::QgsCheckableStyleModel( QgsStyle *style, QObject *parent, bool readOnly )
53  : QgsStyleProxyModel( style, parent )
54  , mStyle( style )
55  , mReadOnly( readOnly )
56 {
57 
58 }
59 
60 void QgsCheckableStyleModel::setCheckable( bool checkable )
61 {
62  if ( checkable == mCheckable )
63  return;
64 
65  mCheckable = checkable;
66  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector< int >() << Qt::CheckStateRole );
67 }
68 
69 void QgsCheckableStyleModel::setCheckTag( const QString &tag )
70 {
71  if ( tag == mCheckTag )
72  return;
73 
74  mCheckTag = tag;
75  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector< int >() << Qt::CheckStateRole );
76 }
77 
78 Qt::ItemFlags QgsCheckableStyleModel::flags( const QModelIndex &index ) const
79 {
80  Qt::ItemFlags f = QgsStyleProxyModel::flags( index );
81  if ( !mReadOnly && mCheckable && index.column() == 0 )
82  f |= Qt::ItemIsUserCheckable;
83 
84  if ( mReadOnly )
85  f &= ~Qt::ItemIsEditable;
86 
87  return f;
88 }
89 
90 QVariant QgsCheckableStyleModel::data( const QModelIndex &index, int role ) const
91 {
92  switch ( role )
93  {
94  case Qt::FontRole:
95  {
96  // drop font size to get reasonable amount of item name shown
97  QFont f = QgsStyleProxyModel::data( index, role ).value< QFont >();
98  f.setPointSize( 9 );
99  return f;
100  }
101 
102  case Qt::CheckStateRole:
103  {
104  if ( !mCheckable || index.column() != 0 )
105  return QVariant();
106 
107  const QStringList tags = data( index, QgsStyleModel::TagRole ).toStringList();
108  return tags.contains( mCheckTag ) ? Qt::Checked : Qt::Unchecked;
109  }
110 
111  default:
112  break;
113 
114  }
115  return QgsStyleProxyModel::data( index, role );
116 }
117 
118 bool QgsCheckableStyleModel::setData( const QModelIndex &i, const QVariant &value, int role )
119 {
120  if ( i.row() < 0 || i.row() >= rowCount( QModelIndex() ) ||
121  ( role != Qt::EditRole && role != Qt::CheckStateRole ) )
122  return false;
123 
124  if ( mReadOnly )
125  return false;
126 
127  if ( role == Qt::CheckStateRole )
128  {
129  if ( !mCheckable || mCheckTag.isEmpty() )
130  return false;
131 
132  const QString name = data( index( i.row(), QgsStyleModel::Name ), Qt::DisplayRole ).toString();
133  const QgsStyle::StyleEntity entity = static_cast< QgsStyle::StyleEntity >( data( i, QgsStyleModel::TypeRole ).toInt() );
134 
135  if ( value.toInt() == Qt::Checked )
136  return mStyle->tagSymbol( entity, name, QStringList() << mCheckTag );
137  else
138  return mStyle->detagSymbol( entity, name, QStringList() << mCheckTag );
139  }
140  return QgsStyleProxyModel::setData( i, value, role );
141 }
143 
144 //
145 // QgsStyleManagerDialog
146 //
147 
148 QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle *style, QWidget *parent, Qt::WindowFlags flags, bool readOnly )
149  : QDialog( parent, flags )
150  , mStyle( style )
151  , mReadOnly( readOnly )
152 {
153  setupUi( this );
154  connect( tabItemType, &QTabWidget::currentChanged, this, &QgsStyleManagerDialog::tabItemType_currentChanged );
155  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsStyleManagerDialog::showHelp );
156  connect( buttonBox, &QDialogButtonBox::rejected, this, &QgsStyleManagerDialog::onClose );
157 
158  mMessageBar = new QgsMessageBar();
159  mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
160  mVerticalLayout->insertWidget( 0, mMessageBar );
161 
162 #ifdef Q_OS_MAC
163  setWindowModality( Qt::WindowModal );
164 #endif
165 
166  QgsSettings settings;
167 
168  restoreGeometry( settings.value( QStringLiteral( "Windows/StyleV2Manager/geometry" ) ).toByteArray() );
169  mSplitter->setSizes( QList<int>() << 170 << 540 );
170  mSplitter->restoreState( settings.value( QStringLiteral( "Windows/StyleV2Manager/splitter" ) ).toByteArray() );
171 
172  tabItemType->setDocumentMode( true );
173  searchBox->setShowSearchIcon( true );
174  searchBox->setPlaceholderText( tr( "Filter symbols…" ) );
175 
176  connect( this, &QDialog::finished, this, &QgsStyleManagerDialog::onFinished );
177 
178  if ( !mReadOnly )
179  {
180  connect( listItems, &QAbstractItemView::doubleClicked, this, &QgsStyleManagerDialog::editItem );
181 
182  connect( btnAddItem, &QPushButton::clicked, this, [ = ]( bool ) { addItem(); }
183  );
184  connect( btnEditItem, &QPushButton::clicked, this, [ = ]( bool ) { editItem(); }
185  );
186  connect( actnEditItem, &QAction::triggered, this, [ = ]( bool ) { editItem(); }
187  );
188  connect( btnRemoveItem, &QPushButton::clicked, this, [ = ]( bool ) { removeItem(); }
189  );
190  connect( actnRemoveItem, &QAction::triggered, this, [ = ]( bool ) { removeItem(); }
191  );
192  }
193  else
194  {
195  btnAddTag->setEnabled( false );
196  btnAddSmartgroup->setEnabled( false );
197  }
198 
199  QMenu *shareMenu = new QMenu( tr( "Share Menu" ), this );
200  QAction *exportAction = new QAction( tr( "Export Item(s)…" ), this );
201  exportAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileSave.svg" ) ) );
202  shareMenu->addAction( exportAction );
203  if ( !mReadOnly )
204  {
205  QAction *importAction = new QAction( tr( "Import Item(s)…" ), this );
206  importAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileOpen.svg" ) ) );
207  shareMenu->addAction( importAction );
208  connect( importAction, &QAction::triggered, this, &QgsStyleManagerDialog::importItems );
209  }
210  if ( mStyle != QgsStyle::defaultStyle() )
211  {
212  mActionCopyToDefault = new QAction( tr( "Copy Selection to Default Style…" ), this );
213  shareMenu->addAction( mActionCopyToDefault );
214  connect( mActionCopyToDefault, &QAction::triggered, this, &QgsStyleManagerDialog::copyItemsToDefault );
215  connect( mCopyToDefaultButton, &QPushButton::clicked, this, &QgsStyleManagerDialog::copyItemsToDefault );
216  }
217  else
218  {
219  mCopyToDefaultButton->hide();
220  }
221 
222  shareMenu->addSeparator();
223  shareMenu->addAction( actnExportAsPNG );
224  shareMenu->addAction( actnExportAsSVG );
225 
226  connect( actnExportAsPNG, &QAction::triggered, this, &QgsStyleManagerDialog::exportItemsPNG );
227  connect( actnExportAsSVG, &QAction::triggered, this, &QgsStyleManagerDialog::exportItemsSVG );
228  connect( exportAction, &QAction::triggered, this, &QgsStyleManagerDialog::exportItems );
229  btnShare->setMenu( shareMenu );
230 
231  double iconSize = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 10;
232  listItems->setIconSize( QSize( static_cast< int >( iconSize ), static_cast< int >( iconSize * 0.9 ) ) ); // ~100, 90 on low dpi
233  double treeIconSize = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 2;
234  mSymbolTreeView->setIconSize( QSize( static_cast< int >( treeIconSize ), static_cast< int >( treeIconSize ) ) );
235 
236  mModel = new QgsCheckableStyleModel( mStyle, this, mReadOnly );
237  mModel->addDesiredIconSize( listItems->iconSize() );
238  mModel->addDesiredIconSize( mSymbolTreeView->iconSize() );
239  listItems->setModel( mModel );
240  mSymbolTreeView->setModel( mModel );
241 
242  listItems->setSelectionBehavior( QAbstractItemView::SelectRows );
243  listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
244  mSymbolTreeView->setSelectionModel( listItems->selectionModel() );
245  mSymbolTreeView->setSelectionMode( listItems->selectionMode() );
246 
247  connect( listItems->selectionModel(), &QItemSelectionModel::currentChanged,
249  connect( listItems->selectionModel(), &QItemSelectionModel::selectionChanged,
251 
252  QStandardItemModel *groupModel = new QStandardItemModel( groupTree );
253  groupTree->setModel( groupModel );
254  groupTree->setHeaderHidden( true );
255  populateGroups();
256  groupTree->setCurrentIndex( groupTree->model()->index( 0, 0 ) );
257 
258  connect( groupTree->selectionModel(), &QItemSelectionModel::currentChanged,
260  if ( !mReadOnly )
261  {
262  connect( groupModel, &QStandardItemModel::itemChanged,
264  }
265 
266  if ( !mReadOnly )
267  {
268  QMenu *groupMenu = new QMenu( tr( "Group Actions" ), this );
269  connect( actnTagSymbols, &QAction::triggered, this, &QgsStyleManagerDialog::tagSymbolsAction );
270  groupMenu->addAction( actnTagSymbols );
271  connect( actnFinishTagging, &QAction::triggered, this, &QgsStyleManagerDialog::tagSymbolsAction );
272  actnFinishTagging->setVisible( false );
273  groupMenu->addAction( actnFinishTagging );
274  groupMenu->addAction( actnEditSmartGroup );
275  btnManageGroups->setMenu( groupMenu );
276  }
277  else
278  {
279  btnManageGroups->setEnabled( false );
280  }
281 
282  connect( searchBox, &QLineEdit::textChanged, this, &QgsStyleManagerDialog::filterSymbols );
283 
284  // Context menu for groupTree
285  groupTree->setContextMenuPolicy( Qt::CustomContextMenu );
286  connect( groupTree, &QWidget::customContextMenuRequested,
288 
289  // Context menu for listItems
290  listItems->setContextMenuPolicy( Qt::CustomContextMenu );
291  connect( listItems, &QWidget::customContextMenuRequested,
293  mSymbolTreeView->setContextMenuPolicy( Qt::CustomContextMenu );
294  connect( mSymbolTreeView, &QWidget::customContextMenuRequested,
296 
297  if ( !mReadOnly )
298  {
299  // Menu for the "Add item" toolbutton when in colorramp mode
300  QStringList rampTypes;
301  rampTypes << tr( "Gradient" ) << tr( "Color presets" ) << tr( "Random" ) << tr( "Catalog: cpt-city" );
302  rampTypes << tr( "Catalog: ColorBrewer" );
303 
304  mMenuBtnAddItemAll = new QMenu( this );
305  mMenuBtnAddItemColorRamp = new QMenu( this );
306 
307  QAction *item = new QAction( tr( "Marker" ), this );
308  connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Marker ); } );
309  mMenuBtnAddItemAll->addAction( item );
310  item = new QAction( tr( "Line" ), this );
311  connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Line ); } );
312  mMenuBtnAddItemAll->addAction( item );
313  item = new QAction( tr( "Fill" ), this );
314  connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Fill ); } );
315  mMenuBtnAddItemAll->addAction( item );
316  mMenuBtnAddItemAll->addSeparator();
317  for ( const QString &rampType : qgis::as_const( rampTypes ) )
318  {
319  item = new QAction( rampType, this );
320  connect( item, &QAction::triggered, this, [ = ]( bool ) { addColorRamp( item ); } );
321  mMenuBtnAddItemAll->addAction( item );
322  mMenuBtnAddItemColorRamp->addAction( new QAction( rampType, this ) );
323  }
324 
325  connect( mMenuBtnAddItemColorRamp, &QMenu::triggered,
326  this, static_cast<bool ( QgsStyleManagerDialog::* )( QAction * )>( &QgsStyleManagerDialog::addColorRamp ) );
327  }
328 
329  // Context menu for symbols/colorramps. The menu entries for every group are created when displaying the menu.
330  mGroupMenu = new QMenu( this );
331  mGroupListMenu = new QMenu( mGroupMenu );
332  mGroupListMenu->setTitle( tr( "Add to Tag" ) );
333  mGroupListMenu->setEnabled( false );
334  if ( !mReadOnly )
335  {
336  connect( actnAddFavorite, &QAction::triggered, this, &QgsStyleManagerDialog::addFavoriteSelectedSymbols );
337  mGroupMenu->addAction( actnAddFavorite );
338  connect( actnRemoveFavorite, &QAction::triggered, this, &QgsStyleManagerDialog::removeFavoriteSelectedSymbols );
339  mGroupMenu->addAction( actnRemoveFavorite );
340  mGroupMenu->addSeparator()->setParent( this );
341  mGroupMenu->addMenu( mGroupListMenu );
342  actnDetag->setData( 0 );
343  connect( actnDetag, &QAction::triggered, this, &QgsStyleManagerDialog::detagSelectedSymbols );
344  mGroupMenu->addAction( actnDetag );
345  mGroupMenu->addSeparator()->setParent( this );
346  mGroupMenu->addAction( actnRemoveItem );
347  mGroupMenu->addAction( actnEditItem );
348  mGroupMenu->addSeparator()->setParent( this );
349  }
350  else
351  {
352  btnAddItem->setVisible( false );
353  btnRemoveItem->setVisible( false );
354  btnEditItem->setVisible( false );
355  btnAddSmartgroup->setVisible( false );
356  btnAddTag->setVisible( false );
357  btnManageGroups->setVisible( false );
358  }
359  if ( mActionCopyToDefault )
360  {
361  mGroupMenu->addAction( mActionCopyToDefault );
362  }
363  mGroupMenu->addAction( actnExportAsPNG );
364  mGroupMenu->addAction( actnExportAsSVG );
365 
366  // Context menu for the group tree
367  mGroupTreeContextMenu = new QMenu( this );
368  if ( !mReadOnly )
369  {
370  connect( actnEditSmartGroup, &QAction::triggered, this, &QgsStyleManagerDialog::editSmartgroupAction );
371  mGroupTreeContextMenu->addAction( actnEditSmartGroup );
372  connect( actnAddTag, &QAction::triggered, this, [ = ]( bool ) { addTag(); }
373  );
374  mGroupTreeContextMenu->addAction( actnAddTag );
375  connect( actnAddSmartgroup, &QAction::triggered, this, [ = ]( bool ) { addSmartgroup(); }
376  );
377  mGroupTreeContextMenu->addAction( actnAddSmartgroup );
378  connect( actnRemoveGroup, &QAction::triggered, this, &QgsStyleManagerDialog::removeGroup );
379  mGroupTreeContextMenu->addAction( actnRemoveGroup );
380  }
381 
382  tabItemType_currentChanged( 0 );
383 
386 
387  connect( mButtonIconView, &QToolButton::toggled, this, [ = ]( bool active )
388  {
389  if ( active )
390  {
391  mSymbolViewStackedWidget->setCurrentIndex( 0 );
392  // note -- we have to save state here and not in destructor, as new symbol list widgets are created before the previous ones are destroyed
393  QgsSettings().setValue( QStringLiteral( "Windows/StyleV2Manager/lastIconView" ), 0, QgsSettings::Gui );
394  }
395  } );
396  connect( mButtonListView, &QToolButton::toggled, this, [ = ]( bool active )
397  {
398  if ( active )
399  {
400  QgsSettings().setValue( QStringLiteral( "Windows/StyleV2Manager/lastIconView" ), 1, QgsSettings::Gui );
401  mSymbolViewStackedWidget->setCurrentIndex( 1 );
402  }
403  } );
404  // restore previous view
405  const int currentView = settings.value( QStringLiteral( "Windows/StyleV2Manager/lastIconView" ), 0, QgsSettings::Gui ).toInt();
406  if ( currentView == 0 )
407  mButtonIconView->setChecked( true );
408  else
409  mButtonListView->setChecked( true );
410 
411  mSymbolTreeView->header()->restoreState( settings.value( QStringLiteral( "Windows/StyleV2Manager/treeState" ), QByteArray(), QgsSettings::Gui ).toByteArray() );
412  connect( mSymbolTreeView->header(), &QHeaderView::sectionResized, this, [this]
413  {
414  // note -- we have to save state here and not in destructor, as new symbol list widgets are created before the previous ones are destroyed
415  QgsSettings().setValue( QStringLiteral( "Windows/StyleV2Manager/treeState" ), mSymbolTreeView->header()->saveState(), QgsSettings::Gui );
416  } );
417 
418  // set initial disabled state for actions requiring a selection
419  selectedSymbolsChanged( QItemSelection(), QItemSelection() );
420 }
421 
423 {
424  if ( mModified && !mReadOnly )
425  {
426  mStyle->save();
427  }
428 
429  QgsSettings settings;
430  settings.setValue( QStringLiteral( "Windows/StyleV2Manager/geometry" ), saveGeometry() );
431  settings.setValue( QStringLiteral( "Windows/StyleV2Manager/splitter" ), mSplitter->saveState() );
432 }
433 
435 {
436 }
437 
438 void QgsStyleManagerDialog::tabItemType_currentChanged( int )
439 {
440  // when in Color Ramp tab, add menu to add item button and hide "Export symbols as PNG/SVG"
441  const bool isSymbol = currentItemType() != 3;
442  searchBox->setPlaceholderText( isSymbol ? tr( "Filter symbols…" ) : tr( "Filter color ramps…" ) );
443 
444  if ( !mReadOnly && !isSymbol ) // color ramp tab
445  {
446  btnAddItem->setMenu( mMenuBtnAddItemColorRamp );
447  }
448  else if ( !mReadOnly && tabItemType->currentIndex() == 0 ) // all symbols tab
449  {
450  btnAddItem->setMenu( mMenuBtnAddItemAll );
451  }
452  else
453  {
454  btnAddItem->setMenu( nullptr );
455  }
456 
457  actnExportAsPNG->setVisible( isSymbol );
458  actnExportAsSVG->setVisible( isSymbol );
459 
460  mModel->setEntityFilter( isSymbol ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity );
461  mModel->setEntityFilterEnabled( !allTypesSelected() );
462  mModel->setSymbolTypeFilterEnabled( isSymbol && !allTypesSelected() );
463  if ( isSymbol && !allTypesSelected() )
464  mModel->setSymbolType( static_cast< QgsSymbol::SymbolType >( currentItemType() ) );
465 
466  populateList();
467 }
468 
469 void QgsStyleManagerDialog::copyItemsToDefault()
470 {
471  const QList< ItemDetails > items = selectedItems();
472  if ( !items.empty() )
473  {
474  bool ok = false;
475  const QString tags = QInputDialog::getText( this, tr( "Import Items" ),
476  tr( "Additional tags to add (comma separated)" ), QLineEdit::Normal,
477  mBaseName, &ok );
478  if ( !ok )
479  return;
480 
481  const QStringList parts = tags.split( ',', QString::SkipEmptyParts );
482  QStringList additionalTags;
483  additionalTags.reserve( parts.count() );
484  for ( const QString &tag : parts )
485  additionalTags << tag.trimmed();
486 
487  auto cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
488  const int count = copyItems( items, mStyle, QgsStyle::defaultStyle(), this, cursorOverride, true, additionalTags, false, false );
489  cursorOverride.reset();
490  if ( count > 0 )
491  {
492  mMessageBar->pushSuccess( tr( "Import Items" ), count > 1 ? tr( "Successfully imported %1 items." ).arg( count ) : tr( "Successfully imported item." ) );
493  }
494  }
495 }
496 
497 int QgsStyleManagerDialog::selectedItemType()
498 {
499  QModelIndex index = listItems->selectionModel()->currentIndex();
500  if ( !index.isValid() )
501  return 0;
502 
503  const QgsStyle::StyleEntity entity = static_cast< QgsStyle::StyleEntity >( mModel->data( index, QgsStyleModel::TypeRole ).toInt() );
504  if ( entity == QgsStyle::ColorrampEntity )
505  return 3;
506 
507  return mModel->data( index, QgsStyleModel::SymbolTypeRole ).toInt();
508 }
509 
510 bool QgsStyleManagerDialog::allTypesSelected() const
511 {
512  return tabItemType->currentIndex() == 0;
513 }
514 
515 QList< QgsStyleManagerDialog::ItemDetails > QgsStyleManagerDialog::selectedItems()
516 {
517  QList<QgsStyleManagerDialog::ItemDetails > res;
518  QModelIndexList indices = listItems->selectionModel()->selectedRows();
519  for ( const QModelIndex &index : indices )
520  {
521  if ( !index.isValid() )
522  continue;
523 
524  ItemDetails details;
525  details.entityType = static_cast< QgsStyle::StyleEntity >( mModel->data( index, QgsStyleModel::TypeRole ).toInt() );
526  if ( details.entityType == QgsStyle::SymbolEntity )
527  details.symbolType = static_cast< QgsSymbol::SymbolType >( mModel->data( index, QgsStyleModel::SymbolTypeRole ).toInt() );
528  details.name = mModel->data( mModel->index( index.row(), QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
529 
530  res << details;
531  }
532  return res;
533 }
534 
535 int QgsStyleManagerDialog::copyItems( const QList<QgsStyleManagerDialog::ItemDetails> &items, QgsStyle *src, QgsStyle *dst, QWidget *parentWidget,
536  std::unique_ptr< QgsTemporaryCursorOverride > &cursorOverride, bool isImport, const QStringList &importTags, bool addToFavorites, bool ignoreSourceTags )
537 {
538  bool prompt = true;
539  bool overwriteAll = true;
540  int count = 0;
541 
542  const QStringList favoriteSymbols = src->symbolsOfFavorite( QgsStyle::SymbolEntity );
543  const QStringList favoriteColorramps = src->symbolsOfFavorite( QgsStyle::ColorrampEntity );
544 
545  for ( auto &details : items )
546  {
547  QStringList symbolTags;
548  if ( !ignoreSourceTags )
549  {
550  symbolTags = src->tagsOfSymbol( details.entityType, details.name );
551  }
552 
553  bool addItemToFavorites = false;
554  if ( isImport )
555  {
556  symbolTags << importTags;
557  addItemToFavorites = addToFavorites;
558  }
559 
560  switch ( details.entityType )
561  {
563  {
564  std::unique_ptr< QgsSymbol > symbol( src->symbol( details.name ) );
565  if ( !symbol )
566  continue;
567 
568  const bool hasDuplicateName = dst->symbolNames().contains( details.name );
569  bool overwriteThis = false;
570  if ( isImport )
571  addItemToFavorites = favoriteSymbols.contains( details.name );
572 
573  if ( hasDuplicateName && prompt )
574  {
575  cursorOverride.reset();
576  int res = QMessageBox::warning( parentWidget, isImport ? tr( "Import Symbol" ) : tr( "Export Symbol" ),
577  tr( "A symbol with the name “%1” already exists.\nOverwrite?" )
578  .arg( details.name ),
579  QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
580  cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
581  switch ( res )
582  {
583  case QMessageBox::Cancel:
584  return count;
585 
586  case QMessageBox::No:
587  continue;
588 
589  case QMessageBox::Yes:
590  overwriteThis = true;
591  break;
592 
593  case QMessageBox::YesToAll:
594  prompt = false;
595  overwriteAll = true;
596  break;
597 
598  case QMessageBox::NoToAll:
599  prompt = false;
600  overwriteAll = false;
601  break;
602  }
603  }
604 
605  if ( !hasDuplicateName || overwriteAll || overwriteThis )
606  {
607  QgsSymbol *newSymbol = symbol.get();
608  dst->addSymbol( details.name, symbol.release() );
609  dst->saveSymbol( details.name, newSymbol, addItemToFavorites, symbolTags );
610  count++;
611  }
612  break;
613  }
614 
616  {
617  std::unique_ptr< QgsColorRamp > ramp( src->colorRamp( details.name ) );
618  if ( !ramp )
619  continue;
620 
621  const bool hasDuplicateName = dst->colorRampNames().contains( details.name );
622  bool overwriteThis = false;
623  if ( isImport )
624  addItemToFavorites = favoriteColorramps.contains( details.name );
625 
626  if ( hasDuplicateName && prompt )
627  {
628  cursorOverride.reset();
629  int res = QMessageBox::warning( parentWidget, isImport ? tr( "Import Color Ramp" ) : tr( "Export Color Ramp" ),
630  tr( "A color ramp with the name “%1” already exists.\nOverwrite?" )
631  .arg( details.name ),
632  QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
633  cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
634  switch ( res )
635  {
636  case QMessageBox::Cancel:
637  return count;
638 
639  case QMessageBox::No:
640  continue;
641 
642  case QMessageBox::Yes:
643  overwriteThis = true;
644  break;
645 
646  case QMessageBox::YesToAll:
647  prompt = false;
648  overwriteAll = true;
649  break;
650 
651  case QMessageBox::NoToAll:
652  prompt = false;
653  overwriteAll = false;
654  break;
655  }
656  }
657 
658  if ( !hasDuplicateName || overwriteAll || overwriteThis )
659  {
660  QgsColorRamp *newRamp = ramp.get();
661  dst->addColorRamp( details.name, ramp.release() );
662  dst->saveColorRamp( details.name, newRamp, addItemToFavorites, symbolTags );
663  count++;
664  }
665  break;
666  }
667 
668  case QgsStyle::TagEntity:
670  break;
671 
672  }
673  }
674  return count;
675 }
676 
678 {
679  groupChanged( groupTree->selectionModel()->currentIndex() );
680 }
681 
682 void QgsStyleManagerDialog::populateSymbols( const QStringList &, bool )
683 {
684 }
685 
686 void QgsStyleManagerDialog::populateColorRamps( const QStringList &, bool )
687 {
688 }
689 
691 {
692  switch ( tabItemType->currentIndex() )
693  {
694  case 1:
695  return QgsSymbol::Marker;
696  case 2:
697  return QgsSymbol::Line;
698  case 3:
699  return QgsSymbol::Fill;
700  case 4:
701  return 3;
702  default:
703  return 0;
704  }
705 }
706 
708 {
709  QModelIndex index = listItems->selectionModel()->currentIndex();
710  if ( !index.isValid() )
711  return QString();
712 
713  return mModel->data( mModel->index( index.row(), QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
714 }
715 
717 {
718  bool changed = false;
719  if ( currentItemType() < 3 )
720  {
721  changed = addSymbol();
722  }
723  else if ( currentItemType() == 3 )
724  {
725  changed = addColorRamp();
726  }
727  else
728  {
729  Q_ASSERT( false && "not implemented" );
730  }
731 
732  if ( changed )
733  {
734  populateList();
735  }
736 }
737 
738 bool QgsStyleManagerDialog::addSymbol( int symbolType )
739 {
740  // create new symbol with current type
741  QgsSymbol *symbol = nullptr;
742  QString name = tr( "new symbol" );
743  switch ( symbolType == -1 ? currentItemType() : symbolType )
744  {
745  case QgsSymbol::Marker:
746  symbol = new QgsMarkerSymbol();
747  name = tr( "new marker" );
748  break;
749  case QgsSymbol::Line:
750  symbol = new QgsLineSymbol();
751  name = tr( "new line" );
752  break;
753  case QgsSymbol::Fill:
754  symbol = new QgsFillSymbol();
755  name = tr( "new fill symbol" );
756  break;
757  default:
758  Q_ASSERT( false && "unknown symbol type" );
759  return false;
760  }
761 
762  // get symbol design
763  // NOTE : Set the parent widget as "this" to notify the Symbol selector
764  // that, it is being called by Style Manager, so recursive calling
765  // of style manager and symbol selector can be arrested
766  // See also: editSymbol()
767  QgsSymbolSelectorDialog dlg( symbol, mStyle, nullptr, this );
768  if ( dlg.exec() == 0 )
769  {
770  delete symbol;
771  return false;
772  }
773 
774  QgsStyleSaveDialog saveDlg( this );
775  if ( !saveDlg.exec() )
776  {
777  delete symbol;
778  return false;
779  }
780 
781  name = saveDlg.name();
782 
783  // request valid/unique name
784  bool nameInvalid = true;
785  while ( nameInvalid )
786  {
787  // validate name
788  if ( name.isEmpty() )
789  {
790  QMessageBox::warning( this, tr( "Save Symbol" ),
791  tr( "Cannot save symbol without name. Enter a name." ) );
792  }
793  else if ( mStyle->symbolNames().contains( name ) )
794  {
795  int res = QMessageBox::warning( this, tr( "Save Symbol" ),
796  tr( "Symbol with name '%1' already exists. Overwrite?" )
797  .arg( name ),
798  QMessageBox::Yes | QMessageBox::No );
799  if ( res == QMessageBox::Yes )
800  {
801  mStyle->removeSymbol( name );
802  nameInvalid = false;
803  }
804  }
805  else
806  {
807  // valid name
808  nameInvalid = false;
809  }
810  if ( nameInvalid )
811  {
812  bool ok;
813  name = QInputDialog::getText( this, tr( "Symbol Name" ),
814  tr( "Please enter a name for new symbol:" ),
815  QLineEdit::Normal, name, &ok );
816  if ( !ok )
817  {
818  delete symbol;
819  return false;
820  }
821  }
822  }
823 
824  QStringList symbolTags = saveDlg.tags().split( ',' );
825 
826  // add new symbol to style and re-populate the list
827  mStyle->addSymbol( name, symbol );
828  mStyle->saveSymbol( name, symbol, saveDlg.isFavorite(), symbolTags );
829 
830  mModified = true;
831  return true;
832 }
833 
834 
835 QString QgsStyleManagerDialog::addColorRampStatic( QWidget *parent, QgsStyle *style, QString rampType )
836 {
837  // let the user choose the color ramp type if rampType is not given
838  bool ok = true;
839  if ( rampType.isEmpty() )
840  {
841  QStringList rampTypes;
842  rampTypes << tr( "Gradient" ) << tr( "Color presets" ) << tr( "Random" ) << tr( "Catalog: cpt-city" );
843  rampTypes << tr( "Catalog: ColorBrewer" );
844  rampType = QInputDialog::getItem( parent, tr( "Color Ramp Type" ),
845  tr( "Please select color ramp type:" ), rampTypes, 0, false, &ok );
846  }
847  if ( !ok || rampType.isEmpty() )
848  return QString();
849 
850  QString name = tr( "new ramp" );
851 
852  std::unique_ptr< QgsColorRamp > ramp;
853  if ( rampType == tr( "Gradient" ) )
854  {
856  if ( !dlg.exec() )
857  {
858  return QString();
859  }
860  ramp.reset( dlg.ramp().clone() );
861  name = tr( "new gradient ramp" );
862  }
863  else if ( rampType == tr( "Random" ) )
864  {
866  if ( !dlg.exec() )
867  {
868  return QString();
869  }
870  ramp.reset( dlg.ramp().clone() );
871  name = tr( "new random ramp" );
872  }
873  else if ( rampType == tr( "Catalog: ColorBrewer" ) )
874  {
876  if ( !dlg.exec() )
877  {
878  return QString();
879  }
880  ramp.reset( dlg.ramp().clone() );
881  name = dlg.ramp().schemeName() + QString::number( dlg.ramp().colors() );
882  }
883  else if ( rampType == tr( "Color presets" ) )
884  {
886  if ( !dlg.exec() )
887  {
888  return QString();
889  }
890  ramp.reset( dlg.ramp().clone() );
891  name = tr( "new preset ramp" );
892  }
893  else if ( rampType == tr( "Catalog: cpt-city" ) )
894  {
895  QgsCptCityColorRampDialog dlg( QgsCptCityColorRamp( QString(), QString() ), parent );
896  if ( !dlg.exec() )
897  {
898  return QString();
899  }
900  // name = dlg.selectedName();
901  name = QFileInfo( dlg.ramp().schemeName() ).baseName() + dlg.ramp().variantName();
902  if ( dlg.saveAsGradientRamp() )
903  {
904  ramp.reset( dlg.ramp().cloneGradientRamp() );
905  }
906  else
907  {
908  ramp.reset( dlg.ramp().clone() );
909  }
910  }
911  else
912  {
913  // Q_ASSERT( 0 && "invalid ramp type" );
914  // bailing out is rather harsh!
915  QgsDebugMsg( QStringLiteral( "invalid ramp type %1" ).arg( rampType ) );
916  return QString();
917  }
918 
920  if ( !saveDlg.exec() )
921  {
922  return QString();
923  }
924 
925  name = saveDlg.name();
926 
927  // get valid/unique name
928  bool nameInvalid = true;
929  while ( nameInvalid )
930  {
931  // validate name
932  if ( name.isEmpty() )
933  {
934  QMessageBox::warning( parent, tr( "Save Color Ramp" ),
935  tr( "Cannot save color ramp without name. Enter a name." ) );
936  }
937  else if ( style->colorRampNames().contains( name ) )
938  {
939  int res = QMessageBox::warning( parent, tr( "Save Color Ramp" ),
940  tr( "Color ramp with name '%1' already exists. Overwrite?" )
941  .arg( name ),
942  QMessageBox::Yes | QMessageBox::No );
943  if ( res == QMessageBox::Yes )
944  {
945  nameInvalid = false;
946  }
947  }
948  else
949  {
950  // valid name
951  nameInvalid = false;
952  }
953  if ( nameInvalid )
954  {
955  bool ok;
956  name = QInputDialog::getText( parent, tr( "Color Ramp Name" ),
957  tr( "Please enter a name for new color ramp:" ),
958  QLineEdit::Normal, name, &ok );
959  if ( !ok )
960  {
961  return QString();
962  }
963  }
964  }
965 
966  QStringList colorRampTags = saveDlg.tags().split( ',' );
967  QgsColorRamp *r = ramp.release();
968 
969  // add new symbol to style and re-populate the list
970  style->addColorRamp( name, r );
971  style->saveColorRamp( name, r, saveDlg.isFavorite(), colorRampTags );
972 
973  return name;
974 }
975 
977 {
978  mFavoritesGroupVisible = show;
979  populateGroups();
980 }
981 
983 {
984  mSmartGroupVisible = show;
985  populateGroups();
986 }
987 
988 void QgsStyleManagerDialog::setBaseStyleName( const QString &name )
989 {
990  mBaseName = name;
991 }
992 
994 {
995  raise();
996  setWindowState( windowState() & ~Qt::WindowMinimized );
997  activateWindow();
998 }
999 
1001 {
1002  return addColorRamp( nullptr );
1003 }
1004 
1006 {
1007  // pass the action text, which is the color ramp type
1008  QString rampName = addColorRampStatic( this, mStyle,
1009  action ? action->text() : QString() );
1010  if ( !rampName.isEmpty() )
1011  {
1012  mModified = true;
1013  populateList();
1014  return true;
1015  }
1016 
1017  return false;
1018 }
1019 
1021 {
1022  if ( selectedItemType() < 3 )
1023  {
1024  editSymbol();
1025  }
1026  else if ( selectedItemType() == 3 )
1027  {
1028  editColorRamp();
1029  }
1030  else
1031  {
1032  Q_ASSERT( false && "not implemented" );
1033  }
1034 }
1035 
1037 {
1038  QString symbolName = currentItemName();
1039  if ( symbolName.isEmpty() )
1040  return false;
1041 
1042  std::unique_ptr< QgsSymbol > symbol( mStyle->symbol( symbolName ) );
1043 
1044  // let the user edit the symbol and update list when done
1045  QgsSymbolSelectorDialog dlg( symbol.get(), mStyle, nullptr, this );
1046  if ( dlg.exec() == 0 )
1047  {
1048  return false;
1049  }
1050 
1051  // by adding symbol to style with the same name the old effectively gets overwritten
1052  mStyle->addSymbol( symbolName, symbol.release(), true );
1053  mModified = true;
1054  return true;
1055 }
1056 
1058 {
1059  QString name = currentItemName();
1060  if ( name.isEmpty() )
1061  return false;
1062 
1063  std::unique_ptr< QgsColorRamp > ramp( mStyle->colorRamp( name ) );
1064 
1065  if ( ramp->type() == QLatin1String( "gradient" ) )
1066  {
1067  QgsGradientColorRamp *gradRamp = static_cast<QgsGradientColorRamp *>( ramp.get() );
1068  QgsGradientColorRampDialog dlg( *gradRamp, this );
1069  if ( !dlg.exec() )
1070  {
1071  return false;
1072  }
1073  ramp.reset( dlg.ramp().clone() );
1074  }
1075  else if ( ramp->type() == QLatin1String( "random" ) )
1076  {
1077  QgsLimitedRandomColorRamp *randRamp = static_cast<QgsLimitedRandomColorRamp *>( ramp.get() );
1078  QgsLimitedRandomColorRampDialog dlg( *randRamp, this );
1079  if ( !dlg.exec() )
1080  {
1081  return false;
1082  }
1083  ramp.reset( dlg.ramp().clone() );
1084  }
1085  else if ( ramp->type() == QLatin1String( "colorbrewer" ) )
1086  {
1087  QgsColorBrewerColorRamp *brewerRamp = static_cast<QgsColorBrewerColorRamp *>( ramp.get() );
1088  QgsColorBrewerColorRampDialog dlg( *brewerRamp, this );
1089  if ( !dlg.exec() )
1090  {
1091  return false;
1092  }
1093  ramp.reset( dlg.ramp().clone() );
1094  }
1095  else if ( ramp->type() == QLatin1String( "preset" ) )
1096  {
1097  QgsPresetSchemeColorRamp *presetRamp = static_cast<QgsPresetSchemeColorRamp *>( ramp.get() );
1098  QgsPresetColorRampDialog dlg( *presetRamp, this );
1099  if ( !dlg.exec() )
1100  {
1101  return false;
1102  }
1103  ramp.reset( dlg.ramp().clone() );
1104  }
1105  else if ( ramp->type() == QLatin1String( "cpt-city" ) )
1106  {
1107  QgsCptCityColorRamp *cptCityRamp = static_cast<QgsCptCityColorRamp *>( ramp.get() );
1108  QgsCptCityColorRampDialog dlg( *cptCityRamp, this );
1109  if ( !dlg.exec() )
1110  {
1111  return false;
1112  }
1113  if ( dlg.saveAsGradientRamp() )
1114  {
1115  ramp.reset( dlg.ramp().cloneGradientRamp() );
1116  }
1117  else
1118  {
1119  ramp.reset( dlg.ramp().clone() );
1120  }
1121  }
1122  else
1123  {
1124  Q_ASSERT( false && "invalid ramp type" );
1125  }
1126 
1127  mStyle->addColorRamp( name, ramp.release(), true );
1128  mModified = true;
1129  return true;
1130 }
1131 
1132 
1134 {
1135  const QList< ItemDetails > items = selectedItems();
1136 
1137  if ( allTypesSelected() )
1138  {
1139  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Items" ),
1140  QString( tr( "Do you really want to remove %n item(s)?", nullptr, items.count() ) ),
1141  QMessageBox::Yes,
1142  QMessageBox::No ) )
1143  return;
1144  }
1145  else
1146  {
1147  if ( currentItemType() < 3 )
1148  {
1149  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Symbol" ),
1150  QString( tr( "Do you really want to remove %n symbol(s)?", nullptr, items.count() ) ),
1151  QMessageBox::Yes,
1152  QMessageBox::No ) )
1153  return;
1154  }
1155  else
1156  {
1157  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Color Ramp" ),
1158  QString( tr( "Do you really want to remove %n ramp(s)?", nullptr, items.count() ) ),
1159  QMessageBox::Yes,
1160  QMessageBox::No ) )
1161  return;
1162  }
1163  }
1164 
1165  QgsTemporaryCursorOverride override( Qt::WaitCursor );
1166 
1167  for ( const ItemDetails &details : items )
1168  {
1169  if ( details.name.isEmpty() )
1170  continue;
1171 
1172  if ( details.entityType == QgsStyle::SymbolEntity )
1173  mStyle->removeSymbol( details.name );
1174  else if ( details.entityType == QgsStyle::ColorrampEntity )
1175  mStyle->removeColorRamp( details.name );
1176  }
1177 
1178  mModified = true;
1179 }
1180 
1182 {
1183  return false;
1184 }
1185 
1187 {
1188  return false;
1189 }
1190 
1191 void QgsStyleManagerDialog::itemChanged( QStandardItem * )
1192 {
1193 }
1194 
1196 {
1197  QString dir = QFileDialog::getExistingDirectory( this, tr( "Export Selected Symbols as PNG" ),
1198  QDir::home().absolutePath(),
1199  QFileDialog::ShowDirsOnly
1200  | QFileDialog::DontResolveSymlinks );
1201  exportSelectedItemsImages( dir, QStringLiteral( "png" ), QSize( 32, 32 ) );
1202 }
1203 
1205 {
1206  QString dir = QFileDialog::getExistingDirectory( this, tr( "Export Selected Symbols as SVG" ),
1207  QDir::home().absolutePath(),
1208  QFileDialog::ShowDirsOnly
1209  | QFileDialog::DontResolveSymlinks );
1210  exportSelectedItemsImages( dir, QStringLiteral( "svg" ), QSize( 32, 32 ) );
1211 }
1212 
1213 
1214 void QgsStyleManagerDialog::exportSelectedItemsImages( const QString &dir, const QString &format, QSize size )
1215 {
1216  if ( dir.isEmpty() )
1217  return;
1218 
1219  const QList< ItemDetails > items = selectedItems();
1220  for ( const ItemDetails &details : items )
1221  {
1222  if ( details.entityType != QgsStyle::SymbolEntity )
1223  continue;
1224 
1225  QString path = dir + '/' + details.name + '.' + format;
1226  std::unique_ptr< QgsSymbol > sym( mStyle->symbol( details.name ) );
1227  if ( sym )
1228  sym->exportImage( path, format, size );
1229  }
1230 }
1231 
1233 {
1235  dlg.exec();
1236 }
1237 
1239 {
1241  dlg.exec();
1242  populateList();
1243  populateGroups();
1244 }
1245 
1246 void QgsStyleManagerDialog::setBold( QStandardItem *item )
1247 {
1248  QFont font = item->font();
1249  font.setBold( true );
1250  item->setFont( font );
1251 }
1252 
1254 {
1255  if ( mBlockGroupUpdates )
1256  return;
1257 
1258  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1259  model->clear();
1260 
1261  if ( mFavoritesGroupVisible )
1262  {
1263  QStandardItem *favoriteSymbols = new QStandardItem( tr( "Favorites" ) );
1264  favoriteSymbols->setData( "favorite" );
1265  favoriteSymbols->setEditable( false );
1266  setBold( favoriteSymbols );
1267  model->appendRow( favoriteSymbols );
1268  }
1269 
1270  QStandardItem *allSymbols = new QStandardItem( tr( "All" ) );
1271  allSymbols->setData( "all" );
1272  allSymbols->setEditable( false );
1273  setBold( allSymbols );
1274  model->appendRow( allSymbols );
1275 
1276  QStandardItem *taggroup = new QStandardItem( QString() ); //require empty name to get first order groups
1277  taggroup->setData( "tags" );
1278  taggroup->setEditable( false );
1279  QStringList tags = mStyle->tags();
1280  tags.sort();
1281  for ( const QString &tag : qgis::as_const( tags ) )
1282  {
1283  QStandardItem *item = new QStandardItem( tag );
1284  item->setData( mStyle->tagId( tag ) );
1285  item->setEditable( !mReadOnly );
1286  taggroup->appendRow( item );
1287  }
1288  taggroup->setText( tr( "Tags" ) );//set title later
1289  setBold( taggroup );
1290  model->appendRow( taggroup );
1291 
1292  if ( mSmartGroupVisible )
1293  {
1294  QStandardItem *smart = new QStandardItem( tr( "Smart Groups" ) );
1295  smart->setData( "smartgroups" );
1296  smart->setEditable( false );
1297  setBold( smart );
1298  QgsSymbolGroupMap sgMap = mStyle->smartgroupsListMap();
1299  QgsSymbolGroupMap::const_iterator i = sgMap.constBegin();
1300  while ( i != sgMap.constEnd() )
1301  {
1302  QStandardItem *item = new QStandardItem( i.value() );
1303  item->setData( i.key() );
1304  item->setEditable( !mReadOnly );
1305  smart->appendRow( item );
1306  ++i;
1307  }
1308  model->appendRow( smart );
1309  }
1310 
1311  // expand things in the group tree
1312  int rows = model->rowCount( model->indexFromItem( model->invisibleRootItem() ) );
1313  for ( int i = 0; i < rows; i++ )
1314  {
1315  groupTree->setExpanded( model->indexFromItem( model->item( i ) ), true );
1316  }
1317 }
1318 
1319 void QgsStyleManagerDialog::groupChanged( const QModelIndex &index )
1320 {
1321  QStringList groupSymbols;
1322 
1323  const QString category = index.data( Qt::UserRole + 1 ).toString();
1324  if ( mGroupingMode )
1325  {
1326  mModel->setTagId( -1 );
1327  mModel->setSmartGroupId( -1 );
1328  mModel->setFavoritesOnly( false );
1329  mModel->setCheckTag( index.data( Qt::DisplayRole ).toString() );
1330  }
1331  else if ( category == QLatin1String( "all" ) || category == QLatin1String( "tags" ) || category == QLatin1String( "smartgroups" ) )
1332  {
1333  enableGroupInputs( false );
1334  if ( category == QLatin1String( "tags" ) )
1335  {
1336  actnAddTag->setEnabled( !mReadOnly );
1337  actnAddSmartgroup->setEnabled( false );
1338  }
1339  else if ( category == QLatin1String( "smartgroups" ) )
1340  {
1341  actnAddTag->setEnabled( false );
1342  actnAddSmartgroup->setEnabled( !mReadOnly );
1343  }
1344 
1345  mModel->setTagId( -1 );
1346  mModel->setSmartGroupId( -1 );
1347  mModel->setFavoritesOnly( false );
1348  }
1349  else if ( category == QLatin1String( "favorite" ) )
1350  {
1351  enableGroupInputs( false );
1352  mModel->setTagId( -1 );
1353  mModel->setSmartGroupId( -1 );
1354  mModel->setFavoritesOnly( true );
1355  }
1356  else if ( index.parent().data( Qt::UserRole + 1 ) == "smartgroups" )
1357  {
1358  actnRemoveGroup->setEnabled( !mReadOnly );
1359  btnManageGroups->setEnabled( !mReadOnly );
1360  const int groupId = index.data( Qt::UserRole + 1 ).toInt();
1361  mModel->setTagId( -1 );
1362  mModel->setSmartGroupId( groupId );
1363  mModel->setFavoritesOnly( false );
1364  }
1365  else // tags
1366  {
1367  enableGroupInputs( true );
1368  int tagId = index.data( Qt::UserRole + 1 ).toInt();
1369  mModel->setTagId( tagId );
1370  mModel->setSmartGroupId( -1 );
1371  mModel->setFavoritesOnly( false );
1372  }
1373 
1374  actnEditSmartGroup->setVisible( false );
1375  actnAddTag->setVisible( false );
1376  actnAddSmartgroup->setVisible( false );
1377  actnRemoveGroup->setVisible( false );
1378  actnTagSymbols->setVisible( false );
1379  actnFinishTagging->setVisible( false );
1380 
1381  if ( index.parent().isValid() )
1382  {
1383  if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "smartgroups" ) )
1384  {
1385  actnEditSmartGroup->setVisible( !mGroupingMode && !mReadOnly );
1386  }
1387  else if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "tags" ) )
1388  {
1389  actnAddTag->setVisible( !mGroupingMode && !mReadOnly );
1390  actnTagSymbols->setVisible( !mGroupingMode && !mReadOnly );
1391  actnFinishTagging->setVisible( mGroupingMode && !mReadOnly );
1392  }
1393  actnRemoveGroup->setVisible( !mReadOnly );
1394  }
1395  else if ( index.data( Qt::UserRole + 1 ) == "smartgroups" )
1396  {
1397  actnAddSmartgroup->setVisible( !mGroupingMode && !mReadOnly );
1398  }
1399  else if ( index.data( Qt::UserRole + 1 ) == "tags" )
1400  {
1401  actnAddTag->setVisible( !mGroupingMode && !mReadOnly );
1402  }
1403 }
1404 
1406 {
1407  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1408  QModelIndex index;
1409  for ( int i = 0; i < groupTree->model()->rowCount(); i++ )
1410  {
1411  index = groupTree->model()->index( i, 0 );
1412  QString data = index.data( Qt::UserRole + 1 ).toString();
1413  if ( data == QLatin1String( "tags" ) )
1414  {
1415  break;
1416  }
1417  }
1418 
1419  QString itemName;
1420  int id;
1421  bool ok;
1422  itemName = QInputDialog::getText( this, tr( "Add Tag" ),
1423  tr( "Please enter name for the new tag:" ), QLineEdit::Normal, tr( "New tag" ), &ok ).trimmed();
1424  if ( !ok || itemName.isEmpty() )
1425  return 0;
1426 
1427  int check = mStyle->tagId( itemName );
1428  if ( check > 0 )
1429  {
1430  mMessageBar->pushCritical( tr( "Add Tag" ), tr( "The tag “%1” already exists." ).arg( itemName ) );
1431  return 0;
1432  }
1433 
1434  // block the auto-repopulation of groups when the style emits groupsModified
1435  // instead, we manually update the model items for better state retention
1436  mBlockGroupUpdates++;
1437  id = mStyle->addTag( itemName );
1438  mBlockGroupUpdates--;
1439 
1440  if ( !id )
1441  {
1442  mMessageBar->pushCritical( tr( "Add Tag" ), tr( "New tag could not be created — There was a problem with the symbol database." ) );
1443  return 0;
1444  }
1445 
1446  QStandardItem *parentItem = model->itemFromIndex( index );
1447  QStandardItem *childItem = new QStandardItem( itemName );
1448  childItem->setData( id );
1449  parentItem->appendRow( childItem );
1450 
1451  return id;
1452 }
1453 
1455 {
1456  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1457  QModelIndex index;
1458  for ( int i = 0; i < groupTree->model()->rowCount(); i++ )
1459  {
1460  index = groupTree->model()->index( i, 0 );
1461  QString data = index.data( Qt::UserRole + 1 ).toString();
1462  if ( data == QLatin1String( "smartgroups" ) )
1463  {
1464  break;
1465  }
1466  }
1467 
1468  QString itemName;
1469  int id;
1470  QgsSmartGroupEditorDialog dlg( mStyle, this );
1471  if ( dlg.exec() == QDialog::Rejected )
1472  return 0;
1473 
1474  // block the auto-repopulation of groups when the style emits groupsModified
1475  // instead, we manually update the model items for better state retention
1476  mBlockGroupUpdates++;
1477  id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() );
1478  mBlockGroupUpdates--;
1479 
1480  if ( !id )
1481  return 0;
1482  itemName = dlg.smartgroupName();
1483 
1484  QStandardItem *parentItem = model->itemFromIndex( index );
1485  QStandardItem *childItem = new QStandardItem( itemName );
1486  childItem->setData( id );
1487  parentItem->appendRow( childItem );
1488 
1489  return id;
1490 }
1491 
1493 {
1494  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1495  QModelIndex index = groupTree->currentIndex();
1496 
1497  // do not allow removal of system-defined groupings
1498  QString data = index.data( Qt::UserRole + 1 ).toString();
1499  if ( data == QLatin1String( "all" ) || data == QLatin1String( "favorite" ) || data == QLatin1String( "tags" ) || index.data() == "smartgroups" )
1500  {
1501  // should never appear -- blocked by GUI
1502  int err = QMessageBox::critical( this, tr( "Remove Group" ),
1503  tr( "Invalid selection. Cannot delete system defined categories.\n"
1504  "Kindly select a group or smart group you might want to delete." ) );
1505  if ( err )
1506  return;
1507  }
1508 
1509  QStandardItem *parentItem = model->itemFromIndex( index.parent() );
1510 
1511  // block the auto-repopulation of groups when the style emits groupsModified
1512  // instead, we manually update the model items for better state retention
1513  mBlockGroupUpdates++;
1514 
1515  if ( parentItem->data( Qt::UserRole + 1 ).toString() == QLatin1String( "smartgroups" ) )
1516  {
1517  mStyle->remove( QgsStyle::SmartgroupEntity, index.data( Qt::UserRole + 1 ).toInt() );
1518  }
1519  else
1520  {
1521  mStyle->remove( QgsStyle::TagEntity, index.data( Qt::UserRole + 1 ).toInt() );
1522  }
1523 
1524  mBlockGroupUpdates--;
1525  parentItem->removeRow( index.row() );
1526 }
1527 
1528 void QgsStyleManagerDialog::groupRenamed( QStandardItem *item )
1529 {
1530  QgsDebugMsg( QStringLiteral( "Symbol group edited: data=%1 text=%2" ).arg( item->data( Qt::UserRole + 1 ).toString(), item->text() ) );
1531  int id = item->data( Qt::UserRole + 1 ).toInt();
1532  QString name = item->text();
1533  mBlockGroupUpdates++;
1534  if ( item->parent()->data( Qt::UserRole + 1 ) == "smartgroups" )
1535  {
1536  mStyle->rename( QgsStyle::SmartgroupEntity, id, name );
1537  }
1538  else
1539  {
1540  mStyle->rename( QgsStyle::TagEntity, id, name );
1541  }
1542  mBlockGroupUpdates--;
1543 }
1544 
1546 {
1547  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
1548 
1549  if ( mGroupingMode )
1550  {
1551  mGroupingMode = false;
1552  mModel->setCheckable( false );
1553  actnTagSymbols->setVisible( true );
1554  actnFinishTagging->setVisible( false );
1555  // disconnect slot which handles regrouping
1556 
1557  // disable all items except groups in groupTree
1559  groupChanged( groupTree->currentIndex() );
1560 
1561  // Finally: Reconnect all Symbol editing functionalities
1562  connect( treeModel, &QStandardItemModel::itemChanged,
1564 
1565  // Reset the selection mode
1566  listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
1567  mSymbolTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection );
1568  }
1569  else
1570  {
1571  bool validGroup = false;
1572  // determine whether it is a valid group
1573  QModelIndex present = groupTree->currentIndex();
1574  while ( present.parent().isValid() )
1575  {
1576  if ( present.parent().data() == "Tags" )
1577  {
1578  validGroup = true;
1579  break;
1580  }
1581  present = present.parent();
1582  }
1583  if ( !validGroup )
1584  return;
1585 
1586  mGroupingMode = true;
1587  // Change visibility of actions
1588  actnTagSymbols->setVisible( false );
1589  actnFinishTagging->setVisible( true );
1590  // Remove all Symbol editing functionalities
1591  disconnect( treeModel, &QStandardItemModel::itemChanged,
1593 
1594  // disable all items except groups in groupTree
1595  enableItemsForGroupingMode( false );
1596  groupChanged( groupTree->currentIndex() );
1597  btnManageGroups->setEnabled( true );
1598 
1599  mModel->setCheckable( true );
1600 
1601  // No selection should be possible
1602  listItems->setSelectionMode( QAbstractItemView::NoSelection );
1603  mSymbolTreeView->setSelectionMode( QAbstractItemView::NoSelection );
1604  }
1605 }
1606 
1607 void QgsStyleManagerDialog::regrouped( QStandardItem * )
1608 {
1609 }
1610 
1611 void QgsStyleManagerDialog::setSymbolsChecked( const QStringList & )
1612 {
1613 }
1614 
1615 void QgsStyleManagerDialog::filterSymbols( const QString &qword )
1616 {
1617  mModel->setFilterString( qword );
1618 }
1619 
1620 void QgsStyleManagerDialog::symbolSelected( const QModelIndex &index )
1621 {
1622  actnEditItem->setEnabled( index.isValid() && !mGroupingMode && !mReadOnly );
1623 }
1624 
1625 void QgsStyleManagerDialog::selectedSymbolsChanged( const QItemSelection &selected, const QItemSelection &deselected )
1626 {
1627  Q_UNUSED( selected )
1628  Q_UNUSED( deselected )
1629  bool nothingSelected = listItems->selectionModel()->selectedIndexes().empty();
1630  actnRemoveItem->setDisabled( nothingSelected || mReadOnly );
1631  actnAddFavorite->setDisabled( nothingSelected || mReadOnly );
1632  actnRemoveFavorite->setDisabled( nothingSelected || mReadOnly );
1633  mGroupListMenu->setDisabled( nothingSelected || mReadOnly );
1634  actnDetag->setDisabled( nothingSelected || mReadOnly );
1635  actnExportAsPNG->setDisabled( nothingSelected );
1636  actnExportAsSVG->setDisabled( nothingSelected );
1637  if ( mActionCopyToDefault )
1638  mActionCopyToDefault->setDisabled( nothingSelected );
1639  mCopyToDefaultButton->setDisabled( nothingSelected );
1640  actnEditItem->setDisabled( nothingSelected || mReadOnly );
1641 }
1642 
1644 {
1645  groupTree->setEnabled( enable );
1646  btnAddTag->setEnabled( enable && !mReadOnly );
1647  btnAddSmartgroup->setEnabled( enable && !mReadOnly );
1648  actnAddTag->setEnabled( enable && !mReadOnly );
1649  actnAddSmartgroup->setEnabled( enable && !mReadOnly );
1650  actnRemoveGroup->setEnabled( enable && !mReadOnly );
1651  btnManageGroups->setEnabled( !mReadOnly && ( enable || mGroupingMode ) ); // always enabled in grouping mode, as it is the only way to leave grouping mode
1652  searchBox->setEnabled( enable );
1653 }
1654 
1656 {
1657  actnRemoveGroup->setEnabled( enable && !mReadOnly );
1658  btnManageGroups->setEnabled( !mReadOnly && ( enable || mGroupingMode ) ); // always enabled in grouping mode, as it is the only way to leave grouping mode
1659 }
1660 
1662 {
1663  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
1664  for ( int i = 0; i < treeModel->rowCount(); i++ )
1665  {
1666  treeModel->item( i )->setEnabled( enable );
1667 
1668  if ( treeModel->item( i )->data() == "smartgroups" )
1669  {
1670  for ( int j = 0; j < treeModel->item( i )->rowCount(); j++ )
1671  {
1672  treeModel->item( i )->child( j )->setEnabled( enable );
1673  }
1674  }
1675  }
1676 
1677  // The buttons
1678  // NOTE: if you ever change the layout name in the .ui file edit here too
1679  for ( int i = 0; i < symbolBtnsLayout->count(); i++ )
1680  {
1681  QWidget *w = symbolBtnsLayout->itemAt( i )->widget();
1682  if ( w )
1683  w->setEnabled( enable );
1684  }
1685 
1686  // The actions
1687  actnRemoveItem->setEnabled( enable );
1688  actnEditItem->setEnabled( enable );
1689 }
1690 
1692 {
1693  QPoint globalPos = groupTree->viewport()->mapToGlobal( point );
1694 
1695  QModelIndex index = groupTree->indexAt( point );
1696  if ( index.isValid() && !mGroupingMode )
1697  mGroupTreeContextMenu->popup( globalPos );
1698 }
1699 
1701 {
1702  QPoint globalPos = mSymbolViewStackedWidget->currentIndex() == 0
1703  ? listItems->viewport()->mapToGlobal( point )
1704  : mSymbolTreeView->viewport()->mapToGlobal( point );
1705 
1706  // Clear all actions and create new actions for every group
1707  mGroupListMenu->clear();
1708 
1709  if ( !mReadOnly )
1710  {
1711  QAction *a = nullptr;
1712  QStringList tags = mStyle->tags();
1713  tags.sort();
1714  for ( const QString &tag : qgis::as_const( tags ) )
1715  {
1716  a = new QAction( tag, mGroupListMenu );
1717  a->setData( tag );
1718  connect( a, &QAction::triggered, this, [ = ]( bool ) { tagSelectedSymbols(); }
1719  );
1720  mGroupListMenu->addAction( a );
1721  }
1722 
1723  if ( tags.count() > 0 )
1724  {
1725  mGroupListMenu->addSeparator();
1726  }
1727  a = new QAction( tr( "Create New Tag…" ), mGroupListMenu );
1728  connect( a, &QAction::triggered, this, [ = ]( bool ) { tagSelectedSymbols( true ); }
1729  );
1730  mGroupListMenu->addAction( a );
1731  }
1732 
1733  mGroupMenu->popup( globalPos );
1734 }
1735 
1737 {
1738  const QList< ItemDetails > items = selectedItems();
1739  for ( const ItemDetails &details : items )
1740  {
1741  mStyle->addFavorite( details.entityType, details.name );
1742  }
1743 }
1744 
1746 {
1747  const QList< ItemDetails > items = selectedItems();
1748  for ( const ItemDetails &details : items )
1749  {
1750  mStyle->removeFavorite( details.entityType, details.name );
1751  }
1752 }
1753 
1755 {
1756  QAction *selectedItem = qobject_cast<QAction *>( sender() );
1757  if ( selectedItem )
1758  {
1759  const QList< ItemDetails > items = selectedItems();
1760  QString tag;
1761  if ( newTag )
1762  {
1763  int id = addTag();
1764  if ( id == 0 )
1765  {
1766  return;
1767  }
1768 
1769  tag = mStyle->tag( id );
1770  }
1771  else
1772  {
1773  tag = selectedItem->data().toString();
1774  }
1775 
1776  for ( const ItemDetails &details : items )
1777  {
1778  mStyle->tagSymbol( details.entityType, details.name, QStringList( tag ) );
1779  }
1780  }
1781 }
1782 
1784 {
1785  QAction *selectedItem = qobject_cast<QAction *>( sender() );
1786 
1787  if ( selectedItem )
1788  {
1789  const QList< ItemDetails > items = selectedItems();
1790  for ( const ItemDetails &details : items )
1791  {
1792  mStyle->detagSymbol( details.entityType, details.name );
1793  }
1794  }
1795 }
1796 
1798 {
1799  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
1800 
1801  // determine whether it is a valid group
1802  QModelIndex present = groupTree->currentIndex();
1803  if ( present.parent().data( Qt::UserRole + 1 ) != "smartgroups" )
1804  {
1805  // should never appear - blocked by GUI logic
1806  QMessageBox::critical( this, tr( "Edit Smart Group" ),
1807  tr( "You have not selected a Smart Group. Kindly select a Smart Group to edit." ) );
1808  return;
1809  }
1810  QStandardItem *item = treeModel->itemFromIndex( present );
1811 
1812  QgsSmartGroupEditorDialog dlg( mStyle, this );
1813  QgsSmartConditionMap map = mStyle->smartgroup( present.data( Qt::UserRole + 1 ).toInt() );
1814  dlg.setSmartgroupName( item->text() );
1815  dlg.setOperator( mStyle->smartgroupOperator( item->data().toInt() ) );
1816  dlg.setConditionMap( map );
1817 
1818  if ( dlg.exec() == QDialog::Rejected )
1819  return;
1820 
1821  mBlockGroupUpdates++;
1822  mStyle->remove( QgsStyle::SmartgroupEntity, item->data().toInt() );
1823  int id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() );
1824  mBlockGroupUpdates--;
1825  if ( !id )
1826  {
1827  mMessageBar->pushCritical( tr( "Edit Smart Group" ), tr( "There was an error while editing the smart group." ) );
1828  return;
1829  }
1830  item->setText( dlg.smartgroupName() );
1831  item->setData( id );
1832 
1833  groupChanged( present );
1834 }
1835 
1837 {
1838  reject();
1839 }
1840 
1842 {
1843  QgsHelp::openHelp( QStringLiteral( "working_with_vector/style_library.html#the-style-manager" ) );
1844 }
1845 
void setBaseStyleName(const QString &name)
Sets the base name for the style, which is used by the dialog to reflect the original style/XML file ...
void groupChanged(const QModelIndex &)
Trigerred when the current group (or tag) is changed.
void tagSymbolsAction()
Toggles the interactive item tagging mode.
void setSmartGroupsVisible(bool show)
Sets whether smart groups should be shown.
void editItem()
Triggers the dialog for editing the current item.
QString tags() const
returns the text value of the tags element
Temporarily sets a cursor override for the QApplication for the lifetime of the object.
Definition: qgsguiutils.h:203
bool addColorRamp(const QString &name, QgsColorRamp *colorRamp, bool update=false)
Adds a color ramp to the style.
Definition: qgsstyle.cpp:197
void symbolSaved(const QString &name, QgsSymbol *symbol)
Emitted every time a new symbol has been added to the database.
Q_DECL_DEPRECATED void regrouped(QStandardItem *) SIP_DEPRECATED
void setBold(QStandardItem *)
sets the text of the item with bold font
bool save(QString filename=QString())
Saves style into a file (will use current filename if empty string is passed)
Definition: qgsstyle.cpp:429
A dialog allowing users to customize and populate a QgsStyle.
QgsStyleManagerDialog(QgsStyle *style, QWidget *parent SIP_TRANSFERTHIS=nullptr, Qt::WindowFlags flags=Qt::WindowFlags(), bool readOnly=false)
Constructor for QgsStyleManagerDialog, with the specified parent widget and window flags...
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
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QgsColorBrewerColorRamp * clone() const override
Creates a clone of the color ramp.
void populateList()
Refreshes the list of items.
void onFinished()
Called when the dialog is going to be closed.
QgsSmartConditionMap conditionMap()
returns the condition map
int addSmartgroup()
Triggers the dialog to add a new smart group.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void selectedSymbolsChanged(const QItemSelection &selected, const QItemSelection &deselected)
Perform tasks when the selected symbols change.
QStringList tagsOfSymbol(StyleEntity type, const QString &symbol)
Returns the tags associated with the symbol.
Definition: qgsstyle.cpp:1043
QString name() const
returns the text value of the name element
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
QMap< int, QString > QgsSymbolGroupMap
Definition: qgsstyle.h:38
QString schemeName() const
Definition: qgscolorramp.h:666
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
bool saveColorRamp(const QString &name, QgsColorRamp *ramp, bool favorite, const QStringList &tags)
Adds the colorramp to the DB.
Definition: qgsstyle.cpp:221
void populateGroups()
populate the groups
bool tagSymbol(StyleEntity type, const QString &symbol, const QStringList &tags)
Tags the symbol with the tags in the list.
Definition: qgsstyle.cpp:892
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:45
void importItems()
Triggers the dialog to import items.
bool addColorRamp()
add a new color ramp to style
Q_DECL_DEPRECATED void populateTypes() SIP_DEPRECATED
Populate combo box with known style items (symbols, color ramps).
Line symbol.
Definition: qgssymbol.h:86
A dialog which allows users to modify the properties of a QgsColorBrewerColorRamp.
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
Definition: qgsstyle.cpp:272
Q_DECL_DEPRECATED void itemChanged(QStandardItem *item) SIP_DEPRECATED
QString smartgroupName()
returns the value from mNameLineEdit
bool removeColorRamp(const QString &name)
Removes color ramp from style (and delete it)
Definition: qgsstyle.cpp:252
bool rename(StyleEntity type, int id, const QString &newName)
Renames the given entity with the specified id.
Definition: qgsstyle.cpp:667
void pushSuccess(const QString &title, const QString &message)
Pushes a success message with default timeout to the message bar.
A dialog which allows users to modify the properties of a QgsGradientColorRamp.
A dialog which allows users to modify the properties of a QgsPresetSchemeColorRamp.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:766
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:966
String list of tags.
Definition: qgsstylemodel.h:58
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:46
A dialog which allows users to modify the properties of a QgsLimitedRandomColorRamp.
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstyle.h:95
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
SymbolType
Type of the symbol.
Definition: qgssymbol.h:83
void tagSelectedSymbols(bool newTag=false)
Tag selected symbols using menu item selection.
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
QgsGradientColorRamp * clone() const override
Creates a clone of the color ramp.
bool addSymbol(int symbolType=-1)
add a new symbol to style
int colors() const
Returns the number of colors in the ramp.
Definition: qgscolorramp.h:575
Constrained random color ramp, which returns random colors based on preset parameters.
Definition: qgscolorramp.h:283
void filterSymbols(const QString &filter)
Sets the filter string to filter symbols by.
QString tag(int id) const
Returns the tag name for the given id.
Definition: qgsstyle.cpp:1143
Q_DECL_DEPRECATED bool removeColorRamp() SIP_DEPRECATED
void exportItemsSVG()
Triggers the dialog to export selected items as SVG files.
QStringList symbolNames()
Returns a list of names of symbols.
Definition: qgsstyle.cpp:191
bool removeFavorite(StyleEntity type, const QString &name)
Removes the specified symbol from favorites.
Definition: qgsstyle.cpp:803
QgsPresetSchemeColorRamp * clone() const override
Creates a clone of the color ramp.
bool remove(StyleEntity type, int id)
Removes the specified entity from the db.
Definition: qgsstyle.cpp:717
void groupsModified()
Emitted every time a tag or smartgroup has been added, removed, or renamed.
void enableItemsForGroupingMode(bool)
Enables or disables the groupTree items for grouping mode.
void editSmartgroupAction()
Triggers the dialog for editing the selected smart group.
void exportSelectedItemsImages(const QString &dir, const QString &format, QSize size)
Triggers the dialog to export selected items as images of the specified format and size...
int addTag(const QString &tagName)
Adds a new tag and returns the tag&#39;s id.
Definition: qgsstyle.cpp:627
Q_DECL_DEPRECATED void populateColorRamps(const QStringList &colorRamps, bool checkable=false) SIP_DEPRECATED
Populates the list view with color ramps of the current type with the given names.
void symbolSelected(const QModelIndex &)
Perform symbol specific tasks when selected.
QString smartgroupOperator(int id)
Returns the operator for the smartgroup clumsy implementation TODO create a class for smartgroups...
Definition: qgsstyle.cpp:1468
void grouptreeContextMenu(QPoint)
Context menu for the groupTree.
static QString addColorRampStatic(QWidget *parent, QgsStyle *style, QString RampType=QString())
Opens the add color ramp dialog, returning the new color ramp&#39;s name if the ramp has been added...
void removeFavoriteSelectedSymbols()
Remove selected symbols from favorites.
A scheme based color ramp consisting of a list of predefined colors.
Definition: qgscolorramp.h:471
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
A QSortFilterProxyModel subclass for showing filtered symbol and color ramps entries from a QgsStyle ...
QgsGradientColorRamp * cloneGradientRamp() const
QgsSmartConditionMap smartgroup(int id)
Returns the QgsSmartConditionMap for the given id.
Definition: qgsstyle.cpp:1428
QStringList colorRampNames()
Returns a list of names of color ramps.
Definition: qgsstyle.cpp:288
QgsLimitedRandomColorRamp * clone() const override
Creates a clone of the color ramp.
void enableSymbolInputs(bool)
Enables or disbables the symbol specific inputs.
Q_DECL_DEPRECATED void populateSymbols(const QStringList &symbolNames, bool checkable=false) SIP_DEPRECATED
Populates the list view with symbols of the current type with the given names.
void setFavoritesGroupVisible(bool show)
Sets whether the favorites group should be shown.
int tagId(const QString &tag)
Returns the DB id for the given tag name.
Definition: qgsstyle.cpp:1218
QString schemeName() const
Returns the name of the color brewer color scheme.
Definition: qgscolorramp.h:569
void groupRenamed(QStandardItem *item)
Triggered when a group item is renamed.
void addFavoriteSelectedSymbols()
Add selected symbols to favorites.
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
QStringList tags() const
Returns a list of all tags in the style database.
Definition: qgsstyle.cpp:647
Fill symbol.
Definition: qgssymbol.h:87
int addSmartgroup(const QString &name, const QString &op, const QgsSmartConditionMap &conditions)
Adds a new smartgroup to the database and returns the id.
Definition: qgsstyle.cpp:1228
Name column.
Definition: qgsstylemodel.h:50
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void setOperator(const QString &)
sets the operator AND/OR
QgsCptCityColorRamp * clone() const override
Creates a clone of the color ramp.
void activate()
Raises, unminimizes and activates this window.
QgsPresetSchemeColorRamp ramp
Q_DECL_DEPRECATED void setSymbolsChecked(const QStringList &) SIP_DEPRECATED
void removeGroup()
Removes the selected tag or smartgroup.
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
void listitemsContextMenu(QPoint)
Context menu for the listItems ( symbols list )
Color ramp utilising "Color Brewer" preset color schemes.
Definition: qgscolorramp.h:535
bool isFavorite() const
returns whether the favorite element is checked
int addTag()
Triggers the dialog to add a new tag.
void setSmartgroupName(const QString &)
sets the smart group Name
void exportItemsPNG()
Triggers the dialog to export selected items as PNG files.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgssymbol.h:1061
void showHelp()
Opens the associated help.
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:175
void addItem()
Triggers the dialog for adding a new item, based on the currently selected item type tab...
void exportItems()
Triggers the dialog to export items.
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 onClose()
Closes the dialog.
bool removeSymbol(const QString &name)
Removes symbol from style (and delete it)
Definition: qgsstyle.cpp:143
A dialog which allows users to modify the properties of a QgsCptCityColorRamp.
Style entity type, see QgsStyle::StyleEntity.
Definition: qgsstylemodel.h:57
bool addFavorite(StyleEntity type, const QString &name)
Adds the specified symbol to favorites.
Definition: qgsstyle.cpp:778
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
void setConditionMap(const QgsSmartConditionMap &)
sets up the GUI for the given conditionmap
QString variantName() const
Definition: qgscolorramp.h:667
bool detagSymbol(StyleEntity type, const QString &symbol, const QStringList &tags)
Detags the symbol with the given list.
Definition: qgsstyle.cpp:946
QStringList symbolsOfFavorite(StyleEntity type) const
Returns the symbol names which are flagged as favorite.
Definition: qgsstyle.cpp:542
QMultiMap< QString, QString > QgsSmartConditionMap
A multimap to hold the smart group conditions as constraint and parameter pairs.
Definition: qgsstyle.h:63
bool saveAsGradientRamp() const
Returns true if the ramp should be converted to a QgsGradientColorRamp.
void removeItem()
Removes the current selected item.
QgsSymbolGroupMap smartgroupsListMap()
Returns the smart groups map with id as key and name as value.
Definition: qgsstyle.cpp:1280
Q_DECL_DEPRECATED bool removeSymbol() SIP_DEPRECATED
void detagSelectedSymbols()
Remove all tags from selected symbols.
Symbol type (for symbol entities)
Definition: qgsstylemodel.h:59
QString conditionOperator()
returns the AND/OR condition
void enableGroupInputs(bool)
Enables or disables the groupTree specific inputs.
void pushCritical(const QString &title, const QString &message)
Pushes a critical warning with default timeout to the message bar.