50 #include <QFileDialog>
51 #include <QInputDialog>
52 #include <QMessageBox>
53 #include <QPushButton>
54 #include <QStandardItemModel>
57 #include <QDesktopServices>
69 QgsCheckableStyleModel::QgsCheckableStyleModel(
QgsStyleModel *sourceModel, QObject *parent,
bool readOnly )
71 , mStyle( sourceModel->style() )
72 , mReadOnly( readOnly )
77 QgsCheckableStyleModel::QgsCheckableStyleModel(
QgsStyle *style, QObject *parent,
bool readOnly )
80 , mReadOnly( readOnly )
84 void QgsCheckableStyleModel::setCheckable(
bool checkable )
86 if ( checkable == mCheckable )
89 mCheckable = checkable;
90 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector< int >() << Qt::CheckStateRole );
93 void QgsCheckableStyleModel::setCheckTag(
const QString &tag )
95 if ( tag == mCheckTag )
99 emit dataChanged( index( 0, 0 ), index( rowCount() - 1, 0 ), QVector< int >() << Qt::CheckStateRole );
102 Qt::ItemFlags QgsCheckableStyleModel::flags(
const QModelIndex &index )
const
104 Qt::ItemFlags f = QgsStyleProxyModel::flags( index );
105 if ( !mReadOnly && mCheckable && index.column() == 0 )
106 f |= Qt::ItemIsUserCheckable;
109 f &= ~Qt::ItemIsEditable;
114 QVariant QgsCheckableStyleModel::data(
const QModelIndex &index,
int role )
const
121 QFont f = QgsStyleProxyModel::data( index, role ).value< QFont >();
126 case Qt::CheckStateRole:
128 if ( !mCheckable || index.column() != 0 )
132 return tags.contains( mCheckTag ) ? Qt::Checked : Qt::Unchecked;
139 return QgsStyleProxyModel::data( index, role );
142 bool QgsCheckableStyleModel::setData(
const QModelIndex &i,
const QVariant &value,
int role )
144 if ( i.row() < 0 || i.row() >= rowCount( QModelIndex() ) ||
145 ( role != Qt::EditRole && role != Qt::CheckStateRole ) )
151 if ( role == Qt::CheckStateRole )
153 if ( !mCheckable || mCheckTag.isEmpty() )
156 const QString name = data( index( i.row(),
QgsStyleModel::Name ), Qt::DisplayRole ).toString();
159 if ( value.toInt() == Qt::Checked )
160 return mStyle->tagSymbol( entity, name, QStringList() << mCheckTag );
162 return mStyle->detagSymbol( entity, name, QStringList() << mCheckTag );
164 return QgsStyleProxyModel::setData( i, value, role );
174 QString QgsStyleManagerDialog::sPreviousTag;
177 : QDialog( parent, flags )
178 , mReadOnly( readOnly )
181 setCurrentStyle( style );
182 mStyleDatabaseWidget->hide();
186 : QDialog( parent, flags )
192 mComboBoxStyleDatabase->setModel( mProjectStyleModel );
196 connect( mComboBoxStyleDatabase, qOverload< int >( &QComboBox::currentIndexChanged ),
this, [ = ]()
198 if ( mBlockStyleDatabaseChanges )
201 const QModelIndex index = mProjectStyleModel->index( mComboBoxStyleDatabase->currentIndex(), 0, QModelIndex() );
205 connect( mButtonAddStyleDatabase, &QAbstractButton::clicked,
this, [ = ] { addStyleDatabase(
false ); } );
206 connect( mButtonNewStyleDatabase, &QAbstractButton::clicked,
this, [ = ] { addStyleDatabase(
true ); } );
208 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
210 mStyleDatabaseWidget->hide();
214 void QgsStyleManagerDialog::init()
218 connect( tabItemType, &QTabWidget::currentChanged,
this, &QgsStyleManagerDialog::tabItemType_currentChanged );
222 QPushButton *downloadButton = buttonBox->addButton( tr(
"Browse Online Styles" ), QDialogButtonBox::ResetRole );
223 downloadButton->setToolTip( tr(
"Download new styles from the online QGIS style repository" ) );
225 connect( downloadButton, &QPushButton::clicked,
this, [ = ]
227 QDesktopServices::openUrl( QUrl( QStringLiteral(
"https://plugins.qgis.org/styles" ) ) );
231 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
232 mVerticalLayout->insertWidget( 0, mMessageBar );
235 setWindowModality( Qt::WindowModal );
240 mSplitter->setSizes( QList<int>() << 170 << 540 );
241 mSplitter->restoreState( settings.
value( QStringLiteral(
"Windows/StyleV2Manager/splitter" ) ).toByteArray() );
243 tabItemType->setDocumentMode(
true );
244 searchBox->setShowSearchIcon(
true );
245 searchBox->setPlaceholderText( tr(
"Filter symbols…" ) );
249 connect( btnEditItem, &QPushButton::clicked,
this, [ = ](
bool ) {
editItem(); }
251 connect( actnEditItem, &QAction::triggered,
this, [ = ](
bool ) {
editItem(); }
255 connect( btnAddItem, &QPushButton::clicked,
this, [ = ](
bool )
258 if ( !btnAddItem->menu() )
265 connect( btnRemoveItem, &QPushButton::clicked,
this, [ = ](
bool ) {
removeItem(); }
267 connect( actnRemoveItem, &QAction::triggered,
this, [ = ](
bool ) {
removeItem(); }
270 mShareMenu =
new QMenu( tr(
"Share Menu" ),
this );
271 mExportAction =
new QAction( tr(
"Export Item(s)…" ),
this );
273 mShareMenu->addAction( mExportAction );
275 connect( mCopyToDefaultButton, &QPushButton::clicked,
this, &QgsStyleManagerDialog::copyItemsToDefault );
277 mActionCopyItem =
new QAction( tr(
"Copy Item" ),
this );
278 connect( mActionCopyItem, &QAction::triggered,
this, &QgsStyleManagerDialog::copyItem );
279 mActionPasteItem =
new QAction( tr(
"Paste Item…" ),
this );
280 connect( mActionPasteItem, &QAction::triggered,
this, &QgsStyleManagerDialog::pasteItem );
282 QShortcut *copyShortcut =
new QShortcut( QKeySequence( QKeySequence::StandardKey::Copy ),
this );
283 connect( copyShortcut, &QShortcut::activated,
this, &QgsStyleManagerDialog::copyItem );
284 QShortcut *pasteShortcut =
new QShortcut( QKeySequence( QKeySequence::StandardKey::Paste ),
this );
285 connect( pasteShortcut, &QShortcut::activated,
this, &QgsStyleManagerDialog::pasteItem );
286 QShortcut *removeShortcut =
new QShortcut( QKeySequence( QKeySequence::StandardKey::Delete ),
this );
288 QShortcut *editShortcut =
new QShortcut( QKeySequence( Qt::Key_Return ),
this );
291 mShareMenu->addSeparator();
292 mShareMenu->addAction( actnExportAsPNG );
293 mShareMenu->addAction( actnExportAsSVG );
298 btnShare->setMenu( mShareMenu );
300 listItems->setTextElideMode( Qt::TextElideMode::ElideRight );
302 mSymbolTreeView->setIconSize( QSize(
static_cast< int >( treeIconSize ),
static_cast< int >( treeIconSize ) ) );
304 listItems->setSelectionBehavior( QAbstractItemView::SelectRows );
305 listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
306 mSymbolTreeView->setSelectionMode( listItems->selectionMode() );
308 QStandardItemModel *groupModel =
new QStandardItemModel( groupTree );
309 groupTree->setModel( groupModel );
310 groupTree->setHeaderHidden(
true );
312 connect( groupTree->selectionModel(), &QItemSelectionModel::currentChanged,
316 QMenu *groupMenu =
new QMenu( tr(
"Group Actions" ),
this );
318 groupMenu->addAction( actnTagSymbols );
320 actnFinishTagging->setVisible(
false );
321 groupMenu->addAction( actnFinishTagging );
322 groupMenu->addAction( actnEditSmartGroup );
323 btnManageGroups->setMenu( groupMenu );
328 groupTree->setContextMenuPolicy( Qt::CustomContextMenu );
329 connect( groupTree, &QWidget::customContextMenuRequested,
333 listItems->setContextMenuPolicy( Qt::CustomContextMenu );
334 connect( listItems, &QWidget::customContextMenuRequested,
336 mSymbolTreeView->setContextMenuPolicy( Qt::CustomContextMenu );
337 connect( mSymbolTreeView, &QWidget::customContextMenuRequested,
340 mMenuBtnAddItemAll =
new QMenu(
this );
341 mMenuBtnAddItemColorRamp =
new QMenu(
this );
342 mMenuBtnAddItemLabelSettings =
new QMenu(
this );
343 mMenuBtnAddItemLegendPatchShape =
new QMenu(
this );
344 mMenuBtnAddItemSymbol3D =
new QMenu(
this );
348 mMenuBtnAddItemAll->addAction( item );
351 mMenuBtnAddItemAll->addAction( item );
354 mMenuBtnAddItemAll->addAction( item );
355 mMenuBtnAddItemAll->addSeparator();
358 for (
const QPair< QString, QString > &rampType : rampTypes )
360 item =
new QAction(
QgsApplication::getThemeIcon( QStringLiteral(
"styleicons/color.svg" ) ), tr(
"%1…" ).arg( rampType.second ),
this );
361 connect( item, &QAction::triggered,
this, [ = ](
bool ) {
addColorRamp( rampType.first ); } );
362 mMenuBtnAddItemAll->addAction( item );
363 mMenuBtnAddItemColorRamp->addAction( item );
365 mMenuBtnAddItemAll->addSeparator();
367 connect( item, &QAction::triggered,
this, [ = ](
bool ) { addTextFormat(); } );
368 mMenuBtnAddItemAll->addAction( item );
369 mMenuBtnAddItemAll->addSeparator();
372 mMenuBtnAddItemAll->addAction( item );
373 mMenuBtnAddItemLabelSettings->addAction( item );
376 mMenuBtnAddItemAll->addAction( item );
377 mMenuBtnAddItemLabelSettings->addAction( item );
380 mMenuBtnAddItemAll->addAction( item );
381 mMenuBtnAddItemLabelSettings->addAction( item );
383 mMenuBtnAddItemAll->addSeparator();
386 mMenuBtnAddItemAll->addAction( item );
387 mMenuBtnAddItemLegendPatchShape->addAction( item );
389 connect( item, &QAction::triggered,
this, [ = ](
bool ) { addLegendPatchShape(
Qgis::SymbolType::Line ); } );
390 mMenuBtnAddItemAll->addAction( item );
391 mMenuBtnAddItemLegendPatchShape->addAction( item );
393 connect( item, &QAction::triggered,
this, [ = ](
bool ) { addLegendPatchShape(
Qgis::SymbolType::Fill ); } );
394 mMenuBtnAddItemAll->addAction( item );
395 mMenuBtnAddItemLegendPatchShape->addAction( item );
397 mMenuBtnAddItemAll->addSeparator();
399 connect( item, &QAction::triggered,
this, [ = ](
bool ) { addSymbol3D( QStringLiteral(
"point" ) ); } );
400 mMenuBtnAddItemAll->addAction( item );
401 mMenuBtnAddItemSymbol3D->addAction( item );
403 connect( item, &QAction::triggered,
this, [ = ](
bool ) { addSymbol3D( QStringLiteral(
"line" ) ); } );
404 mMenuBtnAddItemAll->addAction( item );
405 mMenuBtnAddItemSymbol3D->addAction( item );
407 connect( item, &QAction::triggered,
this, [ = ](
bool ) { addSymbol3D( QStringLiteral(
"polygon" ) ); } );
408 mMenuBtnAddItemAll->addAction( item );
409 mMenuBtnAddItemSymbol3D->addAction( item );
412 mGroupMenu =
new QMenu(
this );
413 mGroupListMenu =
new QMenu( mGroupMenu );
414 mGroupListMenu->setTitle( tr(
"Add to Tag" ) );
415 mGroupListMenu->setEnabled(
false );
422 mGroupTreeContextMenu =
new QMenu(
this );
424 connect( actnAddTag, &QAction::triggered,
this, [ = ](
bool ) {
addTag(); } );
425 connect( actnAddSmartgroup, &QAction::triggered,
this, [ = ](
bool ) {
addSmartgroup(); } );
428 tabItemType_currentChanged( 0 );
430 connect( mButtonIconView, &QToolButton::toggled,
this, [ = ](
bool active )
434 mSymbolViewStackedWidget->setCurrentIndex( 0 );
439 connect( mButtonListView, &QToolButton::toggled,
this, [ = ](
bool active )
444 mSymbolViewStackedWidget->setCurrentIndex( 1 );
448 const int currentView = settings.
value( QStringLiteral(
"Windows/StyleV2Manager/lastIconView" ), 0,
QgsSettings::Gui ).toInt();
449 if ( currentView == 0 )
450 mButtonIconView->setChecked(
true );
452 mButtonListView->setChecked(
true );
454 mSymbolTreeView->header()->restoreState( settings.
value( QStringLiteral(
"Windows/StyleV2Manager/treeState" ), QByteArray(),
QgsSettings::Gui ).toByteArray() );
455 connect( mSymbolTreeView->header(), &QHeaderView::sectionResized,
this, [
this]
458 QgsSettings().setValue( QStringLiteral(
"Windows/StyleV2Manager/treeState" ), mSymbolTreeView->header()->saveState(), QgsSettings::Gui );
461 const int thumbnailSize = settings.
value( QStringLiteral(
"Windows/StyleV2Manager/thumbnailSize" ), 0,
QgsSettings::Gui ).toInt();
462 mSliderIconSize->setValue( thumbnailSize );
463 connect( mSliderIconSize, &QSlider::valueChanged,
this, &QgsStyleManagerDialog::setThumbnailSize );
464 setThumbnailSize( thumbnailSize );
467 void QgsStyleManagerDialog::setCurrentStyle(
QgsStyle *style )
469 if ( mStyle == style )
479 QgsCheckableStyleModel *oldModel = mModel;
482 const bool readOnly = isReadOnly();
485 if ( !mActionCopyToDefault )
487 mActionCopyToDefault =
new QAction( tr(
"Copy Selection to Default Style…" ),
this );
488 mShareMenu->insertAction( mActionCopyItem, mActionCopyToDefault );
489 connect( mActionCopyToDefault, &QAction::triggered,
this, &QgsStyleManagerDialog::copyItemsToDefault );
491 mCopyToDefaultButton->show();
492 mModel =
new QgsCheckableStyleModel( mStyle,
this, readOnly );
496 mCopyToDefaultButton->hide();
497 if ( mActionCopyToDefault )
499 mActionCopyToDefault->deleteLater();
500 mActionCopyToDefault =
nullptr;
504 mModel->addDesiredIconSize( mSymbolTreeView->iconSize() );
505 mModel->addDesiredIconSize( listItems->iconSize() );
506 mModel->setFilterString( searchBox->text() );
508 listItems->setModel( mModel );
509 mSymbolTreeView->setModel( mModel );
511 mSymbolTreeView->setSelectionModel( listItems->selectionModel() );
513 connect( listItems->selectionModel(), &QItemSelectionModel::currentChanged,
515 connect( listItems->selectionModel(), &QItemSelectionModel::selectionChanged,
520 oldModel->deleteLater();
528 if ( mProjectStyleModel )
530 const QModelIndex styleIndex = mProjectStyleModel->
indexFromStyle( mStyle );
531 mBlockStyleDatabaseChanges++;
532 mComboBoxStyleDatabase->setCurrentIndex( styleIndex.row() );
533 mBlockStyleDatabaseChanges--;
538 btnAddTag->setEnabled(
false );
539 btnAddSmartgroup->setEnabled(
false );
540 btnManageGroups->setEnabled(
false );
542 btnAddItem->setVisible(
false );
543 btnRemoveItem->setVisible(
false );
544 btnEditItem->setVisible(
false );
545 btnAddSmartgroup->setVisible(
false );
546 btnAddTag->setVisible(
false );
547 btnManageGroups->setVisible(
false );
549 delete mImportAction;
550 mImportAction =
nullptr;
552 mGroupTreeContextMenu->clear();
554 mGroupMenu->addAction( mActionCopyItem );
558 btnAddTag->setEnabled(
true );
559 btnAddSmartgroup->setEnabled(
true );
560 btnManageGroups->setEnabled(
true );
562 btnAddItem->setVisible(
true );
563 btnRemoveItem->setVisible(
true );
564 btnEditItem->setVisible(
true );
565 btnAddSmartgroup->setVisible(
true );
566 btnAddTag->setVisible(
true );
567 btnManageGroups->setVisible(
true );
569 if ( !mImportAction )
571 mImportAction =
new QAction( tr(
"Import Item(s)…" ),
this );
573 mShareMenu->insertAction( mShareMenu->actions().at( mShareMenu->actions().indexOf( mExportAction ) + 1 ), mImportAction );
577 mGroupTreeContextMenu->clear();
578 mGroupTreeContextMenu->addAction( actnEditSmartGroup );
579 mGroupTreeContextMenu->addAction( actnAddTag );
580 mGroupTreeContextMenu->addAction( actnAddSmartgroup );
581 mGroupTreeContextMenu->addAction( actnRemoveGroup );
584 mGroupMenu->addAction( actnAddFavorite );
585 mGroupMenu->addAction( actnRemoveFavorite );
586 mGroupMenu->addSeparator()->setParent(
this );
587 mGroupMenu->addMenu( mGroupListMenu );
588 mGroupMenu->addAction( actnDetag );
589 mGroupMenu->addSeparator()->setParent(
this );
590 mGroupMenu->addAction( actnRemoveItem );
591 mGroupMenu->addAction( actnEditItem );
592 mGroupMenu->addAction( mActionCopyItem );
593 mGroupMenu->addAction( mActionPasteItem );
594 mGroupMenu->addSeparator()->setParent(
this );
597 if ( mActionCopyToDefault )
599 mGroupMenu->addAction( mActionCopyToDefault );
601 mGroupMenu->addAction( actnExportAsPNG );
602 mGroupMenu->addAction( actnExportAsSVG );
605 const QModelIndexList prevIndex = groupTree->model()->match( groupTree->model()->index( 0, 0 ), Qt::UserRole + 1, sPreviousTag, 1, Qt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive );
606 groupTree->setCurrentIndex( !prevIndex.empty() ? prevIndex.at( 0 ) : groupTree->model()->index( 0, 0 ) );
609 tabItemType_currentChanged( tabItemType->currentIndex() );
615 void QgsStyleManagerDialog::currentStyleAboutToBeDestroyed()
626 settings.
setValue( QStringLiteral(
"Windows/StyleV2Manager/splitter" ), mSplitter->saveState() );
633 void QgsStyleManagerDialog::tabItemType_currentChanged(
int )
642 searchBox->setPlaceholderText( isSymbol ? tr(
"Filter symbols…" ) :
643 isColorRamp ? tr(
"Filter color ramps…" ) :
644 isTextFormat ? tr(
"Filter text symbols…" ) :
645 isLabelSettings ? tr(
"Filter label settings…" ) :
646 isLegendPatchShape ? tr(
"Filter legend patch shapes…" ) : tr(
"Filter 3D symbols…" ) );
648 const bool readOnly = isReadOnly();
649 if ( !readOnly && isColorRamp )
651 btnAddItem->setMenu( mMenuBtnAddItemColorRamp );
653 else if ( !readOnly && isLegendPatchShape )
655 btnAddItem->setMenu( mMenuBtnAddItemLegendPatchShape );
657 else if ( !readOnly && isSymbol3D )
659 btnAddItem->setMenu( mMenuBtnAddItemSymbol3D );
661 else if ( !readOnly && isLabelSettings )
663 btnAddItem->setMenu( mMenuBtnAddItemLabelSettings );
665 else if ( !readOnly && !isSymbol && !isColorRamp )
667 btnAddItem->setMenu(
nullptr );
669 else if ( !readOnly && tabItemType->currentIndex() == 0 )
671 btnAddItem->setMenu( mMenuBtnAddItemAll );
675 btnAddItem->setMenu(
nullptr );
678 actnExportAsPNG->setVisible( isSymbol );
679 actnExportAsSVG->setVisible( isSymbol );
684 mModel->setEntityFilterEnabled( !allTypesSelected() );
685 mModel->setSymbolTypeFilterEnabled( isSymbol && !allTypesSelected() );
686 if ( isSymbol && !allTypesSelected() )
693 void QgsStyleManagerDialog::copyItemsToDefault()
695 const QList< ItemDetails > items = selectedItems();
696 if ( !items.empty() )
700 if ( !mBaseName.isEmpty() )
701 options.append( mBaseName );
704 defaultTags.sort( Qt::CaseInsensitive );
705 options.append( defaultTags );
706 const QString tags = QInputDialog::getItem(
this, tr(
"Import Items" ),
707 tr(
"Additional tags to add (comma separated)" ), options, mBaseName.isEmpty() ? -1 : 0,
true, &ok );
711 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
712 const QStringList parts = tags.split(
',', QString::SkipEmptyParts );
714 const QStringList parts = tags.split(
',', Qt::SkipEmptyParts );
716 QStringList additionalTags;
717 additionalTags.reserve( parts.count() );
718 for (
const QString &tag : parts )
719 additionalTags << tag.trimmed();
721 auto cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
722 const int count = copyItems( items, mStyle,
QgsStyle::defaultStyle(),
this, cursorOverride,
true, additionalTags,
false,
false );
723 cursorOverride.reset();
726 mMessageBar->pushSuccess( tr(
"Import Items" ), count > 1 ? tr(
"Successfully imported %n item(s).",
nullptr, count ) : tr(
"Successfully imported item." ) );
731 void QgsStyleManagerDialog::copyItem()
733 const QList< ItemDetails > items = selectedItems();
737 ItemDetails details = items.at( 0 );
738 switch ( details.entityType )
742 std::unique_ptr< QgsSymbol > symbol( mStyle->
symbol( details.name ) );
752 QApplication::clipboard()->setMimeData( format.toMimeData() );
759 QApplication::clipboard()->setMimeData( format.toMimeData() );
773 void QgsStyleManagerDialog::pasteItem()
775 const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data(
GroupModelRoles::TagName ).toString() : QString();
779 QgsStyleSaveDialog saveDlg(
this );
780 saveDlg.setWindowTitle( tr(
"Paste Symbol" ) );
781 saveDlg.setDefaultTags( defaultTag );
782 if ( !saveDlg.exec() || saveDlg.name().isEmpty() )
785 if ( mStyle->
symbolNames().contains( saveDlg.name() ) )
787 int res = QMessageBox::warning(
this, tr(
"Paste Symbol" ),
788 tr(
"A symbol with the name '%1' already exists. Overwrite?" )
789 .arg( saveDlg.name() ),
790 QMessageBox::Yes | QMessageBox::No );
791 if ( res != QMessageBox::Yes )
798 QStringList symbolTags = saveDlg.tags().split(
',' );
800 mStyle->
addSymbol( saveDlg.name(), tempSymbol.release() );
802 mStyle->
saveSymbol( saveDlg.name(), newSymbol, saveDlg.isFavorite(), symbolTags );
811 saveDlg.setDefaultTags( defaultTag );
812 saveDlg.setWindowTitle( tr(
"Paste Text Format" ) );
813 if ( !saveDlg.exec() || saveDlg.name().isEmpty() )
818 int res = QMessageBox::warning(
this, tr(
"Paste Text Format" ),
819 tr(
"A format with the name '%1' already exists. Overwrite?" )
820 .arg( saveDlg.name() ),
821 QMessageBox::Yes | QMessageBox::No );
822 if ( res != QMessageBox::Yes )
829 QStringList symbolTags = saveDlg.tags().split(
',' );
832 mStyle->
saveTextFormat( saveDlg.name(), format, saveDlg.isFavorite(), symbolTags );
837 void QgsStyleManagerDialog::setThumbnailSize(
int value )
842 const double spacing =
Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance(
'X' ) * ( value * 2.2 + 14 );
845 listItems->setIconSize( QSize(
static_cast< int >(
iconSize ),
static_cast< int >(
iconSize * 0.9 ) ) );
846 listItems->setGridSize( QSize(
static_cast< int >( spacing ),
static_cast< int >( verticalSpacing ) ) );
849 mModel->addDesiredIconSize( listItems->iconSize() );
855 int QgsStyleManagerDialog::selectedItemType()
857 QModelIndex index = listItems->selectionModel()->currentIndex();
858 if ( !index.isValid() )
876 bool QgsStyleManagerDialog::allTypesSelected()
const
878 return tabItemType->currentIndex() == 0;
881 bool QgsStyleManagerDialog::isReadOnly()
const
883 return mReadOnly || ( mStyle && mStyle->
isReadOnly() );
886 QList< QgsStyleManagerDialog::ItemDetails > QgsStyleManagerDialog::selectedItems()
888 QList<QgsStyleManagerDialog::ItemDetails > res;
889 QModelIndexList indices = listItems->selectionModel()->selectedRows();
890 for (
const QModelIndex &index : indices )
892 if ( !index.isValid() )
899 details.name = mModel->data( mModel->index( index.row(),
QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
906 int QgsStyleManagerDialog::copyItems(
const QList<QgsStyleManagerDialog::ItemDetails> &items,
QgsStyle *src,
QgsStyle *dst, QWidget *parentWidget,
907 std::unique_ptr< QgsTemporaryCursorOverride > &cursorOverride,
bool isImport,
const QStringList &importTags,
bool addToFavorites,
bool ignoreSourceTags )
910 bool overwriteAll =
true;
920 for (
auto &details : items )
922 QStringList symbolTags;
923 if ( !ignoreSourceTags )
925 symbolTags = src->
tagsOfSymbol( details.entityType, details.name );
928 bool addItemToFavorites =
false;
931 symbolTags << importTags;
932 addItemToFavorites = addToFavorites;
935 switch ( details.entityType )
939 std::unique_ptr< QgsSymbol > symbol( src->
symbol( details.name ) );
943 const bool hasDuplicateName = dst->
symbolNames().contains( details.name );
944 bool overwriteThis =
false;
946 addItemToFavorites = favoriteSymbols.contains( details.name );
948 if ( hasDuplicateName && prompt )
950 cursorOverride.reset();
951 int res = QMessageBox::warning( parentWidget, isImport ? tr(
"Import Symbol" ) : tr(
"Export Symbol" ),
952 tr(
"A symbol with the name “%1” already exists.\nOverwrite?" )
953 .arg( details.name ),
954 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
955 cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
958 case QMessageBox::Cancel:
961 case QMessageBox::No:
964 case QMessageBox::Yes:
965 overwriteThis =
true;
968 case QMessageBox::YesToAll:
973 case QMessageBox::NoToAll:
975 overwriteAll =
false;
980 if ( !hasDuplicateName || overwriteAll || overwriteThis )
983 dst->
addSymbol( details.name, symbol.release() );
984 dst->
saveSymbol( details.name, newSymbol, addItemToFavorites, symbolTags );
992 std::unique_ptr< QgsColorRamp > ramp( src->
colorRamp( details.name ) );
996 const bool hasDuplicateName = dst->
colorRampNames().contains( details.name );
997 bool overwriteThis =
false;
999 addItemToFavorites = favoriteColorramps.contains( details.name );
1001 if ( hasDuplicateName && prompt )
1003 cursorOverride.reset();
1004 int res = QMessageBox::warning( parentWidget, isImport ? tr(
"Import Color Ramp" ) : tr(
"Export Color Ramp" ),
1005 tr(
"A color ramp with the name “%1” already exists.\nOverwrite?" )
1006 .arg( details.name ),
1007 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
1008 cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
1011 case QMessageBox::Cancel:
1014 case QMessageBox::No:
1017 case QMessageBox::Yes:
1018 overwriteThis =
true;
1021 case QMessageBox::YesToAll:
1023 overwriteAll =
true;
1026 case QMessageBox::NoToAll:
1028 overwriteAll =
false;
1033 if ( !hasDuplicateName || overwriteAll || overwriteThis )
1037 dst->
saveColorRamp( details.name, newRamp, addItemToFavorites, symbolTags );
1047 const bool hasDuplicateName = dst->
textFormatNames().contains( details.name );
1048 bool overwriteThis =
false;
1050 addItemToFavorites = favoriteTextFormats.contains( details.name );
1052 if ( hasDuplicateName && prompt )
1054 cursorOverride.reset();
1055 int res = QMessageBox::warning( parentWidget, isImport ? tr(
"Import Text Format" ) : tr(
"Export Text Format" ),
1056 tr(
"A text format with the name “%1” already exists.\nOverwrite?" )
1057 .arg( details.name ),
1058 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
1059 cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
1062 case QMessageBox::Cancel:
1065 case QMessageBox::No:
1068 case QMessageBox::Yes:
1069 overwriteThis =
true;
1072 case QMessageBox::YesToAll:
1074 overwriteAll =
true;
1077 case QMessageBox::NoToAll:
1079 overwriteAll =
false;
1084 if ( !hasDuplicateName || overwriteAll || overwriteThis )
1087 dst->
saveTextFormat( details.name, format, addItemToFavorites, symbolTags );
1098 bool overwriteThis =
false;
1100 addItemToFavorites = favoriteLabelSettings.contains( details.name );
1102 if ( hasDuplicateName && prompt )
1104 cursorOverride.reset();
1105 int res = QMessageBox::warning( parentWidget, isImport ? tr(
"Import Label Settings" ) : tr(
"Export Label Settings" ),
1106 tr(
"Label settings with the name “%1” already exist.\nOverwrite?" )
1107 .arg( details.name ),
1108 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
1109 cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
1112 case QMessageBox::Cancel:
1115 case QMessageBox::No:
1118 case QMessageBox::Yes:
1119 overwriteThis =
true;
1122 case QMessageBox::YesToAll:
1124 overwriteAll =
true;
1127 case QMessageBox::NoToAll:
1129 overwriteAll =
false;
1134 if ( !hasDuplicateName || overwriteAll || overwriteThis )
1137 dst->
saveLabelSettings( details.name, settings, addItemToFavorites, symbolTags );
1148 bool overwriteThis =
false;
1150 addItemToFavorites = favoriteLegendPatchShapes.contains( details.name );
1152 if ( hasDuplicateName && prompt )
1154 cursorOverride.reset();
1155 int res = QMessageBox::warning( parentWidget, isImport ? tr(
"Import Legend Patch Shape" ) : tr(
"Export Legend Patch Shape" ),
1156 tr(
"Legend patch shape with the name “%1” already exist.\nOverwrite?" )
1157 .arg( details.name ),
1158 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
1159 cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
1162 case QMessageBox::Cancel:
1165 case QMessageBox::No:
1168 case QMessageBox::Yes:
1169 overwriteThis =
true;
1172 case QMessageBox::YesToAll:
1174 overwriteAll =
true;
1177 case QMessageBox::NoToAll:
1179 overwriteAll =
false;
1184 if ( !hasDuplicateName || overwriteAll || overwriteThis )
1195 std::unique_ptr< QgsAbstract3DSymbol > symbol( src->
symbol3D( details.name ) );
1199 const bool hasDuplicateName = dst->
symbol3DNames().contains( details.name );
1200 bool overwriteThis =
false;
1202 addItemToFavorites = favorite3dSymbols.contains( details.name );
1204 if ( hasDuplicateName && prompt )
1206 cursorOverride.reset();
1207 int res = QMessageBox::warning( parentWidget, isImport ? tr(
"Import 3D Symbol" ) : tr(
"Export 3D Symbol" ),
1208 tr(
"A 3D symbol with the name “%1” already exists.\nOverwrite?" )
1209 .arg( details.name ),
1210 QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel );
1211 cursorOverride = std::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
1214 case QMessageBox::Cancel:
1217 case QMessageBox::No:
1220 case QMessageBox::Yes:
1221 overwriteThis =
true;
1224 case QMessageBox::YesToAll:
1226 overwriteAll =
true;
1229 case QMessageBox::NoToAll:
1231 overwriteAll =
false;
1236 if ( !hasDuplicateName || overwriteAll || overwriteThis )
1239 dst->
addSymbol3D( details.name, symbol.release() );
1240 dst->
saveSymbol3D( details.name, newSymbol, addItemToFavorites, symbolTags );
1255 bool QgsStyleManagerDialog::addTextFormat()
1259 formatDlg.setWindowTitle( tr(
"New Text Format" ) );
1260 if ( !formatDlg.exec() )
1262 format = formatDlg.format();
1265 const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data(
GroupModelRoles::TagName ).toString() : QString();
1266 saveDlg.setDefaultTags( defaultTag );
1267 if ( !saveDlg.exec() )
1269 QString name = saveDlg.name();
1272 bool nameInvalid =
true;
1273 while ( nameInvalid )
1276 if ( name.isEmpty() )
1278 QMessageBox::warning(
this, tr(
"Save Text Format" ),
1279 tr(
"Cannot save text format without name. Enter a name." ) );
1283 int res = QMessageBox::warning(
this, tr(
"Save Text Format" ),
1284 tr(
"Text format with name '%1' already exists. Overwrite?" )
1286 QMessageBox::Yes | QMessageBox::No );
1287 if ( res == QMessageBox::Yes )
1290 nameInvalid =
false;
1296 nameInvalid =
false;
1301 name = QInputDialog::getText(
this, tr(
"Text Format Name" ),
1302 tr(
"Please enter a name for new text format:" ),
1303 QLineEdit::Normal, name, &ok );
1311 QStringList symbolTags = saveDlg.tags().split(
',' );
1315 mStyle->
saveTextFormat( name, format, saveDlg.isFavorite(), symbolTags );
1323 groupChanged( groupTree->selectionModel()->currentIndex() );
1336 switch ( tabItemType->currentIndex() )
1361 QModelIndex index = listItems->selectionModel()->currentIndex();
1362 if ( !index.isValid() )
1365 return mModel->data( mModel->index( index.row(),
QgsStyleModel::Name, index.parent() ), Qt::DisplayRole ).toString();
1370 bool changed =
false;
1381 changed = addTextFormat();
1400 Q_ASSERT(
false &&
"not implemented" );
1413 QString name = tr(
"new symbol" );
1414 QString dialogTitle;
1419 name = tr(
"new marker" );
1420 dialogTitle = tr(
"New Marker Symbol" );
1424 name = tr(
"new line" );
1425 dialogTitle = tr(
"New Line Symbol" );
1429 name = tr(
"new fill symbol" );
1430 dialogTitle = tr(
"New Fill Symbol" );
1433 Q_ASSERT(
false &&
"unknown symbol type" );
1443 dlg.setWindowTitle( dialogTitle );
1444 if ( dlg.exec() == 0 )
1450 QgsStyleSaveDialog saveDlg(
this );
1451 const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data(
GroupModelRoles::TagName ).toString() : QString();
1452 saveDlg.setDefaultTags( defaultTag );
1453 if ( !saveDlg.exec() )
1459 name = saveDlg.name();
1462 bool nameInvalid =
true;
1463 while ( nameInvalid )
1466 if ( name.isEmpty() )
1468 QMessageBox::warning(
this, tr(
"Save Symbol" ),
1469 tr(
"Cannot save symbol without name. Enter a name." ) );
1471 else if ( mStyle->
symbolNames().contains( name ) )
1473 int res = QMessageBox::warning(
this, tr(
"Save Symbol" ),
1474 tr(
"Symbol with name '%1' already exists. Overwrite?" )
1476 QMessageBox::Yes | QMessageBox::No );
1477 if ( res == QMessageBox::Yes )
1480 nameInvalid =
false;
1486 nameInvalid =
false;
1491 name = QInputDialog::getText(
this, tr(
"Symbol Name" ),
1492 tr(
"Please enter a name for new symbol:" ),
1493 QLineEdit::Normal, name, &ok );
1502 QStringList symbolTags = saveDlg.tags().split(
',' );
1506 mStyle->
saveSymbol( name, symbol, saveDlg.isFavorite(), symbolTags );
1515 QString rampType = type;
1517 if ( rampType.isEmpty() )
1522 QStringList rampTypeNames;
1523 rampTypeNames.reserve( rampTypes.size() );
1524 for (
const QPair< QString, QString > &type : rampTypes )
1525 rampTypeNames << type.second;
1526 const QString selectedRampTypeName = QInputDialog::getItem( parent, tr(
"Color Ramp Type" ),
1527 tr(
"Please select color ramp type:" ), rampTypeNames, 0,
false, &ok );
1528 if ( !ok || selectedRampTypeName.isEmpty() )
1531 rampType = rampTypes.value( rampTypeNames.indexOf( selectedRampTypeName ) ).first;
1534 QString name = tr(
"new ramp" );
1536 std::unique_ptr< QgsColorRamp > ramp;
1540 dlg.setWindowTitle( tr(
"New Gradient Color Ramp" ) );
1546 name = tr(
"new gradient ramp" );
1551 dlg.setWindowTitle( tr(
"New Random Color Ramp" ) );
1557 name = tr(
"new random ramp" );
1562 dlg.setWindowTitle( tr(
"New ColorBrewer Ramp" ) );
1573 dlg.setWindowTitle( tr(
"New Preset Color Ramp" ) );
1579 name = tr(
"new preset ramp" );
1584 dlg.setWindowTitle( tr(
"New cpt-city Color Ramp" ) );
1604 QgsDebugMsg( QStringLiteral(
"invalid ramp type %1" ).arg( rampType ) );
1609 if ( !saveDlg.exec() )
1614 name = saveDlg.name();
1617 bool nameInvalid =
true;
1618 while ( nameInvalid )
1621 if ( name.isEmpty() )
1623 QMessageBox::warning( parent, tr(
"Save Color Ramp" ),
1624 tr(
"Cannot save color ramp without name. Enter a name." ) );
1628 int res = QMessageBox::warning( parent, tr(
"Save Color Ramp" ),
1629 tr(
"Color ramp with name '%1' already exists. Overwrite?" )
1631 QMessageBox::Yes | QMessageBox::No );
1632 if ( res == QMessageBox::Yes )
1634 nameInvalid =
false;
1640 nameInvalid =
false;
1645 name = QInputDialog::getText( parent, tr(
"Color Ramp Name" ),
1646 tr(
"Please enter a name for new color ramp:" ),
1647 QLineEdit::Normal, name, &ok );
1655 QStringList colorRampTags = saveDlg.tags().split(
',' );
1660 style->
saveColorRamp( name, r, saveDlg.isFavorite(), colorRampTags );
1667 mFavoritesGroupVisible = show;
1673 mSmartGroupVisible = show;
1685 setWindowState( windowState() & ~Qt::WindowMinimized );
1693 if ( !rampName.isEmpty() )
1705 if ( selectedItemType() < 3 )
1709 else if ( selectedItemType() == 3 )
1713 else if ( selectedItemType() == 4 )
1717 else if ( selectedItemType() == 5 )
1719 editLabelSettings();
1721 else if ( selectedItemType() == 6 )
1723 editLegendPatchShape();
1725 else if ( selectedItemType() == 7 )
1731 Q_ASSERT(
false &&
"not implemented" );
1738 if ( symbolName.isEmpty() )
1741 std::unique_ptr< QgsSymbol > symbol( mStyle->
symbol( symbolName ) );
1745 dlg.setWindowTitle( symbolName );
1747 dlg.
buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1753 mStyle->
addSymbol( symbolName, symbol.release(),
true );
1761 if ( name.isEmpty() )
1764 std::unique_ptr< QgsColorRamp > ramp( mStyle->
colorRamp( name ) );
1770 dlg.setWindowTitle( name );
1772 dlg.
buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1784 dlg.setWindowTitle( name );
1786 dlg.
buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1798 dlg.setWindowTitle( name );
1800 dlg.
buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1812 dlg.setWindowTitle( name );
1814 dlg.
buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1826 dlg.setWindowTitle( name );
1828 dlg.
buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1845 Q_ASSERT(
false &&
"invalid ramp type" );
1853 bool QgsStyleManagerDialog::editTextFormat()
1856 if ( formatName.isEmpty() )
1863 dlg.setWindowTitle( formatName );
1865 dlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1879 QgsLabelSettingsDialog settingsDlg( settings,
nullptr,
nullptr,
this, type );
1880 settingsDlg.setWindowTitle( tr(
"New Label Settings" ) );
1882 settingsDlg.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1884 if ( !settingsDlg.exec() )
1887 settings = settingsDlg.settings();
1891 const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data(
GroupModelRoles::TagName ).toString() : QString();
1892 saveDlg.setDefaultTags( defaultTag );
1893 if ( !saveDlg.exec() )
1895 QString name = saveDlg.name();
1898 bool nameInvalid =
true;
1899 while ( nameInvalid )
1902 if ( name.isEmpty() )
1904 QMessageBox::warning(
this, tr(
"Save Label Settings" ),
1905 tr(
"Cannot save label settings without a name. Enter a name." ) );
1909 int res = QMessageBox::warning(
this, tr(
"Save Label Settings" ),
1910 tr(
"Label settings with the name '%1' already exist. Overwrite?" )
1912 QMessageBox::Yes | QMessageBox::No );
1913 if ( res == QMessageBox::Yes )
1916 nameInvalid =
false;
1922 nameInvalid =
false;
1927 name = QInputDialog::getText(
this, tr(
"Label Settings Name" ),
1928 tr(
"Please enter a name for the new label settings:" ),
1929 QLineEdit::Normal, name, &ok );
1937 QStringList symbolTags = saveDlg.tags().split(
',' );
1947 bool QgsStyleManagerDialog::editLabelSettings()
1950 if ( formatName.isEmpty() )
1957 QgsLabelSettingsDialog dlg( settings,
nullptr,
nullptr,
this, geomType );
1958 dlg.setWindowTitle( formatName );
1962 settings = dlg.settings();
1975 dialog.setWindowTitle( tr(
"New Legend Patch Shape" ) );
1977 dialog.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
1979 if ( !dialog.exec() )
1982 shape = dialog.shape();
1985 const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data(
GroupModelRoles::TagName ).toString() : QString();
1986 saveDlg.setDefaultTags( defaultTag );
1987 if ( !saveDlg.exec() )
1989 QString name = saveDlg.name();
1992 bool nameInvalid =
true;
1993 while ( nameInvalid )
1996 if ( name.isEmpty() )
1998 QMessageBox::warning(
this, tr(
"Save Legend Patch Shape" ),
1999 tr(
"Cannot save legend patch shapes without a name. Enter a name." ) );
2003 int res = QMessageBox::warning(
this, tr(
"Save Legend Patch Shape" ),
2004 tr(
"A legend patch shape with the name '%1' already exists. Overwrite?" )
2006 QMessageBox::Yes | QMessageBox::No );
2007 if ( res == QMessageBox::Yes )
2010 nameInvalid =
false;
2016 nameInvalid =
false;
2021 name = QInputDialog::getText(
this, tr(
"Legend Patch Shape Name" ),
2022 tr(
"Please enter a name for the new legend patch shape:" ),
2023 QLineEdit::Normal, name, &ok );
2031 QStringList symbolTags = saveDlg.tags().split(
',' );
2041 bool QgsStyleManagerDialog::editLegendPatchShape()
2044 if ( shapeName.isEmpty() )
2053 dlg.setWindowTitle( shapeName );
2057 shape = dlg.shape();
2065 bool QgsStyleManagerDialog::addSymbol3D(
const QString &type )
2072 dialog.setWindowTitle( tr(
"New 3D Symbol" ) );
2074 dialog.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled(
false );
2076 if ( !dialog.exec() )
2079 symbol.reset( dialog.symbol() );
2084 const QString defaultTag = groupTree->currentIndex().isValid() ? groupTree->currentIndex().data(
GroupModelRoles::TagName ).toString() : QString();
2085 saveDlg.setDefaultTags( defaultTag );
2086 if ( !saveDlg.exec() )
2088 QString name = saveDlg.name();
2091 bool nameInvalid =
true;
2092 while ( nameInvalid )
2095 if ( name.isEmpty() )
2097 QMessageBox::warning(
this, tr(
"Save 3D Symbol" ),
2098 tr(
"Cannot save 3D symbols without a name. Enter a name." ) );
2102 int res = QMessageBox::warning(
this, tr(
"Save 3D Symbol" ),
2103 tr(
"A 3D symbol with the name '%1' already exists. Overwrite?" )
2105 QMessageBox::Yes | QMessageBox::No );
2106 if ( res == QMessageBox::Yes )
2109 nameInvalid =
false;
2115 nameInvalid =
false;
2120 name = QInputDialog::getText(
this, tr(
"3D Symbol Name" ),
2121 tr(
"Please enter a name for the new 3D symbol:" ),
2122 QLineEdit::Normal, name, &ok );
2130 QStringList symbolTags = saveDlg.tags().split(
',' );
2135 mStyle->
saveSymbol3D( name, newSymbol, saveDlg.isFavorite(), symbolTags );
2141 bool QgsStyleManagerDialog::editSymbol3D()
2144 if ( symbolName.isEmpty() )
2147 std::unique_ptr< QgsAbstract3DSymbol > symbol( mStyle->
symbol3D( symbolName ) );
2153 dlg.setWindowTitle( symbolName );
2157 symbol.reset( dlg.symbol() );
2162 mStyle->
addSymbol3D( symbolName, symbol.release(),
true );
2167 void QgsStyleManagerDialog::addStyleDatabase(
bool createNew )
2170 if ( initialFolder.isEmpty() )
2171 initialFolder = QDir::homePath();
2173 QString databasePath = createNew
2174 ? QFileDialog::getSaveFileName(
2176 tr(
"Create Style Database" ),
2178 tr(
"Style databases" ) +
" (*.db)" )
2179 : QFileDialog::getOpenFileName(
2181 tr(
"Add Style Database" ),
2183 tr(
"Style databases" ) +
" (*.db *.xml)" );
2184 if ( ! databasePath.isEmpty() )
2191 if ( QFile::exists( databasePath ) )
2193 QFile::remove( databasePath );
2198 QMessageBox::warning(
this, tr(
"Create Style Database" ), tr(
"The style database could not be created" ) );
2210 const QList< ItemDetails > items = selectedItems();
2212 if ( allTypesSelected() )
2214 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove Items" ),
2215 QString( tr(
"Do you really want to remove %n item(s)?",
nullptr, items.count() ) ),
2224 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove Symbol" ),
2225 QString( tr(
"Do you really want to remove %n symbol(s)?",
nullptr, items.count() ) ),
2232 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove Color Ramp" ),
2233 QString( tr(
"Do you really want to remove %n ramp(s)?",
nullptr, items.count() ) ),
2240 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove Text Formats" ),
2241 QString( tr(
"Do you really want to remove %n text format(s)?",
nullptr, items.count() ) ),
2248 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove Label Settings" ),
2249 QString( tr(
"Do you really want to remove %n label setting(s)?",
nullptr, items.count() ) ),
2256 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove Legend Patch Shapes" ),
2257 QString( tr(
"Do you really want to remove %n legend patch shape(s)?",
nullptr, items.count() ) ),
2264 if ( QMessageBox::Yes != QMessageBox::question(
this, tr(
"Remove 3D Symbols" ),
2265 QString( tr(
"Do you really want to remove %n 3D symbol(s)?",
nullptr, items.count() ) ),
2274 for (
const ItemDetails &details : items )
2276 if ( details.name.isEmpty() )
2301 QString dir = QFileDialog::getExistingDirectory(
this, tr(
"Export Selected Symbols as PNG" ),
2302 QDir::home().absolutePath(),
2303 QFileDialog::DontResolveSymlinks );
2309 QString dir = QFileDialog::getExistingDirectory(
this, tr(
"Export Selected Symbols as SVG" ),
2310 QDir::home().absolutePath(),
2311 QFileDialog::DontResolveSymlinks );
2318 if ( dir.isEmpty() )
2321 const QList< ItemDetails > items = selectedItems();
2322 for (
const ItemDetails &details : items )
2327 QString path = dir +
'/' + details.name +
'.' + format;
2328 std::unique_ptr< QgsSymbol > sym( mStyle->
symbol( details.name ) );
2330 sym->exportImage( path, format, size );
2350 QFont font = item->font();
2351 font.setBold(
true );
2352 item->setFont( font );
2357 if ( mBlockGroupUpdates )
2360 QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
2363 const bool readOnly = isReadOnly();
2365 if ( mFavoritesGroupVisible )
2367 QStandardItem *favoriteSymbols =
new QStandardItem( tr(
"Favorites" ) );
2368 favoriteSymbols->setData(
"favorite" );
2369 favoriteSymbols->setEditable(
false );
2371 model->appendRow( favoriteSymbols );
2374 QStandardItem *allSymbols =
new QStandardItem( tr(
"All" ) );
2375 allSymbols->setData(
"all" );
2376 allSymbols->setEditable(
false );
2378 model->appendRow( allSymbols );
2380 QStandardItem *taggroup =
new QStandardItem( QString() );
2381 taggroup->setData(
"tags" );
2382 taggroup->setEditable(
false );
2383 QStringList tags = mStyle->
tags();
2385 for (
const QString &tag : std::as_const( tags ) )
2387 QStandardItem *item =
new QStandardItem( tag );
2388 item->setData( mStyle->
tagId( tag ) );
2390 item->setEditable( !readOnly );
2391 taggroup->appendRow( item );
2393 taggroup->setText( tr(
"Tags" ) );
2395 model->appendRow( taggroup );
2397 if ( mSmartGroupVisible )
2399 QStandardItem *smart =
new QStandardItem( tr(
"Smart Groups" ) );
2400 smart->setData(
"smartgroups" );
2401 smart->setEditable(
false );
2404 QgsSymbolGroupMap::const_iterator i = sgMap.constBegin();
2405 while ( i != sgMap.constEnd() )
2407 QStandardItem *item =
new QStandardItem( i.value() );
2408 item->setData( i.key() );
2409 item->setEditable( !readOnly );
2410 smart->appendRow( item );
2413 model->appendRow( smart );
2417 int rows = model->rowCount( model->indexFromItem( model->invisibleRootItem() ) );
2418 for (
int i = 0; i < rows; i++ )
2420 groupTree->setExpanded( model->indexFromItem( model->item( i ) ),
true );
2426 QStringList groupSymbols;
2428 const QString category = index.data( Qt::UserRole + 1 ).toString();
2429 sPreviousTag = category;
2431 const bool readOnly = isReadOnly();
2433 if ( mGroupingMode && mModel )
2435 mModel->setTagId( -1 );
2436 mModel->setSmartGroupId( -1 );
2437 mModel->setFavoritesOnly(
false );
2438 mModel->setCheckTag( index.data( Qt::DisplayRole ).toString() );
2440 else if ( category == QLatin1String(
"all" ) || category == QLatin1String(
"tags" ) || category == QLatin1String(
"smartgroups" ) )
2443 if ( category == QLatin1String(
"tags" ) )
2445 actnAddTag->setEnabled( !readOnly );
2446 actnAddSmartgroup->setEnabled(
false );
2448 else if ( category == QLatin1String(
"smartgroups" ) )
2450 actnAddTag->setEnabled(
false );
2451 actnAddSmartgroup->setEnabled( !readOnly );
2456 mModel->setTagId( -1 );
2457 mModel->setSmartGroupId( -1 );
2458 mModel->setFavoritesOnly(
false );
2461 else if ( category == QLatin1String(
"favorite" ) )
2464 mModel->setTagId( -1 );
2465 mModel->setSmartGroupId( -1 );
2466 mModel->setFavoritesOnly(
true );
2468 else if ( index.parent().data( Qt::UserRole + 1 ) ==
"smartgroups" )
2470 actnRemoveGroup->setEnabled( !readOnly );
2471 btnManageGroups->setEnabled( !readOnly );
2472 const int groupId = index.data( Qt::UserRole + 1 ).toInt();
2475 mModel->setTagId( -1 );
2476 mModel->setSmartGroupId( groupId );
2477 mModel->setFavoritesOnly(
false );
2483 int tagId = index.data( Qt::UserRole + 1 ).toInt();
2486 mModel->setTagId( tagId );
2487 mModel->setSmartGroupId( -1 );
2488 mModel->setFavoritesOnly(
false );
2492 actnEditSmartGroup->setVisible(
false );
2493 actnAddTag->setVisible(
false );
2494 actnAddSmartgroup->setVisible(
false );
2495 actnRemoveGroup->setVisible(
false );
2496 actnTagSymbols->setVisible(
false );
2497 actnFinishTagging->setVisible(
false );
2499 if ( index.parent().isValid() )
2501 if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String(
"smartgroups" ) )
2503 actnEditSmartGroup->setVisible( !mGroupingMode && !readOnly );
2505 else if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String(
"tags" ) )
2507 actnAddTag->setVisible( !mGroupingMode && !readOnly );
2508 actnTagSymbols->setVisible( !mGroupingMode && !readOnly );
2509 actnFinishTagging->setVisible( mGroupingMode && !readOnly );
2511 actnRemoveGroup->setVisible( !readOnly );
2513 else if ( index.data( Qt::UserRole + 1 ) ==
"smartgroups" )
2515 actnAddSmartgroup->setVisible( !mGroupingMode && !readOnly );
2517 else if ( index.data( Qt::UserRole + 1 ) ==
"tags" )
2519 actnAddTag->setVisible( !mGroupingMode && !readOnly );
2528 QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
2530 for (
int i = 0; i < groupTree->model()->rowCount(); i++ )
2532 index = groupTree->model()->index( i, 0 );
2533 QString data = index.data( Qt::UserRole + 1 ).toString();
2534 if ( data == QLatin1String(
"tags" ) )
2543 itemName = QInputDialog::getText(
this, tr(
"Add Tag" ),
2544 tr(
"Please enter name for the new tag:" ), QLineEdit::Normal, tr(
"New tag" ), &ok ).trimmed();
2545 if ( !ok || itemName.isEmpty() )
2548 int check = mStyle->
tagId( itemName );
2551 mMessageBar->pushCritical( tr(
"Add Tag" ), tr(
"The tag “%1” already exists." ).arg( itemName ) );
2557 mBlockGroupUpdates++;
2558 id = mStyle->
addTag( itemName );
2559 mBlockGroupUpdates--;
2563 mMessageBar->pushCritical( tr(
"Add Tag" ), tr(
"New tag could not be created — There was a problem with the symbol database." ) );
2567 QStandardItem *parentItem = model->itemFromIndex( index );
2568 QStandardItem *childItem =
new QStandardItem( itemName );
2569 childItem->setData(
id );
2571 parentItem->appendRow( childItem );
2581 QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
2583 for (
int i = 0; i < groupTree->model()->rowCount(); i++ )
2585 index = groupTree->model()->index( i, 0 );
2586 QString data = index.data( Qt::UserRole + 1 ).toString();
2587 if ( data == QLatin1String(
"smartgroups" ) )
2596 if ( dlg.exec() == QDialog::Rejected )
2601 mBlockGroupUpdates++;
2603 mBlockGroupUpdates--;
2609 QStandardItem *parentItem = model->itemFromIndex( index );
2610 QStandardItem *childItem =
new QStandardItem( itemName );
2611 childItem->setData(
id );
2612 parentItem->appendRow( childItem );
2622 QStandardItemModel *model = qobject_cast<QStandardItemModel *>( groupTree->model() );
2623 QModelIndex index = groupTree->currentIndex();
2626 QString data = index.data( Qt::UserRole + 1 ).toString();
2627 if ( data == QLatin1String(
"all" ) || data == QLatin1String(
"favorite" ) || data == QLatin1String(
"tags" ) || index.data() ==
"smartgroups" )
2630 int err = QMessageBox::critical(
this, tr(
"Remove Group" ),
2631 tr(
"Invalid selection. Cannot delete system defined categories.\n"
2632 "Kindly select a group or smart group you might want to delete." ) );
2637 QStandardItem *parentItem = model->itemFromIndex( index.parent() );
2641 mBlockGroupUpdates++;
2643 if ( parentItem->data( Qt::UserRole + 1 ).toString() == QLatin1String(
"smartgroups" ) )
2652 mBlockGroupUpdates--;
2653 parentItem->removeRow( index.row() );
2661 QgsDebugMsg( QStringLiteral(
"Symbol group edited: data=%1 text=%2" ).arg( item->data( Qt::UserRole + 1 ).toString(), item->text() ) );
2662 int id = item->data( Qt::UserRole + 1 ).toInt();
2663 QString name = item->text();
2664 mBlockGroupUpdates++;
2665 if ( item->parent()->data( Qt::UserRole + 1 ) ==
"smartgroups" )
2673 mBlockGroupUpdates--;
2681 QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
2683 if ( mGroupingMode )
2685 mGroupingMode =
false;
2686 mModel->setCheckable(
false );
2687 actnTagSymbols->setVisible(
true );
2688 actnFinishTagging->setVisible(
false );
2696 connect( treeModel, &QStandardItemModel::itemChanged,
2700 listItems->setSelectionMode( QAbstractItemView::ExtendedSelection );
2701 mSymbolTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection );
2705 bool validGroup =
false;
2707 QModelIndex present = groupTree->currentIndex();
2708 while ( present.parent().isValid() )
2710 if ( present.parent().data() ==
"Tags" )
2715 present = present.parent();
2720 mGroupingMode =
true;
2722 actnTagSymbols->setVisible(
false );
2723 actnFinishTagging->setVisible(
true );
2725 disconnect( treeModel, &QStandardItemModel::itemChanged,
2731 btnManageGroups->setEnabled(
true );
2733 mModel->setCheckable(
true );
2736 listItems->setSelectionMode( QAbstractItemView::NoSelection );
2737 mSymbolTreeView->setSelectionMode( QAbstractItemView::NoSelection );
2751 mModel->setFilterString( qword );
2756 actnEditItem->setEnabled( index.isValid() && !mGroupingMode && !isReadOnly() );
2761 Q_UNUSED( selected )
2762 Q_UNUSED( deselected )
2763 const bool nothingSelected = listItems->selectionModel()->selectedIndexes().empty();
2764 const bool readOnly = isReadOnly();
2765 actnRemoveItem->setDisabled( nothingSelected || readOnly );
2766 actnAddFavorite->setDisabled( nothingSelected || readOnly );
2767 actnRemoveFavorite->setDisabled( nothingSelected || readOnly );
2768 mGroupListMenu->setDisabled( nothingSelected || readOnly );
2769 actnDetag->setDisabled( nothingSelected || readOnly );
2770 actnExportAsPNG->setDisabled( nothingSelected );
2771 actnExportAsSVG->setDisabled( nothingSelected );
2772 if ( mActionCopyToDefault )
2773 mActionCopyToDefault->setDisabled( nothingSelected );
2774 mCopyToDefaultButton->setDisabled( nothingSelected );
2775 actnEditItem->setDisabled( nothingSelected || readOnly );
2780 const bool readOnly = isReadOnly();
2781 groupTree->setEnabled( enable );
2782 btnAddTag->setEnabled( enable && !readOnly );
2783 btnAddSmartgroup->setEnabled( enable && !readOnly );
2784 actnAddTag->setEnabled( enable && !readOnly );
2785 actnAddSmartgroup->setEnabled( enable && !readOnly );
2786 actnRemoveGroup->setEnabled( enable && !readOnly );
2787 btnManageGroups->setEnabled( !readOnly && ( enable || mGroupingMode ) );
2788 searchBox->setEnabled( enable );
2793 const bool readOnly = isReadOnly();
2794 actnRemoveGroup->setEnabled( enable && !readOnly );
2795 btnManageGroups->setEnabled( !readOnly && ( enable || mGroupingMode ) );
2800 QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
2801 for (
int i = 0; i < treeModel->rowCount(); i++ )
2803 treeModel->item( i )->setEnabled( enable );
2805 if ( treeModel->item( i )->data() ==
"smartgroups" )
2807 for (
int j = 0; j < treeModel->item( i )->rowCount(); j++ )
2809 treeModel->item( i )->child( j )->setEnabled( enable );
2816 for (
int i = 0; i < symbolBtnsLayout->count(); i++ )
2818 QWidget *w = symbolBtnsLayout->itemAt( i )->widget();
2820 w->setEnabled( enable );
2824 actnRemoveItem->setEnabled( enable );
2825 actnEditItem->setEnabled( enable );
2826 mActionCopyItem->setEnabled( enable );
2827 mActionPasteItem->setEnabled( enable );
2832 QPoint globalPos = groupTree->viewport()->mapToGlobal( point );
2834 QModelIndex index = groupTree->indexAt( point );
2835 if ( index.isValid() && !mGroupingMode )
2836 mGroupTreeContextMenu->popup( globalPos );
2841 QPoint globalPos = mSymbolViewStackedWidget->currentIndex() == 0
2842 ? listItems->viewport()->mapToGlobal( point )
2843 : mSymbolTreeView->viewport()->mapToGlobal( point );
2846 mGroupListMenu->clear();
2848 const QModelIndexList indices = listItems->selectionModel()->selectedRows();
2850 if ( !isReadOnly() )
2852 const QStringList currentTags = indices.count() == 1 ? indices.at( 0 ).data(
QgsStyleModel::TagRole ).toStringList() : QStringList();
2853 QAction *a =
nullptr;
2854 QStringList tags = mStyle->
tags();
2856 for (
const QString &tag : std::as_const( tags ) )
2858 a =
new QAction( tag, mGroupListMenu );
2860 if ( indices.count() == 1 )
2862 a->setCheckable(
true );
2863 a->setChecked( currentTags.contains( tag ) );
2867 mGroupListMenu->addAction( a );
2870 if ( tags.count() > 0 )
2872 mGroupListMenu->addSeparator();
2874 a =
new QAction( tr(
"Create New Tag…" ), mGroupListMenu );
2877 mGroupListMenu->addAction( a );
2880 const QList< ItemDetails > items = selectedItems();
2883 bool enablePaste =
false;
2891 mActionPasteItem->setEnabled( enablePaste );
2893 mGroupMenu->popup( globalPos );
2901 const QList< ItemDetails > items = selectedItems();
2902 for (
const ItemDetails &details : items )
2904 mStyle->
addFavorite( details.entityType, details.name );
2913 const QList< ItemDetails > items = selectedItems();
2914 for (
const ItemDetails &details : items )
2922 QAction *selectedItem = qobject_cast<QAction *>( sender() );
2925 const QList< ItemDetails > items = selectedItems();
2935 tag = mStyle->
tag(
id );
2939 tag = selectedItem->data().toString();
2942 for (
const ItemDetails &details : items )
2944 mStyle->
tagSymbol( details.entityType, details.name, QStringList( tag ) );
2954 QAction *selectedItem = qobject_cast<QAction *>( sender() );
2958 const QList< ItemDetails > items = selectedItems();
2959 for (
const ItemDetails &details : items )
2961 mStyle->
detagSymbol( details.entityType, details.name );
2971 QStandardItemModel *treeModel = qobject_cast<QStandardItemModel *>( groupTree->model() );
2974 QModelIndex present = groupTree->currentIndex();
2975 if ( present.parent().data( Qt::UserRole + 1 ) !=
"smartgroups" )
2978 QMessageBox::critical(
this, tr(
"Edit Smart Group" ),
2979 tr(
"You have not selected a Smart Group. Kindly select a Smart Group to edit." ) );
2982 QStandardItem *item = treeModel->itemFromIndex( present );
2990 if ( dlg.exec() == QDialog::Rejected )
2993 mBlockGroupUpdates++;
2996 mBlockGroupUpdates--;
2999 mMessageBar->pushCritical( tr(
"Edit Smart Group" ), tr(
"There was an error while editing the smart group." ) );
3003 item->setData(
id );