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