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