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