From 13a0e48a26673711ad484b6a39771021cc676dcb Mon Sep 17 00:00:00 2001 From: nirvn Date: Fri, 18 Nov 2016 08:26:49 +0700 Subject: [PATCH 1/3] [style manager] improve UI - create a dedicated set of buttons for addition of tags and smartgroups to make those actions more visible as well as getting rid of th need to select a tag/smartgroup to create those (turns out to be quite confusing for newcomers) - move UI elements around, regroup {add,remove,edit} symbol buttons to harmonize with other parts of QGIS; the elements' placement feels much more natural now --- images/images.qrc | 2 +- images/themes/default/styleicons/color.png | Bin 1179 -> 0 bytes images/themes/default/styleicons/color.svg | 608 ++++++++++++++++++ python/core/symbology-ng/qgsstyle.sip | 3 + .../symbology-ng/qgsstylemanagerdialog.sip | 8 +- src/core/symbology-ng/qgsstyle.cpp | 21 + src/core/symbology-ng/qgsstyle.h | 3 + .../symbology-ng/qgsstylemanagerdialog.cpp | 226 ++++--- src/gui/symbology-ng/qgsstylemanagerdialog.h | 8 +- src/ui/qgsprojectpropertiesbase.ui | 8 +- src/ui/qgsstylemanagerdialogbase.ui | 183 +++--- 11 files changed, 867 insertions(+), 203 deletions(-) delete mode 100644 images/themes/default/styleicons/color.png create mode 100644 images/themes/default/styleicons/color.svg diff --git a/images/images.qrc b/images/images.qrc index 752e9d61041..49a8f09be12 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -492,7 +492,7 @@ themes/default/scale_bar.png themes/default/stars_empty.png themes/default/stars_full.png - themes/default/styleicons/color.png + themes/default/styleicons/color.svg themes/default/styleicons/style-line.png themes/default/styleicons/style-point.png themes/default/styleicons/style-polygon.png diff --git a/images/themes/default/styleicons/color.png b/images/themes/default/styleicons/color.png deleted file mode 100644 index d1077f6a8114296507d7d6b9c32e207064827be6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1179 zcmV;M1Z4Y(P)XNm-$?D={U;~?EuCNDc(!%E2w6!G5 zb1n~e$@#*CU2^GNVhdwm_`mtzkMH+${C{`%JA~(Xc$`8XYx)xpV6)lkX__`{#sjIP z2L?at>(Nqdm%_+dagw+4EOc~p2Ew3$zmg32!!gu%cL}*ReB#1yTMF>zu|sBKXL`)^ zd};tA3wUuq8^Pff#thb$M;`GcWZfRrdG!WvA0KxFHx2OK>E0u{XHz5fO_|p6Yn1?s zn!AlG{BaW*eb+vHR?1(p2VOni_w)7_qu*Bwms966eA_^8;moJQebfI7;N{`o*Ml8V zdhVC{wE|abJOIl9{5r*~_U~MyPY=Cxq$U8{psgWGrH|)H4i7fPcX_9E%e6qT9KiWA z%<>DS^<8yDo_MYyK631xL*}XhQZ3Q3?2dFB001BWq2@T{ovIF^7~W%Ar%>d--e}gQ zTRRQ$v8n(L+v$VM?!-XJCIS#@iBsMwy(9$70i6Gq2?)cB+G9=*oP4{lM;0KrEwjI% z%qvCi2tcSMMtLt(hR7Ae8`dr5;Q#<6p2r(C=`LA-0$FGm+Y2C`j#1a0x_}TO#{oDb z!izGhSgSk$Q4kfCLj-rnE!Um80M7!jEWl4ygaZJO1TXR~c@fbxZQ#0@Kwi(1l1>k$ z{aX{=lLa`?@Ia3s^7ShTb!>WJyT##fB#V2vuz(~XIvR$>$f+Lvt*2*Bxk=o^Q2+ua1^MuPK8dNGCT5`o_=VD8X!tnQ% zdnu`KAw=u_FeQYzRYxxTsW;jy)mH>?eD~Qu+0gt5&oZpy-t1Df;bI8gQi#C08=Csj zaYyCpXv4PsVeErR)aSZ5h + + + + point layer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + point layer + 2011-03-11 + + + Robert Szczepanek + + + + + Robert Szczepanek + + + + + icon + gis + + + GIS icons 0.2 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/core/symbology-ng/qgsstyle.sip b/python/core/symbology-ng/qgsstyle.sip index f3f70d606d2..c275535aa27 100644 --- a/python/core/symbology-ng/qgsstyle.sip +++ b/python/core/symbology-ng/qgsstyle.sip @@ -236,6 +236,9 @@ class QgsStyle : QObject */ QStringList tagsOfSymbol( StyleEntity type, const QString& symbol ); + //! Returns the tag name for the given id + QString tag( int id ) const; + //! Returns the smart groups map with id as key and name as value QMap smartgroupsListMap(); diff --git a/python/gui/symbology-ng/qgsstylemanagerdialog.sip b/python/gui/symbology-ng/qgsstylemanagerdialog.sip index dd0739d46a1..bc23edb3076 100644 --- a/python/gui/symbology-ng/qgsstylemanagerdialog.sip +++ b/python/gui/symbology-ng/qgsstylemanagerdialog.sip @@ -34,7 +34,11 @@ class QgsStyleManagerDialog : QDialog void groupChanged( const QModelIndex& ); void groupRenamed( QStandardItem * ); - void addGroup(); + //! add a tag + int addTag(); + //! add a smartgroup + int addSmartgroup(); + //! remove a tag or smartgroup void removeGroup(); //! carry out symbol tagging using check boxes @@ -68,7 +72,7 @@ class QgsStyleManagerDialog : QDialog //! Remove selected symbols from favorites void removeFavoriteSelectedSymbols(); //! Tag selected symbols using menu item selection - void tagSelectedSymbols(); + void tagSelectedSymbols( bool newTag = false ); //! Remove all tags from selected symbols void detagSelectedSymbols(); diff --git a/src/core/symbology-ng/qgsstyle.cpp b/src/core/symbology-ng/qgsstyle.cpp index cc7d03b377e..c82520415e2 100644 --- a/src/core/symbology-ng/qgsstyle.cpp +++ b/src/core/symbology-ng/qgsstyle.cpp @@ -995,6 +995,27 @@ QStringList QgsStyle::tagsOfSymbol( StyleEntity type, const QString& symbol ) return tagList; } +QString QgsStyle::tag( int id ) const +{ + if ( !mCurrentDB ) + return QString(); + + sqlite3_stmt *ppStmt; + + char *query = sqlite3_mprintf( "SELECT name FROM tag WHERE id=%d", id ); + int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); + + QString tag; + if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) + { + tag = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, 0 ) ) ); + } + + sqlite3_finalize( ppStmt ); + + return tag; +} + int QgsStyle::getId( const QString& table, const QString& name ) { char *query = sqlite3_mprintf( "SELECT id FROM %q WHERE LOWER(name)='%q'", table.toUtf8().constData(), name.toUtf8().toLower().constData() ); diff --git a/src/core/symbology-ng/qgsstyle.h b/src/core/symbology-ng/qgsstyle.h index 9e415b00069..3efad03d19c 100644 --- a/src/core/symbology-ng/qgsstyle.h +++ b/src/core/symbology-ng/qgsstyle.h @@ -301,6 +301,9 @@ class CORE_EXPORT QgsStyle : public QObject */ QStringList tagsOfSymbol( StyleEntity type, const QString& symbol ); + //! Returns the tag name for the given id + QString tag( int id ) const; + //! Returns the smart groups map with id as key and name as value QgsSymbolGroupMap smartgroupsListMap(); diff --git a/src/gui/symbology-ng/qgsstylemanagerdialog.cpp b/src/gui/symbology-ng/qgsstylemanagerdialog.cpp index f53f1996177..1674f1be4dc 100644 --- a/src/gui/symbology-ng/qgsstylemanagerdialog.cpp +++ b/src/gui/symbology-ng/qgsstylemanagerdialog.cpp @@ -30,13 +30,14 @@ #include "qgsstyleexportimportdialog.h" #include "qgssmartgroupeditordialog.h" +#include #include #include #include #include +#include #include #include -#include #include #include "qgsapplication.h" @@ -59,28 +60,33 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle* style, QWidget* parent ) mSplitter->restoreState( settings.value( QStringLiteral( "/Windows/StyleV2Manager/splitter" ) ).toByteArray() ); tabItemType->setDocumentMode( true ); - searchBox->setPlaceholderText( tr( "Type here to filter symbols..." ) ); + searchBox->setPlaceholderText( tr( "Filter symbols…" ) ); connect( this, SIGNAL( finished( int ) ), this, SLOT( onFinished() ) ); connect( listItems, SIGNAL( doubleClicked( const QModelIndex & ) ), this, SLOT( editItem() ) ); - connect( btnAddItem, SIGNAL( clicked() ), this, SLOT( addItem() ) ); - connect( actnEditItem, SIGNAL( triggered( bool ) ), this, SLOT( editItem() ) ); - connect( actnRemoveItem, SIGNAL( triggered( bool ) ), this, SLOT( removeItem() ) ); - - btnRemoveItem->setDefaultAction( actnRemoveItem ); - btnEditItem->setDefaultAction( actnEditItem ); + connect( btnAddItem, &QPushButton::clicked, [=]( bool ) { addItem(); } + ); + connect( btnEditItem, &QPushButton::clicked, [=]( bool ) { editItem(); } + ); + connect( actnEditItem, &QAction::triggered, [=]( bool ) { editItem(); } + ); + connect( btnRemoveItem, &QPushButton::clicked, [=]( bool ) { removeItem(); } + ); + connect( actnRemoveItem, &QAction::triggered, [=]( bool ) { removeItem(); } + ); QMenu *shareMenu = new QMenu( tr( "Share menu" ), this ); + QAction *exportAction = new QAction( tr( "Export symbol(s)…" ), this ); + exportAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileSave.svg" ) ) ); + shareMenu->addAction( exportAction ); + QAction *importAction = new QAction( tr( "Import symbol(s)…" ), this ); + importAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileOpen.svg" ) ) ); + shareMenu->addAction( importAction ); + shareMenu->addSeparator(); shareMenu->addAction( actnExportAsPNG ); shareMenu->addAction( actnExportAsSVG ); - QAction *exportAction = new QAction( tr( "Export..." ), this ); - shareMenu->addAction( exportAction ); - QAction *importAction = new QAction( tr( "Import..." ), this ); - shareMenu->addAction( importAction ); - exportAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileSave.svg" ) ) ); - importAction->setIcon( QIcon( QgsApplication::iconPath( "mActionFileOpen.svg" ) ) ); connect( actnExportAsPNG, SIGNAL( triggered() ), this, SLOT( exportItemsPNG() ) ); connect( actnExportAsSVG, SIGNAL( triggered() ), this, SLOT( exportItemsSVG() ) ); connect( exportAction, SIGNAL( triggered() ), this, SLOT( exportItems() ) ); @@ -106,6 +112,8 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle* style, QWidget* parent ) groupTree->setModel( groupModel ); groupTree->setHeaderHidden( true ); populateGroups(); + groupTree->setCurrentIndex( groupTree->model()->index( 0, 0 ) ); + connect( groupTree->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( groupChanged( const QModelIndex& ) ) ); connect( groupModel, SIGNAL( itemChanged( QStandardItem* ) ), @@ -167,8 +175,12 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle* style, QWidget* parent ) mGroupTreeContextMenu = new QMenu( this ); connect( actnEditSmartGroup, SIGNAL( triggered( bool ) ), this, SLOT( editSmartgroupAction() ) ); mGroupTreeContextMenu->addAction( actnEditSmartGroup ); - connect( actnAddGroup, SIGNAL( triggered( bool ) ), this, SLOT( addGroup() ) ); - mGroupTreeContextMenu->addAction( actnAddGroup ); + connect( actnAddTag, &QAction::triggered, [=]( bool ) { addTag(); } + ); + mGroupTreeContextMenu->addAction( actnAddTag ); + connect( actnAddSmartgroup, &QAction::triggered, [=]( bool ) { addSmartgroup(); } + ); + mGroupTreeContextMenu->addAction( actnAddSmartgroup ); connect( actnRemoveGroup, SIGNAL( triggered( bool ) ), this, SLOT( removeGroup() ) ); mGroupTreeContextMenu->addAction( actnRemoveGroup ); @@ -232,6 +244,7 @@ void QgsStyleManagerDialog::on_tabItemType_currentChanged( int ) { // when in Color Ramp tab, add menu to add item button and hide "Export symbols as PNG/SVG" bool flag = currentItemType() != 3; + searchBox->setPlaceholderText( flag ? tr( "Filter symbols…" ) : tr( "Filter color ramps…" ) ); btnAddItem->setMenu( flag ? nullptr : mMenuBtnAddItemColorRamp ); actnExportAsPNG->setVisible( flag ); actnExportAsSVG->setVisible( flag ); @@ -945,24 +958,25 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) if ( category == QLatin1String( "all" ) || category == QLatin1String( "tags" ) || category == QLatin1String( "smartgroups" ) ) { enableGroupInputs( false ); - if ( category == QLatin1String( "tags" ) || category == QLatin1String( "smartgroups" ) ) + if ( category == QLatin1String( "tags" ) ) { - btnAddGroup->setEnabled( true ); - actnAddGroup->setEnabled( true ); + actnAddTag->setEnabled( true ); + actnAddSmartgroup->setEnabled( false ); + } + else if ( category == QLatin1String( "smartgroups" ) ) + { + actnAddTag->setEnabled( false ); + actnAddSmartgroup->setEnabled( true ); } symbolNames = currentItemType() < 3 ? mStyle->symbolNames() : mStyle->colorRampNames(); } else if ( category == QLatin1String( "favorite" ) ) { - btnAddGroup->setEnabled( true ); - actnAddGroup->setEnabled( true ); enableGroupInputs( false ); - symbolNames = mStyle->symbolsOfFavorite( type ); } else if ( index.parent().data( Qt::UserRole + 1 ) == "smartgroups" ) { - btnRemoveGroup->setEnabled( true ); actnRemoveGroup->setEnabled( true ); btnManageGroups->setEnabled( true ); int groupId = index.data( Qt::UserRole + 1 ).toInt(); @@ -995,7 +1009,8 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) } actnEditSmartGroup->setVisible( false ); - actnAddGroup->setVisible( false ); + actnAddTag->setVisible( false ); + actnAddSmartgroup->setVisible( false ); actnRemoveGroup->setVisible( false ); actnTagSymbols->setVisible( false ); actnFinishTagging->setVisible( false ); @@ -1006,81 +1021,60 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) { actnEditSmartGroup->setVisible( !mGrouppingMode ); } - else + else if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "tags" ) ) { - actnAddGroup->setVisible( !mGrouppingMode ); + actnAddTag->setVisible( !mGrouppingMode ); actnTagSymbols->setVisible( !mGrouppingMode ); actnFinishTagging->setVisible( mGrouppingMode ); } actnRemoveGroup->setVisible( true ); } - else if ( index.data( Qt::UserRole + 1 ) == "tags" || index.data( Qt::UserRole + 1 ) == "smartgroups" ) + else if ( index.data( Qt::UserRole + 1 ) == "smartgroups" ) { - actnAddGroup->setVisible( !mGrouppingMode ); + actnAddSmartgroup->setVisible( !mGrouppingMode ); + } + else if ( index.data( Qt::UserRole + 1 ) == "tags" ) + { + actnAddTag->setVisible( !mGrouppingMode ); } } -void QgsStyleManagerDialog::addGroup() +int QgsStyleManagerDialog::addTag() { QStandardItemModel *model = qobject_cast( groupTree->model() ); - QModelIndex index = groupTree->currentIndex(); - - // don't allow creation of tag/smartgroup against system-defined groupings - QString data = index.data( Qt::UserRole + 1 ).toString(); - if ( data == QLatin1String( "all" ) || data == "favorite" ) + QModelIndex index; + for ( int i = 0; i < groupTree->model()->rowCount(); i++ ) { - int err = QMessageBox::critical( this, tr( "Invalid Selection" ), - tr( "The parent group you have selected is not user editable.\n" - "Kindly select a user defined group." ) ); - if ( err ) - return; + index = groupTree->model()->index( i, 0 ); + QString data = index.data( Qt::UserRole + 1 ).toString(); + if ( data == QLatin1String( "tags" ) ) + { + break; + } } QString itemName; int id; + bool ok; + itemName = QInputDialog::getText( this, tr( "Tag name" ), + tr( "Please enter name for the new tag:" ), QLineEdit::Normal, tr( "New tag" ), &ok ).trimmed(); + if ( !ok || itemName.isEmpty() ) + return 0; - // - if ( index.parent() != QModelIndex() ) + int check = mStyle->tagId( itemName ); + if ( check > 0 ) { - index = index.parent(); - data = index.data( Qt::UserRole + 1 ).toString(); + QMessageBox::critical( this, tr( "Error!" ), + tr( "Tag name already exists in your symbol database." ) ); + return 0; } - - if ( data == QLatin1String( "smartgroups" ) ) + id = mStyle->addTag( itemName ); + if ( !id ) { - // create a smartgroup - QgsSmartGroupEditorDialog dlg( mStyle, this ); - if ( dlg.exec() == QDialog::Rejected ) - return; - id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() ); - if ( !id ) - return; - itemName = dlg.smartgroupName(); - } - else - { - // create a tag - bool ok; - itemName = QInputDialog::getText( this, tr( "Tag name" ), - tr( "Please enter name for the new tag:" ), QLineEdit::Normal, tr( "New tag" ), &ok ).trimmed(); - if ( !ok || itemName.isEmpty() ) - return; - - int check = mStyle->tagId( itemName ); - if ( check > 0 ) - { - QMessageBox::critical( this, tr( "Error!" ), - tr( "Tag name already exists in your symbol database." ) ); - return; - } - id = mStyle->addTag( itemName ); - if ( !id ) - { - QMessageBox::critical( this, tr( "Error!" ), - tr( "New tag could not be created.\n" - "There was a problem with your symbol database." ) ); - return; - } + QMessageBox::critical( this, tr( "Error!" ), + tr( "New tag could not be created.\n" + "There was a problem with your symbol database." ) ); + return 0; } QStandardItem *parentItem = model->itemFromIndex( index ); @@ -1088,7 +1082,39 @@ void QgsStyleManagerDialog::addGroup() childItem->setData( id ); parentItem->appendRow( childItem ); - groupTree->setCurrentIndex( childItem->index() ); + return id; +} + +int QgsStyleManagerDialog::addSmartgroup() +{ + QStandardItemModel *model = qobject_cast( groupTree->model() ); + QModelIndex index; + for ( int i = 0; i < groupTree->model()->rowCount(); i++ ) + { + index = groupTree->model()->index( i, 0 ); + QString data = index.data( Qt::UserRole + 1 ).toString(); + if ( data == QLatin1String( "smartgroups" ) ) + { + break; + } + } + + QString itemName; + int id; + QgsSmartGroupEditorDialog dlg( mStyle, this ); + if ( dlg.exec() == QDialog::Rejected ) + return 0; + id = mStyle->addSmartgroup( dlg.smartgroupName(), dlg.conditionOperator(), dlg.conditionMap() ); + if ( !id ) + return 0; + itemName = dlg.smartgroupName(); + + QStandardItem *parentItem = model->itemFromIndex( index ); + QStandardItem *childItem = new QStandardItem( itemName ); + childItem->setData( id ); + parentItem->appendRow( childItem ); + + return id; } void QgsStyleManagerDialog::removeGroup() @@ -1280,9 +1306,10 @@ void QgsStyleManagerDialog::selectedSymbolsChanged( const QItemSelection& select void QgsStyleManagerDialog::enableSymbolInputs( bool enable ) { groupTree->setEnabled( enable ); - btnAddGroup->setEnabled( enable ); - actnAddGroup->setEnabled( enable ); - btnRemoveGroup->setEnabled( enable ); + btnAddTag->setEnabled( enable ); + btnAddSmartgroup->setEnabled( enable ); + actnAddTag->setEnabled( enable ); + actnAddSmartgroup->setEnabled( enable ); actnRemoveGroup->setEnabled( enable ); btnManageGroups->setEnabled( enable || mGrouppingMode ); // always enabled in grouping mode, as it is the only way to leave grouping mode searchBox->setEnabled( enable ); @@ -1290,8 +1317,6 @@ void QgsStyleManagerDialog::enableSymbolInputs( bool enable ) void QgsStyleManagerDialog::enableGroupInputs( bool enable ) { - btnAddGroup->setEnabled( enable ); - btnRemoveGroup->setEnabled( enable ); actnRemoveGroup->setEnabled( enable ); btnManageGroups->setEnabled( enable || mGrouppingMode ); // always enabled in grouping mode, as it is the only way to leave grouping mode } @@ -1351,10 +1376,20 @@ void QgsStyleManagerDialog::listitemsContextMenu( QPoint point ) { a = new QAction( tag, mGroupListMenu ); a->setData( tag ); - connect( a, SIGNAL( triggered( bool ) ), this, SLOT( tagSelectedSymbols() ) ); + connect( a, &QAction::triggered, this, [=]( bool ) { tagSelectedSymbols(); } + ); mGroupListMenu->addAction( a ); } + if ( tags.count() > 0 ) + { + mGroupListMenu->addSeparator(); + } + a = new QAction( "Create new tag... ", mGroupListMenu ); + connect( a, &QAction::triggered, this, [=]( bool ) { tagSelectedSymbols( true ); } + ); + mGroupListMenu->addAction( a ); + mGroupMenu->popup( globalPos ); } @@ -1392,10 +1427,9 @@ void QgsStyleManagerDialog::removeFavoriteSelectedSymbols() populateList(); } -void QgsStyleManagerDialog::tagSelectedSymbols() +void QgsStyleManagerDialog::tagSelectedSymbols( bool newTag ) { QAction* selectedItem = qobject_cast( sender() ); - if ( selectedItem ) { QgsStyle::StyleEntity type = ( currentItemType() < 3 ) ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity; @@ -1404,7 +1438,23 @@ void QgsStyleManagerDialog::tagSelectedSymbols() QgsDebugMsg( "unknown entity type" ); return; } - QString tag = selectedItem->data().toString(); + + QString tag; + if ( newTag ) + { + int id = addTag(); + if ( id == 0 ) + { + return; + } + + tag = mStyle->tag( id ); + } + else + { + tag = selectedItem->data().toString(); + } + QModelIndexList indexes = listItems->selectionModel()->selectedIndexes(); Q_FOREACH ( const QModelIndex& index, indexes ) { diff --git a/src/gui/symbology-ng/qgsstylemanagerdialog.h b/src/gui/symbology-ng/qgsstylemanagerdialog.h index 7132838af44..ea0ad7330f2 100644 --- a/src/gui/symbology-ng/qgsstylemanagerdialog.h +++ b/src/gui/symbology-ng/qgsstylemanagerdialog.h @@ -63,7 +63,11 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan void groupChanged( const QModelIndex& ); void groupRenamed( QStandardItem * ); - void addGroup(); + //! add a tag + int addTag(); + //! add a smartgroup + int addSmartgroup(); + //! remove a tag or smartgroup void removeGroup(); //! carry out symbol tagging using check boxes @@ -97,7 +101,7 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan //! Remove selected symbols from favorites void removeFavoriteSelectedSymbols(); //! Tag selected symbols using menu item selection - void tagSelectedSymbols(); + void tagSelectedSymbols( bool newTag = false ); //! Remove all tags from selected symbols void detagSelectedSymbols(); diff --git a/src/ui/qgsprojectpropertiesbase.ui b/src/ui/qgsprojectpropertiesbase.ui index 06ce53fe8bc..c0eeeba6235 100644 --- a/src/ui/qgsprojectpropertiesbase.ui +++ b/src/ui/qgsprojectpropertiesbase.ui @@ -887,7 +887,7 @@ - :/images/themes/default/styleicons/color.png + :/images/themes/default/styleicons/color.svg @@ -903,7 +903,7 @@ - :/images/themes/default/styleicons/style-polygon.png + :/images/themes/default/mIconPolygonLayer.svg @@ -930,7 +930,7 @@ - :/images/themes/default/styleicons/style-line.png + :/images/themes/default/mIconLineLayer.svg @@ -982,7 +982,7 @@ - :/images/themes/default/styleicons/style-point.png + :/images/themes/default/mIconPointLayer.svg diff --git a/src/ui/qgsstylemanagerdialogbase.ui b/src/ui/qgsstylemanagerdialogbase.ui index 2a306329aaa..13812b2f116 100644 --- a/src/ui/qgsstylemanagerdialogbase.ui +++ b/src/ui/qgsstylemanagerdialogbase.ui @@ -13,12 +13,6 @@ Style Manager - - QToolButton { padding-left: 3px; padding-right: 3px; } -/* QMenu::item { padding: 2px 10px 2px 20px; } -QMenu::item:selected { background-color: gray; } */ - - 6 @@ -63,7 +57,7 @@ QMenu::item:selected { background-color: gray; } */ 0 - + @@ -83,41 +77,46 @@ QMenu::item:selected { background-color: gray; } */ - + - - - - - :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg + Add tag… false - - + + - - - - - :/images/themes/default/symbologyRemove.svg:/images/themes/default/symbologyRemove.svg + Add smart group… false - + - + Modify group + + + Modify selected tag or smart group + + + false + + + + + + + Import / export - :/images/themes/default/mActionChangeLabelProperties.svg:/images/themes/default/mActionChangeLabelProperties.svg + :/images/themes/default/mActionSharing.svg:/images/themes/default/mActionSharing.svg false @@ -172,7 +171,7 @@ QMenu::item:selected { background-color: gray; } */ - :/images/themes/default/styleicons/style-point.png:/images/themes/default/styleicons/style-point.png + :/images/themes/default/mIconPointLayer.svg:/images/themes/default/mIconPointLayer.svg Marker @@ -187,7 +186,7 @@ QMenu::item:selected { background-color: gray; } */ - :/images/themes/default/styleicons/style-line.png:/images/themes/default/styleicons/style-line.png + :/images/themes/default/mIconLineLayer.svg:/images/themes/default/mIconLineLayer.svg Line @@ -202,7 +201,7 @@ QMenu::item:selected { background-color: gray; } */ - :/images/themes/default/styleicons/style-polygon.png:/images/themes/default/styleicons/style-polygon.png + :/images/themes/default/mIconPolygonLayer.svg:/images/themes/default/mIconPolygonLayer.svg Fill @@ -217,7 +216,7 @@ QMenu::item:selected { background-color: gray; } */ - :/images/themes/default/styleicons/color.png:/images/themes/default/styleicons/color.png + :/images/themes/default/styleicons/color.svg:/images/themes/default/styleicons/color.svg Color ramp @@ -265,16 +264,10 @@ QMenu::item:selected { background-color: gray; } */ - - + + - - - - 0 - 0 - - + Add item @@ -285,16 +278,10 @@ QMenu::item:selected { background-color: gray; } */ :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg - - QToolButton::InstantPopup - - - true - - + Remove item @@ -305,26 +292,10 @@ QMenu::item:selected { background-color: gray; } */ :/images/themes/default/symbologyRemove.svg:/images/themes/default/symbologyRemove.svg - - true - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + Edit item @@ -335,44 +306,21 @@ QMenu::item:selected { background-color: gray; } */ :/images/themes/default/mActionProjectProperties.png:/images/themes/default/mActionProjectProperties.png - - Qt::ToolButtonIconOnly - - - true - - - + + + Qt::Horizontal + + 0 - 16 + 0 - - - - - - :/images/themes/default/mActionSharing.svg:/images/themes/default/mActionSharing.svg - - - QToolButton::InstantPopup - - - Qt::ToolButtonIconOnly - - - true - - + - - - - @@ -391,9 +339,6 @@ QMenu::item:selected { background-color: gray; } */ Qt::Horizontal - - QDialogButtonBox::Close - false @@ -468,13 +413,22 @@ QMenu::item:selected { background-color: gray; } */ Edit smart group... - + :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg - Add group + Add tag… + + + + + + :/images/themes/default/symbologyAdd.svg:/images/themes/default/symbologyAdd.svg + + + Add smart group… @@ -483,7 +437,7 @@ QMenu::item:selected { background-color: gray; } */ :/images/themes/default/symbologyRemove.svg:/images/themes/default/symbologyRemove.svg - Remove group + Remove @@ -508,10 +462,10 @@ QMenu::item:selected { background-color: gray; } */ - :/images/themes/default/mActionFileSave.svg:/images/themes/default/mActionFileSave.svg + :/images/themes/default/mActionSaveMapAsImage.svg:/images/themes/default/mActionSaveMapAsImage.svg - Export selected symbol(s) as PNG... + Export selected symbol(s) as PNG… Export selected symbo(s) as PNG @@ -523,10 +477,10 @@ QMenu::item:selected { background-color: gray; } */ - :/images/themes/default/mActionFileSave.svg:/images/themes/default/mActionFileSave.svg + :/images/themes/default/mActionSaveAsSVG.svg:/images/themes/default/mActionSaveAsSVG.svg - Export selected symbol(s) as SVG... + Export selected symbol(s) as SVG… Export selected symbol(s) as SVG @@ -542,16 +496,17 @@ QMenu::item:selected { background-color: gray; } */ groupTree - btnAddGroup - btnRemoveGroup btnManageGroups - searchBox + btnRemoveGroup + btnAddTag + btnAddSmartgroup + btnShare tabItemType listItems btnAddItem btnRemoveItem btnEditItem - btnShare + searchBox @@ -574,9 +529,25 @@ QMenu::item:selected { background-color: gray; } */ - btnAddGroup + btnAddTag clicked() - actnAddGroup + actnAddTag + trigger() + + + 46 + 362 + + + -1 + -1 + + + + + btnAddSmartgroup + clicked() + actnAddSmartgroup trigger() From 5f3ba725476fc16834ed3486f0b5394985f20d00 Mon Sep 17 00:00:00 2001 From: nirvn Date: Fri, 18 Nov 2016 10:26:43 +0700 Subject: [PATCH 2/3] [style manager] sort displayed symbols, insure tags are added only once --- python/core/symbology-ng/qgsstyle.sip | 9 +++ src/core/symbology-ng/qgsstyle.cpp | 58 ++++++++++++++++--- src/core/symbology-ng/qgsstyle.h | 9 +++ .../symbology-ng/qgsstylemanagerdialog.cpp | 9 +-- src/gui/symbology-ng/qgssymbolslistwidget.cpp | 4 +- 5 files changed, 75 insertions(+), 14 deletions(-) diff --git a/python/core/symbology-ng/qgsstyle.sip b/python/core/symbology-ng/qgsstyle.sip index c275535aa27..1b286699576 100644 --- a/python/core/symbology-ng/qgsstyle.sip +++ b/python/core/symbology-ng/qgsstyle.sip @@ -236,6 +236,15 @@ class QgsStyle : QObject */ QStringList tagsOfSymbol( StyleEntity type, const QString& symbol ); + /** Returns wheter a given tag is associated with the symbol + * + * \param type is either SymbolEntity or ColorrampEntity + * \param symbol is the name of the symbol or color ramp + * \param tag the name of the tag to look for + * \return A boolean value identicating whether a tag was found attached to the symbol + */ + bool symbolHasTag( StyleEntity type, const QString& symbol, const QString& tag ); + //! Returns the tag name for the given id QString tag( int id ) const; diff --git a/src/core/symbology-ng/qgsstyle.cpp b/src/core/symbology-ng/qgsstyle.cpp index c82520415e2..e1f8e864f72 100644 --- a/src/core/symbology-ng/qgsstyle.cpp +++ b/src/core/symbology-ng/qgsstyle.cpp @@ -842,16 +842,19 @@ bool QgsStyle::tagSymbol( StyleEntity type, const QString& symbol, const QString sqlite3_finalize( ppStmt ); - // Now map the tag to the symbol - query = type == SymbolEntity - ? sqlite3_mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid ) - : sqlite3_mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid ); - - char *zErr = nullptr; - nErr = sqlite3_exec( mCurrentDB, query, nullptr, nullptr, &zErr ); - if ( nErr ) + // Now map the tag to the symbol if it's not already tagged + if ( !symbolHasTag( type, symbol, tag ) ) { - QgsDebugMsg( zErr ); + query = type == SymbolEntity + ? sqlite3_mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid ) + : sqlite3_mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid ); + + char *zErr = nullptr; + nErr = sqlite3_exec( mCurrentDB, query, nullptr, nullptr, &zErr ); + if ( nErr ) + { + QgsDebugMsg( zErr ); + } } } } @@ -995,6 +998,43 @@ QStringList QgsStyle::tagsOfSymbol( StyleEntity type, const QString& symbol ) return tagList; } +bool QgsStyle::symbolHasTag( StyleEntity type, const QString& symbol, const QString& tag ) +{ + if ( !mCurrentDB ) + { + QgsDebugMsg( "Sorry! Cannot open database for getting the tags." ); + return false; + } + + int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol ); + if ( !symbolid ) + { + return false; + } + int tagid = tagId( tag ); + if ( !tagid ) + { + return false; + } + + // get the ids of tags for the symbol + char *query = type == SymbolEntity + ? sqlite3_mprintf( "SELECT tag_id FROM tagmap WHERE tag_id=%d AND symbol_id=%d", tagid, symbolid ) + : sqlite3_mprintf( "SELECT tag_id FROM ctagmap WHERE tag_id=%d AND colorramp_id=%d", tagid, symbolid ); + + sqlite3_stmt *ppStmt; + int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); + + if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) + { + return true; + } + else + { + return false; + } +} + QString QgsStyle::tag( int id ) const { if ( !mCurrentDB ) diff --git a/src/core/symbology-ng/qgsstyle.h b/src/core/symbology-ng/qgsstyle.h index 3efad03d19c..de5d0eadb5f 100644 --- a/src/core/symbology-ng/qgsstyle.h +++ b/src/core/symbology-ng/qgsstyle.h @@ -301,6 +301,15 @@ class CORE_EXPORT QgsStyle : public QObject */ QStringList tagsOfSymbol( StyleEntity type, const QString& symbol ); + /** Returns wheter a given tag is associated with the symbol + * + * \param type is either SymbolEntity or ColorrampEntity + * \param symbol is the name of the symbol or color ramp + * \param tag the name of the tag to look for + * \return A boolean value identicating whether a tag was found attached to the symbol + */ + bool symbolHasTag( StyleEntity type, const QString& symbol, const QString& tag ); + //! Returns the tag name for the given id QString tag( int id ) const; diff --git a/src/gui/symbology-ng/qgsstylemanagerdialog.cpp b/src/gui/symbology-ng/qgsstylemanagerdialog.cpp index 1674f1be4dc..3ad3071cb19 100644 --- a/src/gui/symbology-ng/qgsstylemanagerdialog.cpp +++ b/src/gui/symbology-ng/qgsstylemanagerdialog.cpp @@ -271,19 +271,19 @@ void QgsStyleManagerDialog::populateSymbols( const QStringList& symbolNames, boo model->clear(); int type = currentItemType(); - for ( int i = 0; i < symbolNames.count(); ++i ) { QString name = symbolNames[i]; QgsSymbol* symbol = mStyle->symbol( name ); if ( symbol && symbol->type() == type ) { + QStringList tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, name ); QStandardItem* item = new QStandardItem( name ); QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( symbol, listItems->iconSize(), 18 ); item->setIcon( icon ); item->setData( name ); // used to find out original name when user edited the name item->setCheckable( check ); - item->setToolTip( name ); + item->setToolTip( QString( "%1
%2" ).arg( name ).arg( tags.count() > 0 ? tags.join( ", " ) : tr( "Not tagged" ) ) ); // add to model model->appendRow( item ); } @@ -994,6 +994,7 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) } } + symbolNames.sort(); if ( currentItemType() < 3 ) { populateSymbols( symbolNames, mGrouppingMode ); @@ -1271,14 +1272,14 @@ void QgsStyleManagerDialog::setSymbolsChecked( const QStringList& symbols ) void QgsStyleManagerDialog::filterSymbols( const QString& qword ) { QStringList items; + items = mStyle->findSymbols( currentItemType() < 3 ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity, qword ); + items.sort(); if ( currentItemType() == 3 ) { - items = mStyle->findSymbols( QgsStyle::ColorrampEntity, qword ); populateColorRamps( items ); } else { - items = mStyle->findSymbols( QgsStyle::SymbolEntity, qword ); populateSymbols( items ); } } diff --git a/src/gui/symbology-ng/qgssymbolslistwidget.cpp b/src/gui/symbology-ng/qgssymbolslistwidget.cpp index 0257cc20192..be3dc5d1028 100644 --- a/src/gui/symbology-ng/qgssymbolslistwidget.cpp +++ b/src/gui/symbology-ng/qgssymbolslistwidget.cpp @@ -211,6 +211,7 @@ void QgsSymbolsListWidget::populateSymbolView() symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, id ); } + symbols.sort(); populateSymbols( symbols ); } @@ -233,10 +234,11 @@ void QgsSymbolsListWidget::populateSymbols( const QStringList& names ) delete s; continue; } + QStringList tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, names[i] ); QStandardItem* item = new QStandardItem( names[i] ); item->setData( names[i], Qt::UserRole ); //so we can load symbol with that name item->setText( names[i] ); - item->setToolTip( names[i] ); + item->setToolTip( QString( "%1
%2" ).arg( names[i] ).arg( tags.count() > 0 ? tags.join( ", " ) : tr( "Not tagged" ) ) ); item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); // Set font to 10points to show reasonable text QFont itemFont = item->font(); From 8fcf8345bd22ff6070fce8dbebbc4a8fdd279b49 Mon Sep 17 00:00:00 2001 From: nirvn Date: Fri, 18 Nov 2016 12:30:25 +0700 Subject: [PATCH 3/3] tests for two additional QgsStyle functions: tag() & symbolHasTag() --- tests/src/core/testqgsstyle.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/src/core/testqgsstyle.cpp b/tests/src/core/testqgsstyle.cpp index fecf6e6f245..0e2f10cc4d0 100644 --- a/tests/src/core/testqgsstyle.cpp +++ b/tests/src/core/testqgsstyle.cpp @@ -301,7 +301,10 @@ void TestStyle::testTags() id = mStyle->addTag( QStringLiteral( "blue" ) ); QCOMPARE( id, mStyle->tagId( "blue" ) ); id = mStyle->addTag( QStringLiteral( "purple" ) ); + + //check tagid and tag return values QCOMPARE( id, mStyle->tagId( "purple" ) ); + QCOMPARE( QStringLiteral( "purple" ), mStyle->tag( id ) ); QStringList tags = mStyle->tags(); QCOMPARE( tags.count(), 5 ); @@ -348,6 +351,12 @@ void TestStyle::testTags() QVERIFY( tags.contains( "red" ) ); QVERIFY( tags.contains( "starry" ) ); + //check that a given tag is attached to a symbol + QVERIFY( mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ), QStringLiteral( "blue" ) ) ); + + //check that a given tag is not attached to a symbol + QCOMPARE( false, mStyle->symbolHasTag( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ), QStringLiteral( "notblue" ) ) ); + //remove a tag, including a non-present tag QVERIFY( mStyle->detagSymbol( QgsStyle::SymbolEntity, "blue starry", QStringList() << "bad" << "blue" ) ); tags = mStyle->tagsOfSymbol( QgsStyle::SymbolEntity, QStringLiteral( "blue starry" ) );