QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 #include "qgstextformatwidget.h"
35 #include "qgslabelinggui.h"
36 #include <QAction>
37 #include <QFile>
38 #include <QFileDialog>
39 #include <QInputDialog>
40 #include <QMessageBox>
41 #include <QPushButton>
42 #include <QStandardItemModel>
43 #include <QMenu>
44 #include <QClipboard>
45 
46 #include "qgsapplication.h"
47 #include "qgslogger.h"
48 
49 //
50 // QgsCheckableStyleModel
51 //
52 
54 QgsCheckableStyleModel::QgsCheckableStyleModel( QgsStyleModel *sourceModel, QObject *parent, bool readOnly )
55  : QgsStyleProxyModel( sourceModel, parent )
56  , mStyle( sourceModel->style() )
57  , mReadOnly( readOnly )
58 {
59 
60 }
61 
62 QgsCheckableStyleModel::QgsCheckableStyleModel( QgsStyle *style, QObject *parent, bool readOnly )
63  : QgsStyleProxyModel( style, parent )
64  , mStyle( style )
65  , mReadOnly( readOnly )
66 {
67 }
68 
69 void QgsCheckableStyleModel::setCheckable( bool checkable )
70 {
71  if ( checkable == mCheckable )
72  return;
73 
74  mCheckable = checkable;
75  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector< int >() << Qt::CheckStateRole );
76 }
77 
78 void QgsCheckableStyleModel::setCheckTag( const QString &tag )
79 {
80  if ( tag == mCheckTag )
81  return;
82 
83  mCheckTag = tag;
84  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector< int >() << Qt::CheckStateRole );
85 }
86 
87 Qt::ItemFlags QgsCheckableStyleModel::flags( const QModelIndex &index ) const
88 {
89  Qt::ItemFlags f = QgsStyleProxyModel::flags( index );
90  if ( !mReadOnly && mCheckable && index.column() == 0 )
91  f |= Qt::ItemIsUserCheckable;
92 
93  if ( mReadOnly )
94  f &= ~Qt::ItemIsEditable;
95 
96  return f;
97 }
98 
99 QVariant QgsCheckableStyleModel::data( const QModelIndex &index, int role ) const
100 {
101  switch ( role )
102  {
103  case Qt::FontRole:
104  {
105  // drop font size to get reasonable amount of item name shown
106  QFont f = QgsStyleProxyModel::data( index, role ).value< QFont >();
107  f.setPointSize( 9 );
108  return f;
109  }
110 
111  case Qt::CheckStateRole:
112  {
113  if ( !mCheckable || index.column() != 0 )
114  return QVariant();
115 
116  const QStringList tags = data( index, QgsStyleModel::TagRole ).toStringList();
117  return tags.contains( mCheckTag ) ? Qt::Checked : Qt::Unchecked;
118  }
119 
120  default:
121  break;
122 
123  }
124  return QgsStyleProxyModel::data( index, role );
125 }
126 
127 bool QgsCheckableStyleModel::setData( const QModelIndex &i, const QVariant &value, int role )
128 {
129  if ( i.row() < 0 || i.row() >= rowCount( QModelIndex() ) ||
130  ( role != Qt::EditRole && role != Qt::CheckStateRole ) )
131  return false;
132 
133  if ( mReadOnly )
134  return false;
135 
136  if ( role == Qt::CheckStateRole )
137  {
138  if ( !mCheckable || mCheckTag.isEmpty() )
139  return false;
140 
141  const QString name = data( index( i.row(), QgsStyleModel::Name ), Qt::DisplayRole ).toString();
142  const QgsStyle::StyleEntity entity = static_cast< QgsStyle::StyleEntity >( data( i, QgsStyleModel::TypeRole ).toInt() );
143 
144  if ( value.toInt() == Qt::Checked )
145  return mStyle->tagSymbol( entity, name, QStringList() << mCheckTag );
146  else
147  return mStyle->detagSymbol( entity, name, QStringList() << mCheckTag );
148  }
149  return QgsStyleProxyModel::setData( i, value, role );
150 }
152 
153 //
154 // QgsStyleManagerDialog
155 //
156 
157 #include "qgsgui.h"
158 
159 QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle *style, QWidget *parent, Qt::WindowFlags flags, bool readOnly )
160  : QDialog( parent, flags )
161  , mStyle( style )
162  , mReadOnly( readOnly )
163 {
164  setupUi( this );
166  connect( tabItemType, &QTabWidget::currentChanged, this, &QgsStyleManagerDialog::tabItemType_currentChanged );
167  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsStyleManagerDialog::showHelp );
168  connect( buttonBox, &QDialogButtonBox::rejected, this, &QgsStyleManagerDialog::onClose );
169 
170  mMessageBar = new QgsMessageBar();
171  mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
172  mVerticalLayout->insertWidget( 0, mMessageBar );
173 
174 #ifdef Q_OS_MAC
175  setWindowModality( Qt::WindowModal );
176 #endif
177 
178  QgsSettings settings;
179 
180  mSplitter->setSizes( QList<int>() << 170 << 540 );
181  mSplitter->restoreState( settings.value( QStringLiteral( "Windows/StyleV2Manager/splitter" ) ).toByteArray() );
182 
183  tabItemType->setDocumentMode( true );
184  searchBox->setShowSearchIcon( true );
185  searchBox->setPlaceholderText( tr( "Filter symbols…" ) );
186 
187  connect( this, &QDialog::finished, this, &QgsStyleManagerDialog::onFinished );
188  connect( listItems, &QAbstractItemView::doubleClicked, this, &QgsStyleManagerDialog::editItem );
189  connect( btnEditItem, &QPushButton::clicked, this, [ = ]( bool ) { editItem(); }
190  );
191  connect( actnEditItem, &QAction::triggered, this, [ = ]( bool ) { editItem(); }
192  );
193 
194  if ( !mReadOnly )
195  {
196  connect( btnAddItem, &QPushButton::clicked, this, [ = ]( bool ) { addItem(); }
197  );
198 
199  connect( btnRemoveItem, &QPushButton::clicked, this, [ = ]( bool ) { removeItem(); }
200  );
201  connect( actnRemoveItem, &QAction::triggered, this, [ = ]( bool ) { removeItem(); }
202  );
203  }
204  else
205  {
206  btnAddTag->setEnabled( false );
207  btnAddSmartgroup->setEnabled( false );
208  }
209 
210  QMenu *shareMenu = new QMenu( tr( "Share Menu" ), this );
211  QAction *exportAction = new QAction( tr( "Export Item(s)…" ), this );
212  exportAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileSave.svg" ) ) );
213  shareMenu->addAction( exportAction );
214  if ( !mReadOnly )
215  {
216  QAction *importAction = new QAction( tr( "Import Item(s)…" ), this );
217  importAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileOpen.svg" ) ) );
218  shareMenu->addAction( importAction );
219  connect( importAction, &QAction::triggered, this, &QgsStyleManagerDialog::importItems );
220  }
221  if ( mStyle != QgsStyle::defaultStyle() )
222  {
223  mActionCopyToDefault = new QAction( tr( "Copy Selection to Default Style…" ), this );
224  shareMenu->addAction( mActionCopyToDefault );
225  connect( mActionCopyToDefault, &QAction::triggered, this, &QgsStyleManagerDialog::copyItemsToDefault );
226  connect( mCopyToDefaultButton, &QPushButton::clicked, this, &QgsStyleManagerDialog::copyItemsToDefault );
227  }
228  else
229  {
230  mCopyToDefaultButton->hide();
231  }
232 
233  mActionCopyItem = new QAction( tr( "Copy Item" ), this );
234  connect( mActionCopyItem, &QAction::triggered, this, &QgsStyleManagerDialog::copyItem );
235  mActionPasteItem = new QAction( tr( "Paste Item…" ), this );
236  connect( mActionPasteItem, &QAction::triggered, this, &QgsStyleManagerDialog::pasteItem );
237 
238  shareMenu->addSeparator();
239  shareMenu->addAction( actnExportAsPNG );
240  shareMenu->addAction( actnExportAsSVG );
241 
242  connect( actnExportAsPNG, &QAction::triggered, this, &QgsStyleManagerDialog::exportItemsPNG );
243  connect( actnExportAsSVG, &QAction::triggered, this, &QgsStyleManagerDialog::exportItemsSVG );
244  connect( exportAction, &QAction::triggered, this, &QgsStyleManagerDialog::exportItems );
245  btnShare->setMenu( shareMenu );
246 
247  double iconSize = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 10;
248  listItems->setIconSize( QSize( static_cast< int >( iconSize ), static_cast< int >( iconSize * 0.9 ) ) ); // ~100, 90 on low dpi
249  double treeIconSize = Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 2;
250  mSymbolTreeView->setIconSize( QSize( static_cast< int >( treeIconSize ), static_cast< int >( treeIconSize ) ) );
251 
252  mModel = mStyle == QgsStyle::defaultStyle() ? new QgsCheckableStyleModel( QgsApplication::defaultStyleModel(), this, mReadOnly )
253  : new QgsCheckableStyleModel( mStyle, this, mReadOnly );
254  mModel->addDesiredIconSize( listItems->iconSize() );
255  mModel->addDesiredIconSize( mSymbolTreeView->iconSize() );
256  listItems->setModel( mModel );
257  mSymbolTreeView->setModel( mModel );
258 
259  listItems->setSelectionBehavior( QAbstractItemView::SelectRows );
260  listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
261  mSymbolTreeView->setSelectionModel( listItems->selectionModel() );
262  mSymbolTreeView->setSelectionMode( listItems->selectionMode() );
263 
264  connect( listItems->selectionModel(), &QItemSelectionModel::currentChanged,
266  connect( listItems->selectionModel(), &QItemSelectionModel::selectionChanged,
268 
269  QStandardItemModel *groupModel = new QStandardItemModel( groupTree );
270  groupTree->setModel( groupModel );
271  groupTree->setHeaderHidden( true );
272  populateGroups();
273  groupTree->setCurrentIndex( groupTree->model()->index( 0, 0 ) );
274 
275  connect( groupTree->selectionModel(), &QItemSelectionModel::currentChanged,
277  if ( !mReadOnly )
278  {
279  connect( groupModel, &QStandardItemModel::itemChanged,
281  }
282 
283  if ( !mReadOnly )
284  {
285  QMenu *groupMenu = new QMenu( tr( "Group Actions" ), this );
286  connect( actnTagSymbols, &QAction::triggered, this, &QgsStyleManagerDialog::tagSymbolsAction );
287  groupMenu->addAction( actnTagSymbols );
288  connect( actnFinishTagging, &QAction::triggered, this, &QgsStyleManagerDialog::tagSymbolsAction );
289  actnFinishTagging->setVisible( false );
290  groupMenu->addAction( actnFinishTagging );
291  groupMenu->addAction( actnEditSmartGroup );
292  btnManageGroups->setMenu( groupMenu );
293  }
294  else
295  {
296  btnManageGroups->setEnabled( false );
297  }
298 
299  connect( searchBox, &QLineEdit::textChanged, this, &QgsStyleManagerDialog::filterSymbols );
300 
301  // Context menu for groupTree
302  groupTree->setContextMenuPolicy( Qt::CustomContextMenu );
303  connect( groupTree, &QWidget::customContextMenuRequested,
305 
306  // Context menu for listItems
307  listItems->setContextMenuPolicy( Qt::CustomContextMenu );
308  connect( listItems, &QWidget::customContextMenuRequested,
310  mSymbolTreeView->setContextMenuPolicy( Qt::CustomContextMenu );
311  connect( mSymbolTreeView, &QWidget::customContextMenuRequested,
313 
314  if ( !mReadOnly )
315  {
316  // Menu for the "Add item" toolbutton when in colorramp mode
317  QStringList rampTypes;
318  rampTypes << tr( "Gradient…" ) << tr( "Color presets…" ) << tr( "Random…" ) << tr( "Catalog: cpt-city…" );
319  rampTypes << tr( "Catalog: ColorBrewer…" );
320 
321  mMenuBtnAddItemAll = new QMenu( this );
322  mMenuBtnAddItemColorRamp = new QMenu( this );
323  mMenuBtnAddItemLabelSettings = new QMenu( this );
324 
325  QAction *item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "mIconPointLayer.svg" ) ), tr( "Marker…" ), this );
326  connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Marker ); } );
327  mMenuBtnAddItemAll->addAction( item );
328  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "mIconLineLayer.svg" ) ), tr( "Line…" ), this );
329  connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Line ); } );
330  mMenuBtnAddItemAll->addAction( item );
331  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "mIconPolygonLayer.svg" ) ), tr( "Fill…" ), this );
332  connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Fill ); } );
333  mMenuBtnAddItemAll->addAction( item );
334  mMenuBtnAddItemAll->addSeparator();
335  for ( const QString &rampType : qgis::as_const( rampTypes ) )
336  {
337  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "styleicons/color.svg" ) ), rampType, this );
338  connect( item, &QAction::triggered, this, [ = ]( bool ) { addColorRamp( item ); } );
339  mMenuBtnAddItemAll->addAction( item );
340  mMenuBtnAddItemColorRamp->addAction( new QAction( rampType, this ) );
341  }
342  mMenuBtnAddItemAll->addSeparator();
343  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "mIconFieldText.svg" ) ), tr( "Text Format…" ), this );
344  connect( item, &QAction::triggered, this, [ = ]( bool ) { addTextFormat(); } );
345  mMenuBtnAddItemAll->addAction( item );
346  mMenuBtnAddItemAll->addSeparator();
347  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "labelingSingle.svg" ) ), tr( "Point Label Settings…" ), this );
348  connect( item, &QAction::triggered, this, [ = ]( bool ) { addLabelSettings( QgsWkbTypes::PointGeometry ); } );
349  mMenuBtnAddItemAll->addAction( item );
350  mMenuBtnAddItemLabelSettings->addAction( item );
351  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "labelingSingle.svg" ) ), tr( "Line Label Settings…" ), this );
352  connect( item, &QAction::triggered, this, [ = ]( bool ) { addLabelSettings( QgsWkbTypes::LineGeometry ); } );
353  mMenuBtnAddItemAll->addAction( item );
354  mMenuBtnAddItemLabelSettings->addAction( item );
355  item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "labelingSingle.svg" ) ), tr( "Polygon Label Settings…" ), this );
356  connect( item, &QAction::triggered, this, [ = ]( bool ) { addLabelSettings( QgsWkbTypes::PolygonGeometry ); } );
357  mMenuBtnAddItemAll->addAction( item );
358  mMenuBtnAddItemLabelSettings->addAction( item );
359 
360  connect( mMenuBtnAddItemColorRamp, &QMenu::triggered,
361  this, static_cast<bool ( QgsStyleManagerDialog::* )( QAction * )>( &QgsStyleManagerDialog::addColorRamp ) );
362  }
363 
364  // Context menu for symbols/colorramps. The menu entries for every group are created when displaying the menu.
365  mGroupMenu = new QMenu( this );
366  mGroupListMenu = new QMenu( mGroupMenu );
367  mGroupListMenu->setTitle( tr( "Add to Tag" ) );
368  mGroupListMenu->setEnabled( false );
369  if ( !mReadOnly )
370  {
371  connect( actnAddFavorite, &QAction::triggered, this, &QgsStyleManagerDialog::addFavoriteSelectedSymbols );
372  mGroupMenu->addAction( actnAddFavorite );
373  connect( actnRemoveFavorite, &QAction::triggered, this, &QgsStyleManagerDialog::removeFavoriteSelectedSymbols );
374  mGroupMenu->addAction( actnRemoveFavorite );
375  mGroupMenu->addSeparator()->setParent( this );
376  mGroupMenu->addMenu( mGroupListMenu );
377  actnDetag->setData( 0 );
378  connect( actnDetag, &QAction::triggered, this, &QgsStyleManagerDialog::detagSelectedSymbols );
379  mGroupMenu->addAction( actnDetag );
380  mGroupMenu->addSeparator()->setParent( this );
381  mGroupMenu->addAction( actnRemoveItem );
382  mGroupMenu->addAction( actnEditItem );
383  mGroupMenu->addAction( mActionCopyItem );
384  mGroupMenu->addAction( mActionPasteItem );
385  mGroupMenu->addSeparator()->setParent( this );
386  }
387  else
388  {
389  btnAddItem->setVisible( false );
390  btnRemoveItem->setVisible( false );
391  btnEditItem->setVisible( false );
392  btnAddSmartgroup->setVisible( false );
393  btnAddTag->setVisible( false );
394  btnManageGroups->setVisible( false );
395 
396  mGroupMenu->addAction( mActionCopyItem );
397  }
398  if ( mActionCopyToDefault )
399  {
400  mGroupMenu->addAction( mActionCopyToDefault );
401  }
402  mGroupMenu->addAction( actnExportAsPNG );
403  mGroupMenu->addAction( actnExportAsSVG );
404 
405  // Context menu for the group tree
406  mGroupTreeContextMenu = new QMenu( this );
407  if ( !mReadOnly )
408  {
409  connect( actnEditSmartGroup, &QAction::triggered, this, &QgsStyleManagerDialog::editSmartgroupAction );
410  mGroupTreeContextMenu->addAction( actnEditSmartGroup );
411  connect( actnAddTag, &QAction::triggered, this, [ = ]( bool ) { addTag(); }
412  );
413  mGroupTreeContextMenu->addAction( actnAddTag );
414  connect( actnAddSmartgroup, &QAction::triggered, this, [ = ]( bool ) { addSmartgroup(); }
415  );
416  mGroupTreeContextMenu->addAction( actnAddSmartgroup );
417  connect( actnRemoveGroup, &QAction::triggered, this, &QgsStyleManagerDialog::removeGroup );
418  mGroupTreeContextMenu->addAction( actnRemoveGroup );
419  }
420 
421  tabItemType_currentChanged( 0 );
422 
425 
426  connect( mButtonIconView, &QToolButton::toggled, this, [ = ]( bool active )
427  {
428  if ( active )
429  {
430  mSymbolViewStackedWidget->setCurrentIndex( 0 );
431  // note -- we have to save state here and not in destructor, as new symbol list widgets are created before the previous ones are destroyed
432  QgsSettings().setValue( QStringLiteral( "Windows/StyleV2Manager/lastIconView" ), 0, QgsSettings::Gui );
433  }
434  } );
435  connect( mButtonListView, &QToolButton::toggled, this, [ = ]( bool active )
436  {
437  if ( active )
438  {
439  QgsSettings().setValue( QStringLiteral( "Windows/StyleV2Manager/lastIconView" ), 1, QgsSettings::Gui );
440  mSymbolViewStackedWidget->setCurrentIndex( 1 );
441  }
442  } );
443  // restore previous view
444  const int currentView = settings.value( QStringLiteral( "Windows/StyleV2Manager/lastIconView" ), 0, QgsSettings::Gui ).toInt();
445  if ( currentView == 0 )
446  mButtonIconView->setChecked( true );
447  else
448  mButtonListView->setChecked( true );
449 
450  mSymbolTreeView->header()->restoreState( settings.value( QStringLiteral( "Windows/StyleV2Manager/treeState" ), QByteArray(), QgsSettings::Gui ).toByteArray() );
451  connect( mSymbolTreeView->header(), &QHeaderView::sectionResized, this, [this]
452  {
453  // note -- we have to save state here and not in destructor, as new symbol list widgets are created before the previous ones are destroyed
454  QgsSettings().setValue( QStringLiteral( "Windows/StyleV2Manager/treeState" ), mSymbolTreeView->header()->saveState(), QgsSettings::Gui );
455  } );
456 
457  // set initial disabled state for actions requiring a selection
458  selectedSymbolsChanged( QItemSelection(), QItemSelection() );
459 }
460 
462 {
463  if ( mModified && !mReadOnly )
464  {
465  mStyle->save();
466  }
467 
468  QgsSettings settings;
469  settings.setValue( QStringLiteral( "Windows/StyleV2Manager/splitter" ), mSplitter->saveState() );
470 }
471 
473 {
474 }
475 
476 void QgsStyleManagerDialog::tabItemType_currentChanged( int )
477 {
478  // when in Color Ramp tab, add menu to add item button and hide "Export symbols as PNG/SVG"
479  const bool isSymbol = currentItemType() != 3 && currentItemType() != 4 && currentItemType() != 5;
480  const bool isColorRamp = currentItemType() == 3;
481  const bool isTextFormat = currentItemType() == 4;
482  searchBox->setPlaceholderText( isSymbol ? tr( "Filter symbols…" ) :
483  isColorRamp ? tr( "Filter color ramps…" ) :
484  isTextFormat ? tr( "Filter text symbols…" ) : tr( "Filter label settings…" ) );
485 
486  if ( !mReadOnly && isColorRamp ) // color ramp tab
487  {
488  btnAddItem->setMenu( mMenuBtnAddItemColorRamp );
489  }
490  if ( !mReadOnly && !isSymbol && !isColorRamp && !isTextFormat ) // label settings tab
491  {
492  btnAddItem->setMenu( mMenuBtnAddItemLabelSettings );
493  }
494  else if ( !mReadOnly && !isSymbol && !isColorRamp ) // text format tab
495  {
496  btnAddItem->setMenu( nullptr );
497  }
498  else if ( !mReadOnly && tabItemType->currentIndex() == 0 ) // all symbols tab
499  {
500  btnAddItem->setMenu( mMenuBtnAddItemAll );
501  }
502  else
503  {
504  btnAddItem->setMenu( nullptr );
505  }
506 
507  actnExportAsPNG->setVisible( isSymbol );
508  actnExportAsSVG->setVisible( isSymbol );
509 
510  mModel->setEntityFilter( isSymbol ? QgsStyle::SymbolEntity : ( isColorRamp ? QgsStyle::ColorrampEntity : isTextFormat ? QgsStyle::TextFormatEntity : QgsStyle::LabelSettingsEntity ) );
511  mModel->setEntityFilterEnabled( !allTypesSelected() );
512  mModel->setSymbolTypeFilterEnabled( isSymbol && !allTypesSelected() );
513  if ( isSymbol && !allTypesSelected() )
514  mModel->setSymbolType( static_cast< QgsSymbol::SymbolType >( currentItemType() ) );
515 
516  populateList();
517 }
518 
519 void QgsStyleManagerDialog::copyItemsToDefault()
520 {
521  const QList< ItemDetails > items = selectedItems();
522  if ( !items.empty() )
523  {
524  bool ok = false;
525  QStringList options;
526  if ( !mBaseName.isEmpty() )
527  options.append( mBaseName );
528 
529  QStringList defaultTags = QgsStyle::defaultStyle()->tags();
530  defaultTags.sort( Qt::CaseInsensitive );
531  options.append( defaultTags );
532  const QString tags = QInputDialog::getItem( this, tr( "Import Items" ),
533  tr( "Additional tags to add (comma separated)" ), options, mBaseName.isEmpty() ? -1 : 0, true, &ok );
534  if ( !ok )
535  return;
536 
537  const QStringList parts = tags.split( ',', QString::SkipEmptyParts );
538  QStringList additionalTags;
539  additionalTags.reserve( parts.count() );
540  for ( const QString &tag : parts )
541  additionalTags << tag.trimmed();
542 
543  auto cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
544  const int count = copyItems( items, mStyle, QgsStyle::defaultStyle(), this, cursorOverride, true, additionalTags, false, false );
545  cursorOverride.reset();
546  if ( count > 0 )
547  {
548  mMessageBar->pushSuccess( tr( "Import Items" ), count > 1 ? tr( "Successfully imported %1 items." ).arg( count ) : tr( "Successfully imported item." ) );
549  }
550  }
551 }
552 
553 void QgsStyleManagerDialog::copyItem()
554 {
555  const QList< ItemDetails > items = selectedItems();
556  if ( items.empty() )
557  return;
558 
559  ItemDetails details = items.at( 0 );
560  switch ( details.entityType )
561  {
563  {
564  std::unique_ptr< QgsSymbol > symbol( mStyle->symbol( details.name ) );
565  if ( !symbol )
566  return;
567  QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::symbolToMimeData( symbol.get() ) );
568  break;
569  }
570 
572  {
573  const QgsTextFormat format( mStyle->textFormat( details.name ) );
574  QApplication::clipboard()->setMimeData( format.toMimeData() );
575  break;
576  }
577 
579  {
580  const QgsTextFormat format( mStyle->labelSettings( details.name ).format() );
581  QApplication::clipboard()->setMimeData( format.toMimeData() );
582  break;
583  }
584 
586  case QgsStyle::TagEntity:
588  return;
589 
590  }
591 }
592 
593 void QgsStyleManagerDialog::pasteItem()
594 {
595  const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data().toString() : QString();
596  std::unique_ptr< QgsSymbol > tempSymbol( QgsSymbolLayerUtils::symbolFromMimeData( QApplication::clipboard()->mimeData() ) );
597  if ( tempSymbol )
598  {
599  QgsStyleSaveDialog saveDlg( this );
600  saveDlg.setWindowTitle( tr( "Paste Symbol" ) );
601  saveDlg.setDefaultTags( defaultTag );
602  if ( !saveDlg.exec() || saveDlg.name().isEmpty() )
603  return;
604 
605  if ( mStyle->symbolNames().contains( saveDlg.name() ) )
606  {
607  int res = QMessageBox::warning( this, tr( "Paste Symbol" ),
608  tr( "A symbol with the name '%1' already exists. Overwrite?" )
609  .arg( saveDlg.name() ),
610  QMessageBox::Yes | QMessageBox::No );
611  if ( res != QMessageBox::Yes )
612  {
613  return;
614  }
615  mStyle->removeSymbol( saveDlg.name() );
616  }
617 
618  QStringList symbolTags = saveDlg.tags().split( ',' );
619  mStyle->addSymbol( saveDlg.name(), tempSymbol->clone() );
620  // make sure the symbol is stored
621  mStyle->saveSymbol( saveDlg.name(), tempSymbol->clone(), saveDlg.isFavorite(), symbolTags );
622  return;
623  }
624 
625  bool ok = false;
626  const QgsTextFormat format = QgsTextFormat::fromMimeData( QApplication::clipboard()->mimeData(), &ok );
627  if ( ok )
628  {
629  QgsStyleSaveDialog saveDlg( this );
630  saveDlg.setDefaultTags( defaultTag );
631  saveDlg.setWindowTitle( tr( "Paste Text Format" ) );
632  if ( !saveDlg.exec() || saveDlg.name().isEmpty() )
633  return;
634 
635  if ( mStyle->textFormatNames().contains( saveDlg.name() ) )
636  {
637  int res = QMessageBox::warning( this, tr( "Paste Text Format" ),
638  tr( "A format with the name '%1' already exists. Overwrite?" )
639  .arg( saveDlg.name() ),
640  QMessageBox::Yes | QMessageBox::No );
641  if ( res != QMessageBox::Yes )
642  {
643  return;
644  }
645  mStyle->removeTextFormat( saveDlg.name() );
646  }
647 
648  QStringList symbolTags = saveDlg.tags().split( ',' );
649  mStyle->addTextFormat( saveDlg.name(), format );
650  // make sure the foprmatis stored
651  mStyle->saveTextFormat( saveDlg.name(), format, saveDlg.isFavorite(), symbolTags );
652  return;
653  }
654 }
655 
656 int QgsStyleManagerDialog::selectedItemType()
657 {
658  QModelIndex index = listItems->selectionModel()->currentIndex();
659  if ( !index.isValid() )
660  return 0;
661 
662  const QgsStyle::StyleEntity entity = static_cast< QgsStyle::StyleEntity >( mModel->data( index, QgsStyleModel::TypeRole ).toInt() );
663  if ( entity == QgsStyle::ColorrampEntity )
664  return 3;
665  else if ( entity == QgsStyle::TextFormatEntity )
666  return 4;
667  else if ( entity == QgsStyle::LabelSettingsEntity )
668  return 5;
669 
670  return mModel->data( index, QgsStyleModel::SymbolTypeRole ).toInt();
671 }
672 
673 bool QgsStyleManagerDialog::allTypesSelected() const
674 {
675  return tabItemType->currentIndex() == 0;
676 }
677 
678 QList< QgsStyleManagerDialog::ItemDetails > QgsStyleManagerDialog::selectedItems()
679 {
680  QList<QgsStyleManagerDialog::ItemDetails > res;
681  QModelIndexList indices = listItems->selectionModel()->selectedRows();
682  for ( const QModelIndex &index : indices )
683  {
684  if ( !index.isValid() )
685  continue;
686 
687  ItemDetails details;
688  details.entityType = static_cast< QgsStyle::StyleEntity >( mModel->data( index, QgsStyleModel::TypeRole ).toInt() );
689  if ( details.entityType == QgsStyle::SymbolEntity )
690  details.symbolType = static_cast< QgsSymbol::SymbolType >( mModel->data( index, QgsStyleModel::SymbolTypeRole ).toInt() );
691  details.name = mModel->data( mModel->index( index.row(), QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
692 
693  res << details;
694  }
695  return res;
696 }
697 
698 int QgsStyleManagerDialog::copyItems( const QList<QgsStyleManagerDialog::ItemDetails> &items, QgsStyle *src, QgsStyle *dst, QWidget *parentWidget,
699  std::unique_ptr< QgsTemporaryCursorOverride > &cursorOverride, bool isImport, const QStringList &importTags, bool addToFavorites, bool ignoreSourceTags )
700 {
701  bool prompt = true;
702  bool overwriteAll = true;
703  int count = 0;
704 
705  const QStringList favoriteSymbols = src->symbolsOfFavorite( QgsStyle::SymbolEntity );
706  const QStringList favoriteColorramps = src->symbolsOfFavorite( QgsStyle::ColorrampEntity );
707  const QStringList favoriteTextFormats = src->symbolsOfFavorite( QgsStyle::TextFormatEntity );
708  const QStringList favoriteLabelSettings = src->symbolsOfFavorite( QgsStyle::LabelSettingsEntity );
709 
710  for ( auto &details : items )
711  {
712  QStringList symbolTags;
713  if ( !ignoreSourceTags )
714  {
715  symbolTags = src->tagsOfSymbol( details.entityType, details.name );
716  }
717 
718  bool addItemToFavorites = false;
719  if ( isImport )
720  {
721  symbolTags << importTags;
722  addItemToFavorites = addToFavorites;
723  }
724 
725  switch ( details.entityType )
726  {
728  {
729  std::unique_ptr< QgsSymbol > symbol( src->symbol( details.name ) );
730  if ( !symbol )
731  continue;
732 
733  const bool hasDuplicateName = dst->symbolNames().contains( details.name );
734  bool overwriteThis = false;
735  if ( isImport )
736  addItemToFavorites = favoriteSymbols.contains( details.name );
737 
738  if ( hasDuplicateName && prompt )
739  {
740  cursorOverride.reset();
741  int res = QMessageBox::warning( parentWidget, isImport ? tr( "Import Symbol" ) : tr( "Export Symbol" ),
742  tr( "A symbol with the name “%1” already exists.\nOverwrite?" )
743  .arg( details.name ),
744  QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
745  cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
746  switch ( res )
747  {
748  case QMessageBox::Cancel:
749  return count;
750 
751  case QMessageBox::No:
752  continue;
753 
754  case QMessageBox::Yes:
755  overwriteThis = true;
756  break;
757 
758  case QMessageBox::YesToAll:
759  prompt = false;
760  overwriteAll = true;
761  break;
762 
763  case QMessageBox::NoToAll:
764  prompt = false;
765  overwriteAll = false;
766  break;
767  }
768  }
769 
770  if ( !hasDuplicateName || overwriteAll || overwriteThis )
771  {
772  QgsSymbol *newSymbol = symbol.get();
773  dst->addSymbol( details.name, symbol.release() );
774  dst->saveSymbol( details.name, newSymbol, addItemToFavorites, symbolTags );
775  count++;
776  }
777  break;
778  }
779 
781  {
782  std::unique_ptr< QgsColorRamp > ramp( src->colorRamp( details.name ) );
783  if ( !ramp )
784  continue;
785 
786  const bool hasDuplicateName = dst->colorRampNames().contains( details.name );
787  bool overwriteThis = false;
788  if ( isImport )
789  addItemToFavorites = favoriteColorramps.contains( details.name );
790 
791  if ( hasDuplicateName && prompt )
792  {
793  cursorOverride.reset();
794  int res = QMessageBox::warning( parentWidget, isImport ? tr( "Import Color Ramp" ) : tr( "Export Color Ramp" ),
795  tr( "A color ramp with the name “%1” already exists.\nOverwrite?" )
796  .arg( details.name ),
797  QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
798  cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
799  switch ( res )
800  {
801  case QMessageBox::Cancel:
802  return count;
803 
804  case QMessageBox::No:
805  continue;
806 
807  case QMessageBox::Yes:
808  overwriteThis = true;
809  break;
810 
811  case QMessageBox::YesToAll:
812  prompt = false;
813  overwriteAll = true;
814  break;
815 
816  case QMessageBox::NoToAll:
817  prompt = false;
818  overwriteAll = false;
819  break;
820  }
821  }
822 
823  if ( !hasDuplicateName || overwriteAll || overwriteThis )
824  {
825  QgsColorRamp *newRamp = ramp.get();
826  dst->addColorRamp( details.name, ramp.release() );
827  dst->saveColorRamp( details.name, newRamp, addItemToFavorites, symbolTags );
828  count++;
829  }
830  break;
831  }
832 
834  {
835  const QgsTextFormat format( src->textFormat( details.name ) );
836 
837  const bool hasDuplicateName = dst->textFormatNames().contains( details.name );
838  bool overwriteThis = false;
839  if ( isImport )
840  addItemToFavorites = favoriteTextFormats.contains( details.name );
841 
842  if ( hasDuplicateName && prompt )
843  {
844  cursorOverride.reset();
845  int res = QMessageBox::warning( parentWidget, isImport ? tr( "Import Text Format" ) : tr( "Export Text Format" ),
846  tr( "A text format with the name “%1” already exists.\nOverwrite?" )
847  .arg( details.name ),
848  QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
849  cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
850  switch ( res )
851  {
852  case QMessageBox::Cancel:
853  return count;
854 
855  case QMessageBox::No:
856  continue;
857 
858  case QMessageBox::Yes:
859  overwriteThis = true;
860  break;
861 
862  case QMessageBox::YesToAll:
863  prompt = false;
864  overwriteAll = true;
865  break;
866 
867  case QMessageBox::NoToAll:
868  prompt = false;
869  overwriteAll = false;
870  break;
871  }
872  }
873 
874  if ( !hasDuplicateName || overwriteAll || overwriteThis )
875  {
876  dst->addTextFormat( details.name, format );
877  dst->saveTextFormat( details.name, format, addItemToFavorites, symbolTags );
878  count++;
879  }
880  break;
881  }
882 
884  {
885  const QgsPalLayerSettings settings( src->labelSettings( details.name ) );
886 
887  const bool hasDuplicateName = dst->labelSettingsNames().contains( details.name );
888  bool overwriteThis = false;
889  if ( isImport )
890  addItemToFavorites = favoriteLabelSettings.contains( details.name );
891 
892  if ( hasDuplicateName && prompt )
893  {
894  cursorOverride.reset();
895  int res = QMessageBox::warning( parentWidget, isImport ? tr( "Import Label Settings" ) : tr( "Export Label Settings" ),
896  tr( "Label settings with the name “%1” already exist.\nOverwrite?" )
897  .arg( details.name ),
898  QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
899  cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
900  switch ( res )
901  {
902  case QMessageBox::Cancel:
903  return count;
904 
905  case QMessageBox::No:
906  continue;
907 
908  case QMessageBox::Yes:
909  overwriteThis = true;
910  break;
911 
912  case QMessageBox::YesToAll:
913  prompt = false;
914  overwriteAll = true;
915  break;
916 
917  case QMessageBox::NoToAll:
918  prompt = false;
919  overwriteAll = false;
920  break;
921  }
922  }
923 
924  if ( !hasDuplicateName || overwriteAll || overwriteThis )
925  {
926  dst->addLabelSettings( details.name, settings );
927  dst->saveLabelSettings( details.name, settings, addItemToFavorites, symbolTags );
928  count++;
929  }
930  break;
931  }
932 
933  case QgsStyle::TagEntity:
935  break;
936 
937  }
938  }
939  return count;
940 }
941 
942 bool QgsStyleManagerDialog::addTextFormat()
943 {
944  QgsTextFormat format;
945  QgsTextFormatDialog formatDlg( format, nullptr, this );
946  if ( !formatDlg.exec() )
947  return false;
948  format = formatDlg.format();
949 
950  QgsStyleSaveDialog saveDlg( this );
951  if ( !saveDlg.exec() )
952  return false;
953  QString name = saveDlg.name();
954 
955  // request valid/unique name
956  bool nameInvalid = true;
957  while ( nameInvalid )
958  {
959  // validate name
960  if ( name.isEmpty() )
961  {
962  QMessageBox::warning( this, tr( "Save Text Format" ),
963  tr( "Cannot save text format without name. Enter a name." ) );
964  }
965  else if ( mStyle->textFormatNames().contains( name ) )
966  {
967  int res = QMessageBox::warning( this, tr( "Save Text Format" ),
968  tr( "Text format with name '%1' already exists. Overwrite?" )
969  .arg( name ),
970  QMessageBox::Yes | QMessageBox::No );
971  if ( res == QMessageBox::Yes )
972  {
973  mStyle->removeTextFormat( name );
974  nameInvalid = false;
975  }
976  }
977  else
978  {
979  // valid name
980  nameInvalid = false;
981  }
982  if ( nameInvalid )
983  {
984  bool ok;
985  name = QInputDialog::getText( this, tr( "Text Format Name" ),
986  tr( "Please enter a name for new text format:" ),
987  QLineEdit::Normal, name, &ok );
988  if ( !ok )
989  {
990  return false;
991  }
992  }
993  }
994 
995  QStringList symbolTags = saveDlg.tags().split( ',' );
996 
997  // add new format to style and re-populate the list
998  mStyle->addTextFormat( name, format );
999  mStyle->saveTextFormat( name, format, saveDlg.isFavorite(), symbolTags );
1000 
1001  mModified = true;
1002  return true;
1003 }
1004 
1006 {
1007  groupChanged( groupTree->selectionModel()->currentIndex() );
1008 }
1009 
1010 void QgsStyleManagerDialog::populateSymbols( const QStringList &, bool )
1011 {
1012 }
1013 
1014 void QgsStyleManagerDialog::populateColorRamps( const QStringList &, bool )
1015 {
1016 }
1017 
1019 {
1020  switch ( tabItemType->currentIndex() )
1021  {
1022  case 1:
1023  return QgsSymbol::Marker;
1024  case 2:
1025  return QgsSymbol::Line;
1026  case 3:
1027  return QgsSymbol::Fill;
1028  case 4:
1029  return 3;
1030  case 5:
1031  return 4;
1032  case 6:
1033  return 5;
1034  default:
1035  return 0;
1036  }
1037 }
1038 
1040 {
1041  QModelIndex index = listItems->selectionModel()->currentIndex();
1042  if ( !index.isValid() )
1043  return QString();
1044 
1045  return mModel->data( mModel->index( index.row(), QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
1046 }
1047 
1049 {
1050  bool changed = false;
1051  if ( currentItemType() < 3 )
1052  {
1053  changed = addSymbol();
1054  }
1055  else if ( currentItemType() == 3 )
1056  {
1057  changed = addColorRamp();
1058  }
1059  else if ( currentItemType() == 4 )
1060  {
1061  changed = addTextFormat();
1062  }
1063  else if ( currentItemType() == 5 )
1064  {
1065  // changed = addLabelSettings();
1066  }
1067  else
1068  {
1069  Q_ASSERT( false && "not implemented" );
1070  }
1071 
1072  if ( changed )
1073  {
1074  populateList();
1075  }
1076 }
1077 
1078 bool QgsStyleManagerDialog::addSymbol( int symbolType )
1079 {
1080  // create new symbol with current type
1081  QgsSymbol *symbol = nullptr;
1082  QString name = tr( "new symbol" );
1083  switch ( symbolType == -1 ? currentItemType() : symbolType )
1084  {
1085  case QgsSymbol::Marker:
1086  symbol = new QgsMarkerSymbol();
1087  name = tr( "new marker" );
1088  break;
1089  case QgsSymbol::Line:
1090  symbol = new QgsLineSymbol();
1091  name = tr( "new line" );
1092  break;
1093  case QgsSymbol::Fill:
1094  symbol = new QgsFillSymbol();
1095  name = tr( "new fill symbol" );
1096  break;
1097  default:
1098  Q_ASSERT( false && "unknown symbol type" );
1099  return false;
1100  }
1101 
1102  // get symbol design
1103  // NOTE : Set the parent widget as "this" to notify the Symbol selector
1104  // that, it is being called by Style Manager, so recursive calling
1105  // of style manager and symbol selector can be arrested
1106  // See also: editSymbol()
1107  QgsSymbolSelectorDialog dlg( symbol, mStyle, nullptr, this );
1108  if ( dlg.exec() == 0 )
1109  {
1110  delete symbol;
1111  return false;
1112  }
1113 
1114  QgsStyleSaveDialog saveDlg( this );
1115  if ( !saveDlg.exec() )
1116  {
1117  delete symbol;
1118  return false;
1119  }
1120 
1121  name = saveDlg.name();
1122 
1123  // request valid/unique name
1124  bool nameInvalid = true;
1125  while ( nameInvalid )
1126  {
1127  // validate name
1128  if ( name.isEmpty() )
1129  {
1130  QMessageBox::warning( this, tr( "Save Symbol" ),
1131  tr( "Cannot save symbol without name. Enter a name." ) );
1132  }
1133  else if ( mStyle->symbolNames().contains( name ) )
1134  {
1135  int res = QMessageBox::warning( this, tr( "Save Symbol" ),
1136  tr( "Symbol with name '%1' already exists. Overwrite?" )
1137  .arg( name ),
1138  QMessageBox::Yes | QMessageBox::No );
1139  if ( res == QMessageBox::Yes )
1140  {
1141  mStyle->removeSymbol( name );
1142  nameInvalid = false;
1143  }
1144  }
1145  else
1146  {
1147  // valid name
1148  nameInvalid = false;
1149  }
1150  if ( nameInvalid )
1151  {
1152  bool ok;
1153  name = QInputDialog::getText( this, tr( "Symbol Name" ),
1154  tr( "Please enter a name for new symbol:" ),
1155  QLineEdit::Normal, name, &ok );
1156  if ( !ok )
1157  {
1158  delete symbol;
1159  return false;
1160  }
1161  }
1162  }
1163 
1164  QStringList symbolTags = saveDlg.tags().split( ',' );
1165 
1166  // add new symbol to style and re-populate the list
1167  mStyle->addSymbol( name, symbol );
1168  mStyle->saveSymbol( name, symbol, saveDlg.isFavorite(), symbolTags );
1169 
1170  mModified = true;
1171  return true;
1172 }
1173 
1174 
1175 QString QgsStyleManagerDialog::addColorRampStatic( QWidget *parent, QgsStyle *style, QString rampType )
1176 {
1177  // let the user choose the color ramp type if rampType is not given
1178  bool ok = true;
1179  if ( rampType.isEmpty() )
1180  {
1181  QStringList rampTypes;
1182  rampTypes << tr( "Gradient" ) << tr( "Color presets" ) << tr( "Random" ) << tr( "Catalog: cpt-city" );
1183  rampTypes << tr( "Catalog: ColorBrewer" );
1184  rampType = QInputDialog::getItem( parent, tr( "Color Ramp Type" ),
1185  tr( "Please select color ramp type:" ), rampTypes, 0, false, &ok );
1186  }
1187  if ( !ok || rampType.isEmpty() )
1188  return QString();
1189 
1190  QString name = tr( "new ramp" );
1191 
1192  std::unique_ptr< QgsColorRamp > ramp;
1193  if ( rampType == tr( "Gradient" ) )
1194  {
1196  if ( !dlg.exec() )
1197  {
1198  return QString();
1199  }
1200  ramp.reset( dlg.ramp().clone() );
1201  name = tr( "new gradient ramp" );
1202  }
1203  else if ( rampType == tr( "Random" ) )
1204  {
1206  if ( !dlg.exec() )
1207  {
1208  return QString();
1209  }
1210  ramp.reset( dlg.ramp().clone() );
1211  name = tr( "new random ramp" );
1212  }
1213  else if ( rampType == tr( "Catalog: ColorBrewer" ) )
1214  {
1216  if ( !dlg.exec() )
1217  {
1218  return QString();
1219  }
1220  ramp.reset( dlg.ramp().clone() );
1221  name = dlg.ramp().schemeName() + QString::number( dlg.ramp().colors() );
1222  }
1223  else if ( rampType == tr( "Color presets" ) )
1224  {
1226  if ( !dlg.exec() )
1227  {
1228  return QString();
1229  }
1230  ramp.reset( dlg.ramp().clone() );
1231  name = tr( "new preset ramp" );
1232  }
1233  else if ( rampType == tr( "Catalog: cpt-city" ) )
1234  {
1235  QgsCptCityColorRampDialog dlg( QgsCptCityColorRamp( QString(), QString() ), parent );
1236  if ( !dlg.exec() )
1237  {
1238  return QString();
1239  }
1240  // name = dlg.selectedName();
1241  name = QFileInfo( dlg.ramp().schemeName() ).baseName() + dlg.ramp().variantName();
1242  if ( dlg.saveAsGradientRamp() )
1243  {
1244  ramp.reset( dlg.ramp().cloneGradientRamp() );
1245  }
1246  else
1247  {
1248  ramp.reset( dlg.ramp().clone() );
1249  }
1250  }
1251  else
1252  {
1253  // Q_ASSERT( 0 && "invalid ramp type" );
1254  // bailing out is rather harsh!
1255  QgsDebugMsg( QStringLiteral( "invalid ramp type %1" ).arg( rampType ) );
1256  return QString();
1257  }
1258 
1259  QgsStyleSaveDialog saveDlg( parent, QgsStyle::ColorrampEntity );
1260  if ( !saveDlg.exec() )
1261  {
1262  return QString();
1263  }
1264 
1265  name = saveDlg.name();
1266 
1267  // get valid/unique name
1268  bool nameInvalid = true;
1269  while ( nameInvalid )
1270  {
1271  // validate name
1272  if ( name.isEmpty() )
1273  {
1274  QMessageBox::warning( parent, tr( "Save Color Ramp" ),
1275  tr( "Cannot save color ramp without name. Enter a name." ) );
1276  }
1277  else if ( style->colorRampNames().contains( name ) )
1278  {
1279  int res = QMessageBox::warning( parent, tr( "Save Color Ramp" ),
1280  tr( "Color ramp with name '%1' already exists. Overwrite?" )
1281  .arg( name ),
1282  QMessageBox::Yes | QMessageBox::No );
1283  if ( res == QMessageBox::Yes )
1284  {
1285  nameInvalid = false;
1286  }
1287  }
1288  else
1289  {
1290  // valid name
1291  nameInvalid = false;
1292  }
1293  if ( nameInvalid )
1294  {
1295  bool ok;
1296  name = QInputDialog::getText( parent, tr( "Color Ramp Name" ),
1297  tr( "Please enter a name for new color ramp:" ),
1298  QLineEdit::Normal, name, &ok );
1299  if ( !ok )
1300  {
1301  return QString();
1302  }
1303  }
1304  }
1305 
1306  QStringList colorRampTags = saveDlg.tags().split( ',' );
1307  QgsColorRamp *r = ramp.release();
1308 
1309  // add new symbol to style and re-populate the list
1310  style->addColorRamp( name, r );
1311  style->saveColorRamp( name, r, saveDlg.isFavorite(), colorRampTags );
1312 
1313  return name;
1314 }
1315 
1317 {
1318  mFavoritesGroupVisible = show;
1319  populateGroups();
1320 }
1321 
1323 {
1324  mSmartGroupVisible = show;
1325  populateGroups();
1326 }
1327 
1328 void QgsStyleManagerDialog::setBaseStyleName( const QString &name )
1329 {
1330  mBaseName = name;
1331 }
1332 
1334 {
1335  raise();
1336  setWindowState( windowState() & ~Qt::WindowMinimized );
1337  activateWindow();
1338 }
1339 
1341 {
1342  return addColorRamp( nullptr );
1343 }
1344 
1346 {
1347  // pass the action text, which is the color ramp type
1348  QString rampName = addColorRampStatic( this, mStyle,
1349  action ? action->text() : QString() );
1350  if ( !rampName.isEmpty() )
1351  {
1352  mModified = true;
1353  populateList();
1354  return true;
1355  }
1356 
1357  return false;
1358 }
1359 
1361 {
1362  if ( selectedItemType() < 3 )
1363  {
1364  editSymbol();
1365  }
1366  else if ( selectedItemType() == 3 )
1367  {
1368  editColorRamp();
1369  }
1370  else if ( selectedItemType() == 4 )
1371  {
1372  editTextFormat();
1373  }
1374  else if ( selectedItemType() == 5 )
1375  {
1376  editLabelSettings();
1377  }
1378  else
1379  {
1380  Q_ASSERT( false && "not implemented" );
1381  }
1382 }
1383 
1385 {
1386  QString symbolName = currentItemName();
1387  if ( symbolName.isEmpty() )
1388  return false;
1389 
1390  std::unique_ptr< QgsSymbol > symbol( mStyle->symbol( symbolName ) );
1391 
1392  // let the user edit the symbol and update list when done
1393  QgsSymbolSelectorDialog dlg( symbol.get(), mStyle, nullptr, this );
1394  if ( mReadOnly )
1395  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1396 
1397  if ( !dlg.exec() )
1398  return false;
1399 
1400  // by adding symbol to style with the same name the old effectively gets overwritten
1401  mStyle->addSymbol( symbolName, symbol.release(), true );
1402  mModified = true;
1403  return true;
1404 }
1405 
1407 {
1408  QString name = currentItemName();
1409  if ( name.isEmpty() )
1410  return false;
1411 
1412  std::unique_ptr< QgsColorRamp > ramp( mStyle->colorRamp( name ) );
1413 
1414  if ( ramp->type() == QLatin1String( "gradient" ) )
1415  {
1416  QgsGradientColorRamp *gradRamp = static_cast<QgsGradientColorRamp *>( ramp.get() );
1417  QgsGradientColorRampDialog dlg( *gradRamp, this );
1418  if ( mReadOnly )
1419  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1420 
1421  if ( !dlg.exec() )
1422  {
1423  return false;
1424  }
1425  ramp.reset( dlg.ramp().clone() );
1426  }
1427  else if ( ramp->type() == QLatin1String( "random" ) )
1428  {
1429  QgsLimitedRandomColorRamp *randRamp = static_cast<QgsLimitedRandomColorRamp *>( ramp.get() );
1430  QgsLimitedRandomColorRampDialog dlg( *randRamp, this );
1431  if ( mReadOnly )
1432  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1433 
1434  if ( !dlg.exec() )
1435  {
1436  return false;
1437  }
1438  ramp.reset( dlg.ramp().clone() );
1439  }
1440  else if ( ramp->type() == QLatin1String( "colorbrewer" ) )
1441  {
1442  QgsColorBrewerColorRamp *brewerRamp = static_cast<QgsColorBrewerColorRamp *>( ramp.get() );
1443  QgsColorBrewerColorRampDialog dlg( *brewerRamp, this );
1444  if ( mReadOnly )
1445  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1446 
1447  if ( !dlg.exec() )
1448  {
1449  return false;
1450  }
1451  ramp.reset( dlg.ramp().clone() );
1452  }
1453  else if ( ramp->type() == QLatin1String( "preset" ) )
1454  {
1455  QgsPresetSchemeColorRamp *presetRamp = static_cast<QgsPresetSchemeColorRamp *>( ramp.get() );
1456  QgsPresetColorRampDialog dlg( *presetRamp, this );
1457  if ( mReadOnly )
1458  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1459 
1460  if ( !dlg.exec() )
1461  {
1462  return false;
1463  }
1464  ramp.reset( dlg.ramp().clone() );
1465  }
1466  else if ( ramp->type() == QLatin1String( "cpt-city" ) )
1467  {
1468  QgsCptCityColorRamp *cptCityRamp = static_cast<QgsCptCityColorRamp *>( ramp.get() );
1469  QgsCptCityColorRampDialog dlg( *cptCityRamp, this );
1470  if ( mReadOnly )
1471  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1472 
1473  if ( !dlg.exec() )
1474  {
1475  return false;
1476  }
1477  if ( dlg.saveAsGradientRamp() )
1478  {
1479  ramp.reset( dlg.ramp().cloneGradientRamp() );
1480  }
1481  else
1482  {
1483  ramp.reset( dlg.ramp().clone() );
1484  }
1485  }
1486  else
1487  {
1488  Q_ASSERT( false && "invalid ramp type" );
1489  }
1490 
1491  mStyle->addColorRamp( name, ramp.release(), true );
1492  mModified = true;
1493  return true;
1494 }
1495 
1496 bool QgsStyleManagerDialog::editTextFormat()
1497 {
1498  const QString formatName = currentItemName();
1499  if ( formatName.isEmpty() )
1500  return false;
1501 
1502  QgsTextFormat format = mStyle->textFormat( formatName );
1503 
1504  // let the user edit the format and update list when done
1505  QgsTextFormatDialog dlg( format, nullptr, this );
1506  if ( mReadOnly )
1507  dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1508 
1509  if ( !dlg.exec() )
1510  return false;
1511 
1512  // by adding format to style with the same name the old effectively gets overwritten
1513  mStyle->addTextFormat( formatName, dlg.format(), true );
1514  mModified = true;
1515  return true;
1516 }
1517 
1518 bool QgsStyleManagerDialog::addLabelSettings( QgsWkbTypes::GeometryType type )
1519 {
1520  QgsPalLayerSettings settings;
1521  QgsLabelSettingsDialog settingsDlg( settings, nullptr, nullptr, this, type );
1522  if ( mReadOnly )
1523  settingsDlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
1524 
1525  if ( !settingsDlg.exec() )
1526  return false;
1527 
1528  settings = settingsDlg.settings();
1529  settings.layerType = type;
1530 
1531  QgsStyleSaveDialog saveDlg( this );
1532  if ( !saveDlg.exec() )
1533  return false;
1534  QString name = saveDlg.name();
1535 
1536  // request valid/unique name
1537  bool nameInvalid = true;
1538  while ( nameInvalid )
1539  {
1540  // validate name
1541  if ( name.isEmpty() )
1542  {
1543  QMessageBox::warning( this, tr( "Save Label Settings" ),
1544  tr( "Cannot save label settings without a name. Enter a name." ) );
1545  }
1546  else if ( mStyle->labelSettingsNames().contains( name ) )
1547  {
1548  int res = QMessageBox::warning( this, tr( "Save Label Settings" ),
1549  tr( "Label settings with the name '%1' already exist. Overwrite?" )
1550  .arg( name ),
1551  QMessageBox::Yes | QMessageBox::No );
1552  if ( res == QMessageBox::Yes )
1553  {
1554  mStyle->removeLabelSettings( name );
1555  nameInvalid = false;
1556  }
1557  }
1558  else
1559  {
1560  // valid name
1561  nameInvalid = false;
1562  }
1563  if ( nameInvalid )
1564  {
1565  bool ok;
1566  name = QInputDialog::getText( this, tr( "Label Settings Name" ),
1567  tr( "Please enter a name for the new label settings:" ),
1568  QLineEdit::Normal, name, &ok );
1569  if ( !ok )
1570  {
1571  return false;
1572  }
1573  }
1574  }
1575 
1576  QStringList symbolTags = saveDlg.tags().split( ',' );
1577 
1578  // add new format to style and re-populate the list
1579  mStyle->addLabelSettings( name, settings );
1580  mStyle->saveLabelSettings( name, settings, saveDlg.isFavorite(), symbolTags );
1581 
1582  mModified = true;
1583  return true;
1584 }
1585 
1586 bool QgsStyleManagerDialog::editLabelSettings()
1587 {
1588  const QString formatName = currentItemName();
1589  if ( formatName.isEmpty() )
1590  return false;
1591 
1592  QgsPalLayerSettings settings = mStyle->labelSettings( formatName );
1593  QgsWkbTypes::GeometryType geomType = settings.layerType;
1594 
1595  // let the user edit the settings and update list when done
1596  QgsLabelSettingsDialog dlg( settings, nullptr, nullptr, this, geomType );
1597  if ( !dlg.exec() )
1598  return false;
1599 
1600  settings = dlg.settings();
1601  settings.layerType = geomType;
1602 
1603  // by adding format to style with the same name the old effectively gets overwritten
1604  mStyle->addLabelSettings( formatName, settings, true );
1605  mModified = true;
1606  return true;
1607 }
1608 
1609 
1611 {
1612  const QList< ItemDetails > items = selectedItems();
1613 
1614  if ( allTypesSelected() )
1615  {
1616  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Items" ),
1617  QString( tr( "Do you really want to remove %n item(s)?", nullptr, items.count() ) ),
1618  QMessageBox::Yes,
1619  QMessageBox::No ) )
1620  return;
1621  }
1622  else
1623  {
1624  if ( currentItemType() < 3 )
1625  {
1626  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Symbol" ),
1627  QString( tr( "Do you really want to remove %n symbol(s)?", nullptr, items.count() ) ),
1628  QMessageBox::Yes,
1629  QMessageBox::No ) )
1630  return;
1631  }
1632  else if ( currentItemType() == 3 )
1633  {
1634  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Color Ramp" ),
1635  QString( tr( "Do you really want to remove %n ramp(s)?", nullptr, items.count() ) ),
1636  QMessageBox::Yes,
1637  QMessageBox::No ) )
1638  return;
1639  }
1640  else if ( currentItemType() == 4 )
1641  {
1642  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Text Formats" ),
1643  QString( tr( "Do you really want to remove %n text format(s)?", nullptr, items.count() ) ),
1644  QMessageBox::Yes,
1645  QMessageBox::No ) )
1646  return;
1647  }
1648  else if ( currentItemType() == 5 )
1649  {
1650  if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove Label Settings" ),
1651  QString( tr( "Do you really want to remove %n label settings?", nullptr, items.count() ) ),
1652  QMessageBox::Yes,
1653  QMessageBox::No ) )
1654  return;
1655  }
1656  }
1657 
1658  QgsTemporaryCursorOverride override( Qt::WaitCursor );
1659 
1660  for ( const ItemDetails &details : items )
1661  {
1662  if ( details.name.isEmpty() )
1663  continue;
1664 
1665  switch ( details.entityType )
1666  {
1668  mStyle->removeSymbol( details.name );
1669  break;
1670 
1672  mStyle->removeColorRamp( details.name );
1673  break;
1674 
1676  mStyle->removeTextFormat( details.name );
1677  break;
1678 
1680  mStyle->removeLabelSettings( details.name );
1681  break;
1682 
1683  case QgsStyle::TagEntity:
1685  continue;
1686  }
1687  }
1688 
1689  mModified = true;
1690 }
1691 
1693 {
1694  return false;
1695 }
1696 
1698 {
1699  return false;
1700 }
1701 
1702 void QgsStyleManagerDialog::itemChanged( QStandardItem * )
1703 {
1704 }
1705 
1707 {
1708  QString dir = QFileDialog::getExistingDirectory( this, tr( "Export Selected Symbols as PNG" ),
1709  QDir::home().absolutePath(),
1710  QFileDialog::ShowDirsOnly
1711  | QFileDialog::DontResolveSymlinks );
1712  exportSelectedItemsImages( dir, QStringLiteral( "png" ), QSize( 32, 32 ) );
1713 }
1714 
1716 {
1717  QString dir = QFileDialog::getExistingDirectory( this, tr( "Export Selected Symbols as SVG" ),
1718  QDir::home().absolutePath(),
1719  QFileDialog::ShowDirsOnly
1720  | QFileDialog::DontResolveSymlinks );
1721  exportSelectedItemsImages( dir, QStringLiteral( "svg" ), QSize( 32, 32 ) );
1722 }
1723 
1724 
1725 void QgsStyleManagerDialog::exportSelectedItemsImages( const QString &dir, const QString &format, QSize size )
1726 {
1727  if ( dir.isEmpty() )
1728  return;
1729 
1730  const QList< ItemDetails > items = selectedItems();
1731  for ( const ItemDetails &details : items )
1732  {
1733  if ( details.entityType != QgsStyle::SymbolEntity )
1734  continue;
1735 
1736  QString path = dir + '/' + details.name + '.' + format;
1737  std::unique_ptr< QgsSymbol > sym( mStyle->symbol( details.name ) );
1738  if ( sym )
1739  sym->exportImage( path, format, size );
1740  }
1741 }
1742 
1744 {
1746  dlg.exec();
1747 }
1748 
1750 {
1752  dlg.exec();
1753  populateList();
1754  populateGroups();
1755 }
1756 
1757 void QgsStyleManagerDialog::setBold( QStandardItem *item )
1758 {
1759  QFont font = item->font();
1760  font.setBold( true );
1761  item->setFont( font );
1762 }
1763 
1765 {
1766  if ( mBlockGroupUpdates )
1767  return;
1768 
1769  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1770  model->clear();
1771 
1772  if ( mFavoritesGroupVisible )
1773  {
1774  QStandardItem *favoriteSymbols = new QStandardItem( tr( "Favorites" ) );
1775  favoriteSymbols->setData( "favorite" );
1776  favoriteSymbols->setEditable( false );
1777  setBold( favoriteSymbols );
1778  model->appendRow( favoriteSymbols );
1779  }
1780 
1781  QStandardItem *allSymbols = new QStandardItem( tr( "All" ) );
1782  allSymbols->setData( "all" );
1783  allSymbols->setEditable( false );
1784  setBold( allSymbols );
1785  model->appendRow( allSymbols );
1786 
1787  QStandardItem *taggroup = new QStandardItem( QString() ); //require empty name to get first order groups
1788  taggroup->setData( "tags" );
1789  taggroup->setEditable( false );
1790  QStringList tags = mStyle->tags();
1791  tags.sort();
1792  for ( const QString &tag : qgis::as_const( tags ) )
1793  {
1794  QStandardItem *item = new QStandardItem( tag );
1795  item->setData( mStyle->tagId( tag ) );
1796  item->setEditable( !mReadOnly );
1797  taggroup->appendRow( item );
1798  }
1799  taggroup->setText( tr( "Tags" ) );//set title later
1800  setBold( taggroup );
1801  model->appendRow( taggroup );
1802 
1803  if ( mSmartGroupVisible )
1804  {
1805  QStandardItem *smart = new QStandardItem( tr( "Smart Groups" ) );
1806  smart->setData( "smartgroups" );
1807  smart->setEditable( false );
1808  setBold( smart );
1809  QgsSymbolGroupMap sgMap = mStyle->smartgroupsListMap();
1810  QgsSymbolGroupMap::const_iterator i = sgMap.constBegin();
1811  while ( i != sgMap.constEnd() )
1812  {
1813  QStandardItem *item = new QStandardItem( i.value() );
1814  item->setData( i.key() );
1815  item->setEditable( !mReadOnly );
1816  smart->appendRow( item );
1817  ++i;
1818  }
1819  model->appendRow( smart );
1820  }
1821 
1822  // expand things in the group tree
1823  int rows = model->rowCount( model->indexFromItem( model->invisibleRootItem() ) );
1824  for ( int i = 0; i < rows; i++ )
1825  {
1826  groupTree->setExpanded( model->indexFromItem( model->item( i ) ), true );
1827  }
1828 }
1829 
1830 void QgsStyleManagerDialog::groupChanged( const QModelIndex &index )
1831 {
1832  QStringList groupSymbols;
1833 
1834  const QString category = index.data( Qt::UserRole + 1 ).toString();
1835  if ( mGroupingMode )
1836  {
1837  mModel->setTagId( -1 );
1838  mModel->setSmartGroupId( -1 );
1839  mModel->setFavoritesOnly( false );
1840  mModel->setCheckTag( index.data( Qt::DisplayRole ).toString() );
1841  }
1842  else if ( category == QLatin1String( "all" ) || category == QLatin1String( "tags" ) || category == QLatin1String( "smartgroups" ) )
1843  {
1844  enableGroupInputs( false );
1845  if ( category == QLatin1String( "tags" ) )
1846  {
1847  actnAddTag->setEnabled( !mReadOnly );
1848  actnAddSmartgroup->setEnabled( false );
1849  }
1850  else if ( category == QLatin1String( "smartgroups" ) )
1851  {
1852  actnAddTag->setEnabled( false );
1853  actnAddSmartgroup->setEnabled( !mReadOnly );
1854  }
1855 
1856  mModel->setTagId( -1 );
1857  mModel->setSmartGroupId( -1 );
1858  mModel->setFavoritesOnly( false );
1859  }
1860  else if ( category == QLatin1String( "favorite" ) )
1861  {
1862  enableGroupInputs( false );
1863  mModel->setTagId( -1 );
1864  mModel->setSmartGroupId( -1 );
1865  mModel->setFavoritesOnly( true );
1866  }
1867  else if ( index.parent().data( Qt::UserRole + 1 ) == "smartgroups" )
1868  {
1869  actnRemoveGroup->setEnabled( !mReadOnly );
1870  btnManageGroups->setEnabled( !mReadOnly );
1871  const int groupId = index.data( Qt::UserRole + 1 ).toInt();
1872  mModel->setTagId( -1 );
1873  mModel->setSmartGroupId( groupId );
1874  mModel->setFavoritesOnly( false );
1875  }
1876  else // tags
1877  {
1878  enableGroupInputs( true );
1879  int tagId = index.data( Qt::UserRole + 1 ).toInt();
1880  mModel->setTagId( tagId );
1881  mModel->setSmartGroupId( -1 );
1882  mModel->setFavoritesOnly( false );
1883  }
1884 
1885  actnEditSmartGroup->setVisible( false );
1886  actnAddTag->setVisible( false );
1887  actnAddSmartgroup->setVisible( false );
1888  actnRemoveGroup->setVisible( false );
1889  actnTagSymbols->setVisible( false );
1890  actnFinishTagging->setVisible( false );
1891 
1892  if ( index.parent().isValid() )
1893  {
1894  if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "smartgroups" ) )
1895  {
1896  actnEditSmartGroup->setVisible( !mGroupingMode && !mReadOnly );
1897  }
1898  else if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "tags" ) )
1899  {
1900  actnAddTag->setVisible( !mGroupingMode && !mReadOnly );
1901  actnTagSymbols->setVisible( !mGroupingMode && !mReadOnly );
1902  actnFinishTagging->setVisible( mGroupingMode && !mReadOnly );
1903  }
1904  actnRemoveGroup->setVisible( !mReadOnly );
1905  }
1906  else if ( index.data( Qt::UserRole + 1 ) == "smartgroups" )
1907  {
1908  actnAddSmartgroup->setVisible( !mGroupingMode && !mReadOnly );
1909  }
1910  else if ( index.data( Qt::UserRole + 1 ) == "tags" )
1911  {
1912  actnAddTag->setVisible( !mGroupingMode && !mReadOnly );
1913  }
1914 }
1915 
1917 {
1918  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1919  QModelIndex index;
1920  for ( int i = 0; i < groupTree->model()->rowCount(); i++ )
1921  {
1922  index = groupTree->model()->index( i, 0 );
1923  QString data = index.data( Qt::UserRole + 1 ).toString();
1924  if ( data == QLatin1String( "tags" ) )
1925  {
1926  break;
1927  }
1928  }
1929 
1930  QString itemName;
1931  int id;
1932  bool ok;
1933  itemName = QInputDialog::getText( this, tr( "Add Tag" ),
1934  tr( "Please enter name for the new tag:" ), QLineEdit::Normal, tr( "New tag" ), &ok ).trimmed();
1935  if ( !ok || itemName.isEmpty() )
1936  return 0;
1937 
1938  int check = mStyle->tagId( itemName );
1939  if ( check > 0 )
1940  {
1941  mMessageBar->pushCritical( tr( "Add Tag" ), tr( "The tag “%1” already exists." ).arg( itemName ) );
1942  return 0;
1943  }
1944 
1945  // block the auto-repopulation of groups when the style emits groupsModified
1946  // instead, we manually update the model items for better state retention
1947  mBlockGroupUpdates++;
1948  id = mStyle->addTag( itemName );
1949  mBlockGroupUpdates--;
1950 
1951  if ( !id )
1952  {
1953  mMessageBar->pushCritical( tr( "Add Tag" ), tr( "New tag could not be created — There was a problem with the symbol database." ) );
1954  return 0;
1955  }
1956 
1957  QStandardItem *parentItem = model->itemFromIndex( index );
1958  QStandardItem *childItem = new QStandardItem( itemName );
1959  childItem->setData( id );
1960  parentItem->appendRow( childItem );
1961 
1962  return id;
1963 }
1964 
1966 {
1967  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
1968  QModelIndex index;
1969  for ( int i = 0; i < groupTree->model()->rowCount(); i++ )
1970  {
1971  index = groupTree->model()->index( i, 0 );
1972  QString data = index.data( Qt::UserRole + 1 ).toString();
1973  if ( data == QLatin1String( "smartgroups" ) )
1974  {
1975  break;
1976  }
1977  }
1978 
1979  QString itemName;
1980  int id;
1981  QgsSmartGroupEditorDialog dlg( mStyle, this );
1982  if ( dlg.exec() == QDialog::Rejected )
1983  return 0;
1984 
1985  // block the auto-repopulation of groups when the style emits groupsModified
1986  // instead, we manually update the model items for better state retention
1987  mBlockGroupUpdates++;
1988  id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() );
1989  mBlockGroupUpdates--;
1990 
1991  if ( !id )
1992  return 0;
1993  itemName = dlg.smartgroupName();
1994 
1995  QStandardItem *parentItem = model->itemFromIndex( index );
1996  QStandardItem *childItem = new QStandardItem( itemName );
1997  childItem->setData( id );
1998  parentItem->appendRow( childItem );
1999 
2000  return id;
2001 }
2002 
2004 {
2005  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
2006  QModelIndex index = groupTree->currentIndex();
2007 
2008  // do not allow removal of system-defined groupings
2009  QString data = index.data( Qt::UserRole + 1 ).toString();
2010  if ( data == QLatin1String( "all" ) || data == QLatin1String( "favorite" ) || data == QLatin1String( "tags" ) || index.data() == "smartgroups" )
2011  {
2012  // should never appear -- blocked by GUI
2013  int err = QMessageBox::critical( this, tr( "Remove Group" ),
2014  tr( "Invalid selection. Cannot delete system defined categories.\n"
2015  "Kindly select a group or smart group you might want to delete." ) );
2016  if ( err )
2017  return;
2018  }
2019 
2020  QStandardItem *parentItem = model->itemFromIndex( index.parent() );
2021 
2022  // block the auto-repopulation of groups when the style emits groupsModified
2023  // instead, we manually update the model items for better state retention
2024  mBlockGroupUpdates++;
2025 
2026  if ( parentItem->data( Qt::UserRole + 1 ).toString() == QLatin1String( "smartgroups" ) )
2027  {
2028  mStyle->remove( QgsStyle::SmartgroupEntity, index.data( Qt::UserRole + 1 ).toInt() );
2029  }
2030  else
2031  {
2032  mStyle->remove( QgsStyle::TagEntity, index.data( Qt::UserRole + 1 ).toInt() );
2033  }
2034 
2035  mBlockGroupUpdates--;
2036  parentItem->removeRow( index.row() );
2037 }
2038 
2039 void QgsStyleManagerDialog::groupRenamed( QStandardItem *item )
2040 {
2041  QgsDebugMsg( QStringLiteral( "Symbol group edited: data=%1 text=%2" ).arg( item->data( Qt::UserRole + 1 ).toString(), item->text() ) );
2042  int id = item->data( Qt::UserRole + 1 ).toInt();
2043  QString name = item->text();
2044  mBlockGroupUpdates++;
2045  if ( item->parent()->data( Qt::UserRole + 1 ) == "smartgroups" )
2046  {
2047  mStyle->rename( QgsStyle::SmartgroupEntity, id, name );
2048  }
2049  else
2050  {
2051  mStyle->rename( QgsStyle::TagEntity, id, name );
2052  }
2053  mBlockGroupUpdates--;
2054 }
2055 
2057 {
2058  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
2059 
2060  if ( mGroupingMode )
2061  {
2062  mGroupingMode = false;
2063  mModel->setCheckable( false );
2064  actnTagSymbols->setVisible( true );
2065  actnFinishTagging->setVisible( false );
2066  // disconnect slot which handles regrouping
2067 
2068  // disable all items except groups in groupTree
2070  groupChanged( groupTree->currentIndex() );
2071 
2072  // Finally: Reconnect all Symbol editing functionalities
2073  connect( treeModel, &QStandardItemModel::itemChanged,
2075 
2076  // Reset the selection mode
2077  listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
2078  mSymbolTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection );
2079  }
2080  else
2081  {
2082  bool validGroup = false;
2083  // determine whether it is a valid group
2084  QModelIndex present = groupTree->currentIndex();
2085  while ( present.parent().isValid() )
2086  {
2087  if ( present.parent().data() == "Tags" )
2088  {
2089  validGroup = true;
2090  break;
2091  }
2092  present = present.parent();
2093  }
2094  if ( !validGroup )
2095  return;
2096 
2097  mGroupingMode = true;
2098  // Change visibility of actions
2099  actnTagSymbols->setVisible( false );
2100  actnFinishTagging->setVisible( true );
2101  // Remove all Symbol editing functionalities
2102  disconnect( treeModel, &QStandardItemModel::itemChanged,
2104 
2105  // disable all items except groups in groupTree
2106  enableItemsForGroupingMode( false );
2107  groupChanged( groupTree->currentIndex() );
2108  btnManageGroups->setEnabled( true );
2109 
2110  mModel->setCheckable( true );
2111 
2112  // No selection should be possible
2113  listItems->setSelectionMode( QAbstractItemView::NoSelection );
2114  mSymbolTreeView->setSelectionMode( QAbstractItemView::NoSelection );
2115  }
2116 }
2117 
2118 void QgsStyleManagerDialog::regrouped( QStandardItem * )
2119 {
2120 }
2121 
2122 void QgsStyleManagerDialog::setSymbolsChecked( const QStringList & )
2123 {
2124 }
2125 
2126 void QgsStyleManagerDialog::filterSymbols( const QString &qword )
2127 {
2128  mModel->setFilterString( qword );
2129 }
2130 
2131 void QgsStyleManagerDialog::symbolSelected( const QModelIndex &index )
2132 {
2133  actnEditItem->setEnabled( index.isValid() && !mGroupingMode && !mReadOnly );
2134 }
2135 
2136 void QgsStyleManagerDialog::selectedSymbolsChanged( const QItemSelection &selected, const QItemSelection &deselected )
2137 {
2138  Q_UNUSED( selected )
2139  Q_UNUSED( deselected )
2140  bool nothingSelected = listItems->selectionModel()->selectedIndexes().empty();
2141  actnRemoveItem->setDisabled( nothingSelected || mReadOnly );
2142  actnAddFavorite->setDisabled( nothingSelected || mReadOnly );
2143  actnRemoveFavorite->setDisabled( nothingSelected || mReadOnly );
2144  mGroupListMenu->setDisabled( nothingSelected || mReadOnly );
2145  actnDetag->setDisabled( nothingSelected || mReadOnly );
2146  actnExportAsPNG->setDisabled( nothingSelected );
2147  actnExportAsSVG->setDisabled( nothingSelected );
2148  if ( mActionCopyToDefault )
2149  mActionCopyToDefault->setDisabled( nothingSelected );
2150  mCopyToDefaultButton->setDisabled( nothingSelected );
2151  actnEditItem->setDisabled( nothingSelected || mReadOnly );
2152 }
2153 
2155 {
2156  groupTree->setEnabled( enable );
2157  btnAddTag->setEnabled( enable && !mReadOnly );
2158  btnAddSmartgroup->setEnabled( enable && !mReadOnly );
2159  actnAddTag->setEnabled( enable && !mReadOnly );
2160  actnAddSmartgroup->setEnabled( enable && !mReadOnly );
2161  actnRemoveGroup->setEnabled( enable && !mReadOnly );
2162  btnManageGroups->setEnabled( !mReadOnly && ( enable || mGroupingMode ) ); // always enabled in grouping mode, as it is the only way to leave grouping mode
2163  searchBox->setEnabled( enable );
2164 }
2165 
2167 {
2168  actnRemoveGroup->setEnabled( enable && !mReadOnly );
2169  btnManageGroups->setEnabled( !mReadOnly && ( enable || mGroupingMode ) ); // always enabled in grouping mode, as it is the only way to leave grouping mode
2170 }
2171 
2173 {
2174  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
2175  for ( int i = 0; i < treeModel->rowCount(); i++ )
2176  {
2177  treeModel->item( i )->setEnabled( enable );
2178 
2179  if ( treeModel->item( i )->data() == "smartgroups" )
2180  {
2181  for ( int j = 0; j < treeModel->item( i )->rowCount(); j++ )
2182  {
2183  treeModel->item( i )->child( j )->setEnabled( enable );
2184  }
2185  }
2186  }
2187 
2188  // The buttons
2189  // NOTE: if you ever change the layout name in the .ui file edit here too
2190  for ( int i = 0; i < symbolBtnsLayout->count(); i++ )
2191  {
2192  QWidget *w = symbolBtnsLayout->itemAt( i )->widget();
2193  if ( w )
2194  w->setEnabled( enable );
2195  }
2196 
2197  // The actions
2198  actnRemoveItem->setEnabled( enable );
2199  actnEditItem->setEnabled( enable );
2200  mActionCopyItem->setEnabled( enable );
2201  mActionPasteItem->setEnabled( enable );
2202 }
2203 
2205 {
2206  QPoint globalPos = groupTree->viewport()->mapToGlobal( point );
2207 
2208  QModelIndex index = groupTree->indexAt( point );
2209  if ( index.isValid() && !mGroupingMode )
2210  mGroupTreeContextMenu->popup( globalPos );
2211 }
2212 
2214 {
2215  QPoint globalPos = mSymbolViewStackedWidget->currentIndex() == 0
2216  ? listItems->viewport()->mapToGlobal( point )
2217  : mSymbolTreeView->viewport()->mapToGlobal( point );
2218 
2219  // Clear all actions and create new actions for every group
2220  mGroupListMenu->clear();
2221 
2222  const QModelIndexList indices = listItems->selectionModel()->selectedRows();
2223 
2224  if ( !mReadOnly )
2225  {
2226  const QStringList currentTags = indices.count() == 1 ? indices.at( 0 ).data( QgsStyleModel::TagRole ).toStringList() : QStringList();
2227  QAction *a = nullptr;
2228  QStringList tags = mStyle->tags();
2229  tags.sort();
2230  for ( const QString &tag : qgis::as_const( tags ) )
2231  {
2232  a = new QAction( tag, mGroupListMenu );
2233  a->setData( tag );
2234  if ( indices.count() == 1 )
2235  {
2236  a->setCheckable( true );
2237  a->setChecked( currentTags.contains( tag ) );
2238  }
2239  connect( a, &QAction::triggered, this, [ = ]( bool ) { tagSelectedSymbols(); }
2240  );
2241  mGroupListMenu->addAction( a );
2242  }
2243 
2244  if ( tags.count() > 0 )
2245  {
2246  mGroupListMenu->addSeparator();
2247  }
2248  a = new QAction( tr( "Create New Tag…" ), mGroupListMenu );
2249  connect( a, &QAction::triggered, this, [ = ]( bool ) { tagSelectedSymbols( true ); }
2250  );
2251  mGroupListMenu->addAction( a );
2252  }
2253 
2254  const QList< ItemDetails > items = selectedItems();
2255  mActionCopyItem->setEnabled( !items.isEmpty() && ( items.at( 0 ).entityType != QgsStyle::ColorrampEntity ) );
2256 
2257  bool enablePaste = false;
2258  std::unique_ptr< QgsSymbol > tempSymbol( QgsSymbolLayerUtils::symbolFromMimeData( QApplication::clipboard()->mimeData() ) );
2259  if ( tempSymbol )
2260  enablePaste = true;
2261  else
2262  {
2263  ( void )QgsTextFormat::fromMimeData( QApplication::clipboard()->mimeData(), &enablePaste );
2264  }
2265  mActionPasteItem->setEnabled( enablePaste );
2266 
2267  mGroupMenu->popup( globalPos );
2268 }
2269 
2271 {
2272  const QList< ItemDetails > items = selectedItems();
2273  for ( const ItemDetails &details : items )
2274  {
2275  mStyle->addFavorite( details.entityType, details.name );
2276  }
2277 }
2278 
2280 {
2281  const QList< ItemDetails > items = selectedItems();
2282  for ( const ItemDetails &details : items )
2283  {
2284  mStyle->removeFavorite( details.entityType, details.name );
2285  }
2286 }
2287 
2289 {
2290  QAction *selectedItem = qobject_cast<QAction *>( sender() );
2291  if ( selectedItem )
2292  {
2293  const QList< ItemDetails > items = selectedItems();
2294  QString tag;
2295  if ( newTag )
2296  {
2297  int id = addTag();
2298  if ( id == 0 )
2299  {
2300  return;
2301  }
2302 
2303  tag = mStyle->tag( id );
2304  }
2305  else
2306  {
2307  tag = selectedItem->data().toString();
2308  }
2309 
2310  for ( const ItemDetails &details : items )
2311  {
2312  mStyle->tagSymbol( details.entityType, details.name, QStringList( tag ) );
2313  }
2314  }
2315 }
2316 
2318 {
2319  QAction *selectedItem = qobject_cast<QAction *>( sender() );
2320 
2321  if ( selectedItem )
2322  {
2323  const QList< ItemDetails > items = selectedItems();
2324  for ( const ItemDetails &details : items )
2325  {
2326  mStyle->detagSymbol( details.entityType, details.name );
2327  }
2328  }
2329 }
2330 
2332 {
2333  QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
2334 
2335  // determine whether it is a valid group
2336  QModelIndex present = groupTree->currentIndex();
2337  if ( present.parent().data( Qt::UserRole + 1 ) != "smartgroups" )
2338  {
2339  // should never appear - blocked by GUI logic
2340  QMessageBox::critical( this, tr( "Edit Smart Group" ),
2341  tr( "You have not selected a Smart Group. Kindly select a Smart Group to edit." ) );
2342  return;
2343  }
2344  QStandardItem *item = treeModel->itemFromIndex( present );
2345 
2346  QgsSmartGroupEditorDialog dlg( mStyle, this );
2347  QgsSmartConditionMap map = mStyle->smartgroup( present.data( Qt::UserRole + 1 ).toInt() );
2348  dlg.setSmartgroupName( item->text() );
2349  dlg.setOperator( mStyle->smartgroupOperator( item->data().toInt() ) );
2350  dlg.setConditionMap( map );
2351 
2352  if ( dlg.exec() == QDialog::Rejected )
2353  return;
2354 
2355  mBlockGroupUpdates++;
2356  mStyle->remove( QgsStyle::SmartgroupEntity, item->data().toInt() );
2357  int id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() );
2358  mBlockGroupUpdates--;
2359  if ( !id )
2360  {
2361  mMessageBar->pushCritical( tr( "Edit Smart Group" ), tr( "There was an error while editing the smart group." ) );
2362  return;
2363  }
2364  item->setText( dlg.smartgroupName() );
2365  item->setData( id );
2366 
2367  groupChanged( present );
2368 }
2369 
2371 {
2372  reject();
2373 }
2374 
2376 {
2377  QgsHelp::openHelp( QStringLiteral( "working_with_vector/style_library.html#the-style-manager" ) );
2378 }
2379 
A QAbstractItemModel subclass for showing symbol and color ramp entities contained within a QgsStyle ...
Definition: qgsstylemodel.h:45
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 &)
Triggered 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.
static QgsSymbol * symbolFromMimeData(const QMimeData *data)
Attempts to parse mime data as a symbol.
bool addTextFormat(const QString &name, const QgsTextFormat &format, bool update=false)
Adds a text format with the specified name to the style.
Definition: qgsstyle.cpp:260
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:236
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:597
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
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:154
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.
bool addLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool update=false)
Adds label settings with the specified name to the style.
Definition: qgsstyle.cpp:281
QStringList tagsOfSymbol(StyleEntity type, const QString &symbol)
Returns the tags associated with the symbol.
Definition: qgsstyle.cpp:1674
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
Abstract base class for color ramps.
Definition: qgscolorramp.h:31
QMap< int, QString > QgsSymbolGroupMap
Definition: qgsstyle.h:41
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:302
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:1397
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:45
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QgsTextFormat format() const
Returns the current formatting settings defined by the widget.
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
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:61
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
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:356
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:335
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
bool rename(StyleEntity type, int id, const QString &newName)
Renames the given entity with the specified id.
Definition: qgsstyle.cpp:1052
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:860
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1060
String list of tags.
Definition: qgsstylemodel.h:62
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:74
A dialog which allows users to modify the properties of a QgsLimitedRandomColorRamp.
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstyle.h:177
static QgsTextFormat fromMimeData(const QMimeData *data, bool *ok=nullptr)
Attempts to parse the provided mime data as a QgsTextFormat.
SymbolType
Type of the symbol.
Definition: qgssymbol.h:83
void tagSelectedSymbols(bool newTag=false)
Tag selected symbols using menu item selection.
QgsGradientColorRamp * clone() const override
Creates a clone of the color ramp.
QStringList textFormatNames() const
Returns a list of names of text formats in the style.
Definition: qgsstyle.cpp:2038
QgsPalLayerSettings labelSettings(const QString &name) const
Returns the label settings with the specified name.
Definition: qgsstyle.cpp:2048
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:1953
Q_DECL_DEPRECATED bool removeColorRamp() SIP_DEPRECATED
void exportItemsSVG()
Triggers the dialog to export selected items as SVG files.
QStringList labelSettingsNames() const
Returns a list of names of label settings in the style.
Definition: qgsstyle.cpp:2066
bool removeFavorite(StyleEntity type, const QString &name)
Removes the specified symbol from favorites.
Definition: qgsstyle.cpp:1241
QgsPresetSchemeColorRamp * clone() const override
Creates a clone of the color ramp.
static QMimeData * symbolToMimeData(const QgsSymbol *symbol)
Creates new mime data from a symbol.
bool remove(StyleEntity type, int id)
Removes the specified entity from the db.
Definition: qgsstyle.cpp:1116
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:1012
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:2344
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...
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
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.
QgsTextFormat textFormat(const QString &name) const
Returns the text format with the specified name.
Definition: qgsstyle.cpp:2028
A QSortFilterProxyModel subclass for showing filtered symbol and color ramps entries from a QgsStyle ...
const QgsTextFormat & format() const
Returns the label text formatting settings, e.g., font settings, buffer settings, etc...
QgsGradientColorRamp * cloneGradientRamp() const
QgsSmartConditionMap smartgroup(int id)
Returns the QgsSmartConditionMap for the given id.
Definition: qgsstyle.cpp:2304
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:2076
static QgsStyleModel * defaultStyleModel()
Returns a shared QgsStyleModel containing the default style library (see QgsStyle::defaultStyle()).
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
bool saveTextFormat(const QString &name, const QgsTextFormat &format, bool favorite, const QStringList &tags)
Adds a text format to the database.
Definition: qgsstyle.cpp:712
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:124
bool removeTextFormat(const QString &name)
Removes a text format from the style.
Definition: qgsstyle.cpp:745
QStringList tags() const
Returns a list of all tags in the style database.
Definition: qgsstyle.cpp:1032
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:2111
Name column.
Definition: qgsstylemodel.h:54
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
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
Q_DECL_DEPRECATED void setSymbolsChecked(const QStringList &) SIP_DEPRECATED
QStringList colorRampNames() const
Returns a list of names of color ramps.
Definition: qgsstyle.cpp:372
void removeGroup()
Removes the selected tag or smartgroup.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:127
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
int addTag()
Triggers the dialog to add a new tag.
void setSmartgroupName(const QString &)
sets the smart group Name
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
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:1155
void showHelp()
Opens the associated help.
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
Definition: qgsstyle.cpp:214
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:148
void onClose()
Closes the dialog.
bool removeSymbol(const QString &name)
Removes symbol from style (and delete it)
Definition: qgsstyle.cpp:181
Container for all settings relating to text rendering.
bool saveLabelSettings(const QString &name, const QgsPalLayerSettings &settings, bool favorite, const QStringList &tags)
Adds label settings to the database.
Definition: qgsstyle.cpp:800
A dialog which allows users to modify the properties of a QgsCptCityColorRamp.
A simple dialog for customizing text formatting settings.
Style entity type, see QgsStyle::StyleEntity.
Definition: qgsstylemodel.h:61
QDialogButtonBox * buttonBox() const
Returns a reference to the dialog&#39;s button box.
bool addFavorite(StyleEntity type, const QString &name)
Adds the specified symbol to favorites.
Definition: qgsstyle.cpp:1189
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Definition: qgscolorramp.h:139
bool removeLabelSettings(const QString &name)
Removes label settings from the style.
Definition: qgsstyle.cpp:833
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:1495
QStringList symbolsOfFavorite(StyleEntity type) const
Returns the symbol names which are flagged as favorite.
Definition: qgsstyle.cpp:887
QMultiMap< QString, QString > QgsSmartConditionMap
A multimap to hold the smart group conditions as constraint and parameter pairs.
Definition: qgsstyle.h:78
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:2163
Q_DECL_DEPRECATED bool removeSymbol() SIP_DEPRECATED
void detagSelectedSymbols()
Remove all tags from selected symbols.
Symbol type (for symbol entities)
Definition: qgsstylemodel.h:63
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.
QStringList symbolNames() const
Returns a list of names of symbols.
Definition: qgsstyle.cpp:230
QgsWkbTypes::GeometryType layerType
Geometry type of layers associated with these settings.