diff --git a/doc/api_break.dox b/doc/api_break.dox index 87dcd05f342..0394a62b113 100644 --- a/doc/api_break.dox +++ b/doc/api_break.dox @@ -1371,6 +1371,11 @@ QgsSvgCache {#qgis_api_break_3_0_QgsSvgCache} - containsParamsV2() was removed. Use containsParamsV3() instead. +QgsStyle (renamed from QgsStyleV2) {#qgis_api_break_3_0_QgsStyle} +---------------------------------- +- All group functions have been removed: group(), addGroup(), groupId(), groupName(), groupNames(), groupIds(), symbolsOfGroup(), getGroupRemoveQuery() +- The StyleEntity::GroupEntity has been removed +- The SymgroupTable enum has been removed QgsSymbol (renamed from QgsSymbolV2) {#qgis_api_break_3_0_QgsSymbol} ------------------------------------ diff --git a/python/core/symbology-ng/qgsstyle.sip b/python/core/symbology-ng/qgsstyle.sip index 32395591bee..f3f70d606d2 100644 --- a/python/core/symbology-ng/qgsstyle.sip +++ b/python/core/symbology-ng/qgsstyle.sip @@ -8,15 +8,16 @@ class QgsStyle : QObject QgsStyle(); ~QgsStyle(); - //! Enum for Entities involved in a style - /*! - The enumerator is used for identifying the entity being operated on when generic - database functions are being run. - \sa group(), rename(), remove(), symbolsOfGroup(), symbolsWithTag(), symbolsOfSmartgroup() + /** Enum for Entities involved in a style + /* + * The enumerator is used for identifying the entity being operated on when generic + * database functions are being run. + * \sa group(), rename(), remove(), symbolsOfGroup(), symbolsWithTag(), symbolsOfSmartgroup() */ - enum StyleEntity { SymbolEntity, GroupEntity, TagEntity, ColorrampEntity, SmartgroupEntity }; + enum StyleEntity { SymbolEntity, TagEntity, ColorrampEntity, SmartgroupEntity }; /** Adds a color ramp to the style. Calling this method takes the ramp's ownership. + * * \note Adding a color ramp with the name of existing one replaces it. * \param name is the name of the color ramp being added or updated * \param colorRamp is the color ramp. Ownership is transferred. @@ -25,24 +26,16 @@ class QgsStyle : QObject */ bool addColorRamp( const QString& name, QgsColorRamp* colorRamp /Transfer/, bool update = false ); - //! adds a new group and returns the group's id - /*! - * \param groupName the name of the new group as QString - * \param parent is the id of the parent group when a subgrouo is to be created. By default it is 0 indicating it is not a sub-group - * \return returns an int, which is the DB id of the new group created, 0 if the group couldn't be created - */ - int addGroup( const QString& groupName, int parent = 0 ); - - //! adds new smartgroup to the database and returns the id - /*! + /** Adds new smartgroup to the database and returns the id + * * \param name is the name of the new Smart Group to be added * \param op is the operator between the conditions; AND/OR as QString * \param conditions are the smart group conditions */ int addSmartgroup( const QString& name, const QString& op, QMultiMap conditions ); - //! add symbol to style. takes symbol's ownership - /*! + /** Adds symbol to style and takes symbol's ownership + * * \note Adding a symbol with the name of existing one replaces it. * \param name is the name of the symbol being added or updated * \param symbol is the Vector symbol @@ -51,22 +44,19 @@ class QgsStyle : QObject */ bool addSymbol( const QString& name, QgsSymbol* symbol /Transfer/, bool update = false ); - //! adds a new tag and returns the tag's id - /*! + /** Adds a new tag and returns the tag's id + * * \param tagName the name of the new tag to be created * \return returns an int, which is the DB id of the new tag created, 0 if the tag couldn't be created */ int addTag( const QString& tagName ); /** Returns a list of all tags in the style database - * @note added in QGIS 2.16 - * @see addTag() + * @note added in QGIS 2.16 + * @see addTag() */ QStringList tags() const; - //! return a map of groupid and names for the given parent group - QMap childGroupNames( const QString& parent = "" ); - //! remove all contents of the style void clear(); @@ -75,24 +65,25 @@ class QgsStyle : QObject */ QgsColorRamp* colorRamp( const QString& name ) const /Factory/; - //! return count of color ramps + //! Returns count of color ramps int colorRampCount(); - //! return a list of names of color ramps + //! Returns a list of names of color ramps QStringList colorRampNames(); - //! return a const pointer to a symbol (doesn't create new instance) + //! Returns a const pointer to a symbol (doesn't create new instance) const QgsColorRamp* colorRampRef( const QString& name ) const; - //! return the id in the style database for the given colorramp name - //! returns 0 if not found + /** Returns the id in the style database for the given colorramp name + * returns 0 if not found + */ int colorrampId( const QString& name ); - //! return default application-wide style + //! Returns default application-wide style static QgsStyle* defaultStyle(); - //! tags the symbol with the tags in the list - /*! + /** Tags the symbol with the tags in the list + * * Applies the given tags to the given symbol or colorramp * \param type is either SymbolEntity or ColorrampEntity * \param symbol is the name of the symbol or colorramp as QString @@ -101,8 +92,8 @@ class QgsStyle : QObject */ bool tagSymbol( StyleEntity type, const QString& symbol, const QStringList& tags ); - //! detags the symbol with the given list - /*! + /** Detags the symbol with the given list + * * Removes the given tags for the specified symbol or colorramp * \param type is either SymbolEntity or ColorrampEntity * \param symbol is the name of the symbol or colorramp @@ -110,85 +101,89 @@ class QgsStyle : QObject * \return returns the success state of the operation */ bool detagSymbol( StyleEntity type, QString symbol, QStringList tags ); + /** Clears the symbol from all attached tags + * + * Removes all tags for the specified symbol or colorramp + * \param type is either SymbolEntity or ColorrampEntity + * \param symbol is the name of the symbol or colorramp + * \return returns the success state of the operation + */ + bool detagSymbol( StyleEntity type, QString symbol ); - //! remove symbol from style (and delete it) + //! Removes symbol from style (and delete it) bool removeSymbol( const QString& name ); - //! change symbol's name + //! Changes symbol's name bool renameSymbol( const QString& oldName, const QString& newName ); - //! return a NEW copy of symbol + //! Returns a NEW copy of symbol QgsSymbol* symbol( const QString& name ) /Factory/; - //! return a const pointer to a symbol (doesn't create new instance) + //! Returns a const pointer to a symbol (doesn't create new instance) const QgsSymbol* symbolRef( const QString& name ) const; - //! return count of symbols in style + //! Returns count of symbols in style int symbolCount(); - //! return a list of names of symbols + //! Returns a list of names of symbols QStringList symbolNames(); - //! return the id in the style database for the given symbol name - //! returns 0 if not found + /** Returns the id in the style database for the given symbol name + * returns 0 if not found + */ int symbolId( const QString& name ); - //! return the DB id for the given group name - int groupId( const QString& group ); - //! return the group name for the given DB id - QString groupName( int groupId ) const; - //! return the DB id for the given tag name + //! Returns the DB id for the given tag name int tagId( const QString& tag ); - //! return the DB id for the given smartgroup name + //! Returns the DB id for the given smartgroup name int smartgroupId( const QString& smartgroup ); - //! return the all the groups in the style - QStringList groupNames(); - - //! return the ids of all the groups in the style - QList groupIds() const; - - //! returns the symbolnames of a given groupid - /*! + /** Returns the symbol names which are flagged as favorite + * * \param type is either SymbolEntity or ColorampEntity - * \param groupid is id of the group to which the symbols belong to, as int - * \return A QStringList of the symbol or colorramp names for the given group id + * \return A QStringList of the symbol or colorramp names flagged as favorite */ - QStringList symbolsOfGroup( StyleEntity type, int groupid ); + QStringList symbolsOfFavorite( StyleEntity type ); - //! returns the symbol names with which have the given tag - /*! + /** Returns the symbol names with which have the given tag + * * \param type is either SymbolEntity or ColorampEntity * \param tagid is id of the tag which has been applied over the symbol as int * \return A QStringList of the symbol or colorramp names for the given tag id */ QStringList symbolsWithTag( StyleEntity type, int tagid ); - //! applies the specified group to the symbol or colorramp specified by StyleEntity - /*! + /** Adds the specified symbol to favorites + * * \param type is either SymbolEntity of ColorrampEntity - * \param name is the name of the symbol or coloramp whose group is to be set - * \param groupid is the id of the group to which the entity is assigned + * \param name is the name of the symbol or coloramp whose is to be added to favorites * \return returns the success state as bool */ - bool group( StyleEntity type, const QString& name, int groupid ); + bool addFavorite( StyleEntity type, const QString& name ); + /** Removes the specified symbol from favorites + * + * \param type is either SymbolEntity of ColorrampEntity + * \param name is the name of the symbol or coloramp whose is to be removed from favorites + * \return returns the success state as bool + */ + bool removeFavorite( StyleEntity type, const QString& name ); - //! rename the given entity with the specified id - /*! + /** Renames the given entity with the specified id + * * \param type is any of the style entites. Refer enum StyleEntity. * \param id is the DB id of the entity which is to be renamed * \param newName is the new name of the entity */ void rename( StyleEntity type, int id, const QString& newName ); - //! remove the specified entity from the db - /*! + /** Removes the specified entity from the db + * * \param type is any of the style entites. Refer enum StyleEntity. * \param id is the DB id of the entity to be removed */ void remove( StyleEntity type, int id ); - //! add the symbol to the DB with the tags - /*! + /** Adds the symbol to the DB with the tags + * * \param name is the name of the symbol as QString * \param symbol is the pointer to the new QgsSymbol being saved * \param groupid is the id of the group to which the symbol belongs. Pass 0 if it doesn't belong to any group or not known. @@ -197,8 +192,8 @@ class QgsStyle : QObject */ bool saveSymbol( const QString& name, QgsSymbol* symbol /Transfer/, int groupid, const QStringList& tags ); - //! add the colorramp to the DB - /*! + /** Adds the colorramp to the DB + * * \param name is the name of the colorramp as QString * \param ramp is the pointer to the new QgsColorRamp being saved * \param groupid is the id of the group to which the Color Ramp belongs. Pass 0 if it doesn't belong to any group or not known. @@ -207,54 +202,54 @@ class QgsStyle : QObject */ bool saveColorRamp( const QString& name, QgsColorRamp* ramp, int groupid, const QStringList& tags ); - //! remove color ramp from style (and delete it) + //! Removes color ramp from style (and delete it) bool removeColorRamp( const QString& name ); - //! change ramp's name + //! Changes ramp's name bool renameColorRamp( const QString& oldName, const QString& newName ); - //! load a file into the style + //! Loads a file into the style bool load( const QString& filename ); - //! save style into a file (will use current filename if empty string is passed) + //! Saves style into a file (will use current filename if empty string is passed) bool save( QString filename = QString() ); - //! return last error from load/save operation + //! Returns last error from load/save operation QString errorString(); - //! return current file name of the style + //! Returns current file name of the style QString fileName(); - //! return the names of the symbols which have a matching 'substring' in its defintion - /*! + /** Returns the names of the symbols which have a matching 'substring' in its defintion + * * \param type is either SymbolEntity or ColorrampEntity * \param qword is the query string to search the symbols or colorramps. * \return A QStringList of the matched symbols or colorramps * */ QStringList findSymbols( StyleEntity type, const QString& qword ); - //! return the tags associated with the symbol - /*! + /** Returns the tags associated with the symbol + * * \param type is either SymbolEntity or ColorrampEntity * \param symbol is the name of the symbol or color ramp * \return A QStringList of the tags that have been applied to that symbol/colorramp */ QStringList tagsOfSymbol( StyleEntity type, const QString& symbol ); - //! returns the smart groups map with id as key and name as value + //! Returns the smart groups map with id as key and name as value QMap smartgroupsListMap(); - //! returns the smart groups list + //! Returns the smart groups list QStringList smartgroupNames(); - //! returns the QgsSmartConditionMap for the given id + //! Returns the QgsSmartConditionMap for the given id QMultiMap smartgroup( int id ); - //! returns the operator for the smartgroup + //! Returns the operator for the smartgroup //clumsy implementation TODO create a class for smartgroups QString smartgroupOperator( int id ); - //! returns the symbols for the smartgroup + //! Returns the symbols for the smartgroup QStringList symbolsOfSmartgroup( StyleEntity type, int id ); //! Exports the style as a XML file @@ -264,29 +259,30 @@ class QgsStyle : QObject bool importXml( const QString& filename ); signals: + //! Is emitted every time a new symbol has been added to the database void symbolSaved( const QString& name, QgsSymbol* symbol ); + //! Is emitted every time a tag or smartgroup has been added, removed, or renamed + void groupsModified(); protected: - //! convenience function to open the DB and return a sqlite3 object + //! Convenience function to open the DB and return a sqlite3 object bool openDB( const QString& filename ); - //! convenience function that would run queries which don't generate return values - //! \param query query to run - //! \param freeQuery release query memory - //! \return success true on success + /** Convenience function that would run queries which don't generate return values + * \param query query to run + * \param freeQuery release query memory + * \return success true on success + */ bool runEmptyQuery( char* query, bool freeQuery = true ); - //! prepares the complex query for removing a group, so that the children are not abandoned - char* getGroupRemoveQuery( int id ); - - //! gets the id from the table for the given name from the database, 0 if not found + //! Gets the id from the table for the given name from the database, 0 if not found int getId( const QString& table, const QString& name ); - //! gets the name from the table for the given id from the database, empty if not found + //! Gets the name from the table for the given id from the database, empty if not found QString getName( const QString& table, int id ) const; - //! updates the properties of an existing symbol/colorramp - /*! + /** Updates the properties of an existing symbol/colorramp + * * \note This should not be called separately, only called through addSymbol or addColorRamp * \param type is either SymbolEntity or ColorrampEntity * \param name is the name of an existing symbol or a color ramp diff --git a/python/gui/gui.sip b/python/gui/gui.sip index 3587c165310..4396df54e71 100644 --- a/python/gui/gui.sip +++ b/python/gui/gui.sip @@ -247,6 +247,7 @@ %Include symbology-ng/qgsstyleexportimportdialog.sip %Include symbology-ng/qgsstylegroupselectiondialog.sip %Include symbology-ng/qgsstylemanagerdialog.sip +%Include symbology-ng/qgsstylesavedialog.sip %Include symbology-ng/qgssvgselectorwidget.sip %Include symbology-ng/qgssymbollayerwidget.sip %Include symbology-ng/qgssymbollevelsdialog.sip diff --git a/python/gui/symbology-ng/qgsstyleexportimportdialog.sip b/python/gui/symbology-ng/qgsstyleexportimportdialog.sip index 678403050e9..85ed24242a8 100644 --- a/python/gui/symbology-ng/qgsstyleexportimportdialog.sip +++ b/python/gui/symbology-ng/qgsstyleexportimportdialog.sip @@ -41,15 +41,15 @@ class QgsStyleExportImportDialog : QDialog */ void clearSelection(); /** - * Select the symbols belonging to the given group - * @param groupName the name of the group to be selected + * Select the symbols belonging to the given tag + * @param tagName the name of the tag to be selected */ - void selectGroup( const QString& groupName ); + void selectTag( const QString& tagName ); /** - * Deselect the symbols belonging to the given group - * @param groupName the name of the group to be deselected + * Deselect the symbols belonging to the given tag + * @param tagName the name of the tag to be deselected */ - void deselectGroup( const QString& groupName ); + void deselectTag( const QString& tagName ); /** * @brief selectSmartgroup selects all symbols from a smart group * @param groupName diff --git a/python/gui/symbology-ng/qgsstylegroupselectiondialog.sip b/python/gui/symbology-ng/qgsstylegroupselectiondialog.sip index 0579ebb6dbf..8e4f99e818d 100644 --- a/python/gui/symbology-ng/qgsstylegroupselectiondialog.sip +++ b/python/gui/symbology-ng/qgsstylegroupselectiondialog.sip @@ -28,10 +28,10 @@ class QgsStyleGroupSelectionDialog : public QDialog, private Ui::SymbolsGroupSel void setBold( QStandardItem *item ); signals: - //! group with groupName has been selected - void groupSelected( const QString& groupName ); - //! group with groupName has been deselected - void groupDeselected( const QString& groupName ); + //! tag with tagName has been selected + void tagSelected( const QString& tagName ); + //! tag with tagName has been deselected + void tagDeselected( const QString& tagName ); //! smartgroup with groupName has been selected void smartgroupSelected( const QString& groupName ); //! smart group with groupName has been deselected diff --git a/python/gui/symbology-ng/qgsstylemanagerdialog.sip b/python/gui/symbology-ng/qgsstylemanagerdialog.sip index 012907dbf67..dd0739d46a1 100644 --- a/python/gui/symbology-ng/qgsstylemanagerdialog.sip +++ b/python/gui/symbology-ng/qgsstylemanagerdialog.sip @@ -37,8 +37,8 @@ class QgsStyleManagerDialog : QDialog void addGroup(); void removeGroup(); - //! carryout symbol grouping using check boxes - void groupSymbolsAction(); + //! carry out symbol tagging using check boxes + void tagSymbolsAction(); //! edit the selected smart group void editSmartgroupAction(); @@ -49,9 +49,6 @@ class QgsStyleManagerDialog : QDialog //! filter the symbols based on input search term void filterSymbols( const QString& ); - //! Listen to tag changes - void tagsChanged(); - //! Perform symbol specific tasks when selected void symbolSelected( const QModelIndex& ); @@ -66,7 +63,14 @@ class QgsStyleManagerDialog : QDialog protected slots: bool addColorRamp( QAction* action ); - void groupSelectedSymbols(); + //! Add selected symbols to favorites + void addFavoriteSelectedSymbols(); + //! Remove selected symbols from favorites + void removeFavoriteSelectedSymbols(); + //! Tag selected symbols using menu item selection + void tagSelectedSymbols(); + //! Remove all tags from selected symbols + void detagSelectedSymbols(); protected: @@ -75,8 +79,6 @@ class QgsStyleManagerDialog : QDialog //! populate the groups void populateGroups(); - //! build the groups tree - void buildGroupTree( QStandardItem* &parent ); //! to set symbols checked when in editing mode void setSymbolsChecked( const QStringList& ); @@ -107,9 +109,6 @@ class QgsStyleManagerDialog : QDialog //! Enables or diables the groupTree items for grouping mode void enableItemsForGroupingMode( bool ); - //! Event filter to capture tagsLineEdit out of focus - bool eventFilter( QObject*, QEvent* ); - //! sets the text of the item with bold font void setBold( QStandardItem* ); }; diff --git a/python/gui/symbology-ng/qgsstylesavedialog.sip b/python/gui/symbology-ng/qgsstylesavedialog.sip new file mode 100644 index 00000000000..f73521ed223 --- /dev/null +++ b/python/gui/symbology-ng/qgsstylesavedialog.sip @@ -0,0 +1,22 @@ +class QgsStyleSaveDialog : QDialog +{ +%TypeHeaderCode +#include +%End + + public: + /** Constructor for QgsSymbolSaveDialog + * @param parent parent widget + * @param type the QgsStyle entity type being saved + */ + QgsStyleSaveDialog( QWidget* parent /TransferThis/ = NULL, QgsStyle::StyleEntity type = QgsStyle::SymbolEntity ); + + //! returns the text value of the name element + QString name() const; + + //! returns the text value of the tags element + QString tags() const; + + //! returns whether the favorite element is checked + bool isFavorite() const; +}; diff --git a/python/gui/symbology-ng/qgssymbolslistwidget.sip b/python/gui/symbology-ng/qgssymbolslistwidget.sip index 7bf1f727fe8..d7a7051a939 100644 --- a/python/gui/symbology-ng/qgssymbolslistwidget.sip +++ b/python/gui/symbology-ng/qgssymbolslistwidget.sip @@ -37,8 +37,9 @@ class QgsSymbolsListWidget : QWidget void on_mSymbolUnitWidget_changed(); void on_mTransparencySlider_valueChanged( int value ); + //! Pupulates the groups combo box with available tags and smartgroups + void populateGroups(); void on_groupsCombo_currentIndexChanged( int index ); - void on_groupsCombo_editTextChanged( const QString &text ); void openStyleManager(); void clipFeaturesToggled( bool checked ); diff --git a/resources/symbology-ng-style.db b/resources/symbology-ng-style.db index 4807ad61699..6a62979ba86 100644 Binary files a/resources/symbology-ng-style.db and b/resources/symbology-ng-style.db differ diff --git a/resources/symbology-ng-style.xml b/resources/symbology-ng-style.xml index da1fb44d60a..05fe215abd4 100644 --- a/resources/symbology-ng-style.xml +++ b/resources/symbology-ng-style.xml @@ -838,7 +838,7 @@ - + diff --git a/scripts/symbol_xml2db.py b/scripts/symbol_xml2db.py index 9cf7102df11..8d220715b24 100644 --- a/scripts/symbol_xml2db.py +++ b/scripts/symbol_xml2db.py @@ -32,13 +32,13 @@ _symbol = "CREATE TABLE symbol("\ "id INTEGER PRIMARY KEY,"\ "name TEXT UNIQUE,"\ "xml TEXT,"\ - "groupid INTEGER)" + "favorite INTEGER)" _colorramp = "CREATE TABLE colorramp("\ "id INTEGER PRIMARY KEY,"\ "name TEXT UNIQUE,"\ "xml TEXT,"\ - "groupid INTEGER)" + "favorite INTEGER)" _tag = "CREATE TABLE tag("\ "id INTEGER PRIMARY KEY,"\ @@ -48,57 +48,60 @@ _tagmap = "CREATE TABLE tagmap("\ "tag_id INTEGER NOT NULL,"\ "symbol_id INTEGER)" -_symgroup = "CREATE TABLE symgroup("\ - "id INTEGER PRIMARY KEY,"\ - "name TEXT,"\ - "parent INTEGER)" +_ctagmap = "CREATE TABLE ctagmap("\ + "tag_id INTEGER NOT NULL,"\ + "colorramp_id INTEGER)" _smartgroup = "CREATE TABLE smartgroup("\ "id INTEGER PRIMARY KEY,"\ "name TEXT,"\ "xml TEXT)" -_ctagmap = "CREATE TABLE ctagmap("\ - "tag_id INTEGER NOT NULL,"\ - "colorramp_id INTEGER)" - -create_tables = [ _symbol, _colorramp, _tag, _tagmap, _ctagmap, _symgroup, _smartgroup ] +create_tables = [_symbol, _colorramp, _tag, _tagmap, _ctagmap, _smartgroup] # Create the DB with required Schema -conn = sqlite3.connect( dbfile ) +conn = sqlite3.connect(dbfile) c = conn.cursor() print "Creating tables in the Database\n" for table in create_tables: try: - c.execute( table ) + c.execute(table) print table except sqlite3.OperationalError as e: pass conn.commit() # parse the XML file & write symbol into DB -dom = parse( xmlfile ) -symbols = dom.getElementsByTagName( "symbol" ) +dom = parse(xmlfile) +symbols = dom.getElementsByTagName("symbol") for symbol in symbols: - symbol_name = symbol.getAttribute( "name" ) + symbol_name = symbol.getAttribute("name") + symbol_favorite = symbol.getAttribute("favorite") + if not symbol_favorite: + symbol_favorite = 0 + if '@' in symbol_name: parts = symbol_name.split('@') parent_name = parts[1] layerno = int(parts[2]) - c.execute( "SELECT xml FROM symbol WHERE name=(?)", (parent_name,) ) - symdom = parseString( c.fetchone()[0] ).getElementsByTagName( 'symbol' )[0] - symdom.getElementsByTagName( "layer" )[ layerno ].appendChild( symbol ) - c.execute( "UPDATE symbol SET xml=? WHERE name=?", ( symdom.toxml(), parent_name )) + c.execute("SELECT xml FROM symbol WHERE name=(?)", (parent_name,)) + symdom = parseString(c.fetchone()[0]).getElementsByTagName('symbol')[0] + symdom.getElementsByTagName("layer")[layerno].appendChild(symbol) + c.execute("UPDATE symbol SET xml=? WHERE name=?", (symdom.toxml(), parent_name)) else: - c.execute( "INSERT INTO symbol VALUES (?,?,?,?)", ( None, symbol_name, symbol.toxml(), 0 ) ) + c.execute("INSERT INTO symbol VALUES (?,?,?,?)", (None, symbol_name, symbol.toxml(), symbol_favorite)) conn.commit() # ColorRamps -colorramps = dom.getElementsByTagName( "colorramp" ) +colorramps = dom.getElementsByTagName("colorramp") for ramp in colorramps: - ramp_name = ramp.getAttribute( "name" ) - c.execute( "INSERT INTO colorramp VALUES (?,?,?,?)", ( None, ramp_name, ramp.toxml(), 0 ) ) + ramp_name = ramp.getAttribute("name") + symbol_favorite = symbol.getAttribute("favorite") + if not symbol_favorite: + symbol_favorite = 0 + + c.execute("INSERT INTO colorramp VALUES (?,?,?,?)", (None, ramp_name, ramp.toxml(), symbol_favorite)) conn.commit() # Finally close the sqlite cursor diff --git a/src/core/symbology-ng/qgsstyle.cpp b/src/core/symbology-ng/qgsstyle.cpp index 4410974001d..cc7d03b377e 100644 --- a/src/core/symbology-ng/qgsstyle.cpp +++ b/src/core/symbology-ng/qgsstyle.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -96,13 +97,13 @@ bool QgsStyle::addSymbol( const QString& name, QgsSymbol* symbol, bool update ) { mSymbols.insert( name, symbol ); if ( update ) - saveSymbol( name, symbol, 0, QStringList() ); + saveSymbol( name, symbol, false, QStringList() ); } return true; } -bool QgsStyle::saveSymbol( const QString& name, QgsSymbol* symbol, int groupid, const QStringList& tags ) +bool QgsStyle::saveSymbol( const QString& name, QgsSymbol* symbol, bool favorite, const QStringList& tags ) { // TODO add support for groups QDomDocument doc( QStringLiteral( "dummy" ) ); @@ -118,7 +119,7 @@ bool QgsStyle::saveSymbol( const QString& name, QgsSymbol* symbol, int groupid, stream.setCodec( "UTF-8" ); symEl.save( stream, 4 ); char *query = sqlite3_mprintf( "INSERT INTO symbol VALUES (NULL, '%q', '%q', %d);", - name.toUtf8().constData(), xmlArray.constData(), groupid ); + name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) ); if ( !runEmptyQuery( query ) ) { @@ -207,11 +208,12 @@ bool QgsStyle::addColorRamp( const QString& name, QgsColorRamp* colorRamp, bool return true; } -bool QgsStyle::saveColorRamp( const QString& name, QgsColorRamp* ramp, int groupid, const QStringList& tags ) +bool QgsStyle::saveColorRamp( const QString& name, QgsColorRamp* ramp, bool favorite, const QStringList& tags ) { // insert it into the database QDomDocument doc( QStringLiteral( "dummy" ) ); QDomElement rampEl = QgsSymbolLayerUtils::saveColorRamp( name, ramp, doc ); + if ( rampEl.isNull() ) { QgsDebugMsg( "Couldn't convert color ramp to valid XML!" ); @@ -223,8 +225,7 @@ bool QgsStyle::saveColorRamp( const QString& name, QgsColorRamp* ramp, int group stream.setCodec( "UTF-8" ); rampEl.save( stream, 4 ); char *query = sqlite3_mprintf( "INSERT INTO colorramp VALUES (NULL, '%q', '%q', %d);", - name.toUtf8().constData(), xmlArray.constData(), groupid ); - + name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) ); if ( !runEmptyQuery( query ) ) { QgsDebugMsg( "Couldn't insert colorramp into the database!" ); @@ -301,8 +302,8 @@ bool QgsStyle::load( const QString& filename ) } // Make sure there are no Null fields in parenting symbols ang groups - char *query = sqlite3_mprintf( "UPDATE symbol SET groupid=0 WHERE groupid IS NULL;" - "UPDATE colorramp SET groupid=0 WHERE groupid IS NULL;" + char *query = sqlite3_mprintf( "UPDATE symbol SET favorite=0 WHERE favorite IS NULL;" + "UPDATE colorramp SET favorite=0 WHERE favorite IS NULL;" "UPDATE symgroup SET parent=0 WHERE parent IS NULL;" ); runEmptyQuery( query ); @@ -460,97 +461,22 @@ bool QgsStyle::renameColorRamp( const QString& oldName, const QString& newName ) return true; } -QStringList QgsStyle::groupNames() -{ - QStringList groupNames; - sqlite3_stmt *ppStmt; - const char *query = "SELECT * FROM symgroup"; - int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) - { - groupNames << QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, SymgroupName ) ) ); - } - sqlite3_finalize( ppStmt ); - return groupNames; -} - -QList QgsStyle::groupIds() const -{ - QList groupIds; - sqlite3_stmt *ppStmt; - const char *query = "SELECT * FROM symgroup"; - int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) - { - groupIds << QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, SymgroupId ) ) ).toInt(); - } - sqlite3_finalize( ppStmt ); - return groupIds; -} - -QgsSymbolGroupMap QgsStyle::childGroupNames( const QString& parent ) -{ - // get the name list from the sqlite database and return as a QStringList - if ( !mCurrentDB ) - { - QgsDebugMsg( "Cannot open database for listing groups" ); - return QgsSymbolGroupMap(); - } - - char *query = nullptr; - int nError; - sqlite3_stmt *ppStmt; - - // decide the query to be run based on parent group - if ( parent == QLatin1String( "" ) || parent == QString() ) - { - query = sqlite3_mprintf( "SELECT * FROM symgroup WHERE parent=0" ); - } - else - { - char *subquery = sqlite3_mprintf( "SELECT * FROM symgroup WHERE name='%q'", parent.toUtf8().constData() ); - nError = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt, nullptr ); - if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) - { - query = sqlite3_mprintf( "SELECT * FROM symgroup WHERE parent=%d", sqlite3_column_int( ppStmt, SymgroupId ) ); - } - sqlite3_finalize( ppStmt ); - } - - if ( !query ) - return QgsSymbolGroupMap(); - - QgsSymbolGroupMap groupNames; - - // Now run the query and retrieve the group names - nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) - { - QString group = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( ppStmt, SymgroupName ) ) ); - groupNames.insert( sqlite3_column_int( ppStmt, SymgroupId ), group ); - } - - sqlite3_finalize( ppStmt ); - - return groupNames; -} - -QStringList QgsStyle::symbolsOfGroup( StyleEntity type, int groupid ) +QStringList QgsStyle::symbolsOfFavorite( StyleEntity type ) const { if ( !mCurrentDB ) { - QgsDebugMsg( QString( "Cannot Open database for getting group symbols of groupid: %1" ).arg( groupid ) ); + QgsDebugMsg( QString( "Cannot Open database for getting favorite symbols" ) ); return QStringList(); } char *query; if ( type == SymbolEntity ) { - query = sqlite3_mprintf( "SELECT name FROM symbol WHERE groupid=%d", groupid ); + query = sqlite3_mprintf( "SELECT name FROM symbol WHERE favorite=1" ); } else if ( type == ColorrampEntity ) { - query = sqlite3_mprintf( "SELECT name FROM colorramp WHERE groupid=%d", groupid ); + query = sqlite3_mprintf( "SELECT name FROM colorramp WHERE favorite=1" ); } else { @@ -572,7 +498,7 @@ QStringList QgsStyle::symbolsOfGroup( StyleEntity type, int groupid ) return symbols; } -QStringList QgsStyle::symbolsWithTag( StyleEntity type, int tagid ) +QStringList QgsStyle::symbolsWithTag( StyleEntity type, int tagid ) const { if ( !mCurrentDB ) { @@ -587,7 +513,7 @@ QStringList QgsStyle::symbolsWithTag( StyleEntity type, int tagid ) } else if ( type == ColorrampEntity ) { - subquery = sqlite3_mprintf( "SELECT symbol_id FROM ctagmap WHERE tag_id=%d", tagid ); + subquery = sqlite3_mprintf( "SELECT colorramp_id FROM ctagmap WHERE tag_id=%d", tagid ); } else { @@ -598,15 +524,15 @@ QStringList QgsStyle::symbolsWithTag( StyleEntity type, int tagid ) sqlite3_stmt *ppStmt; int nErr = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt, nullptr ); - // get the symbol <-> tag connection from table 'tagmap' + // get the symbol <-> tag connection from table 'tagmap'/'ctagmap' QStringList symbols; while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) { - int symbolId = sqlite3_column_int( ppStmt, 0 ); + int id = sqlite3_column_int( ppStmt, 0 ); char *query = type == SymbolEntity - ? sqlite3_mprintf( "SELECT name FROM symbol WHERE id=%d", symbolId ) - : sqlite3_mprintf( "SELECT name FROM colorramp WHERE id=%d", symbolId ); + ? sqlite3_mprintf( "SELECT name FROM symbol WHERE id=%d", id ) + : sqlite3_mprintf( "SELECT name FROM colorramp WHERE id=%d", id ); sqlite3_stmt *ppStmt2; int sErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt2, nullptr ); @@ -621,23 +547,6 @@ QStringList QgsStyle::symbolsWithTag( StyleEntity type, int tagid ) return symbols; } -int QgsStyle::addGroup( const QString& groupName, int parentid ) -{ - if ( !mCurrentDB ) - return 0; - - char *query = sqlite3_mprintf( "INSERT INTO symgroup VALUES (NULL, '%q', %d)", groupName.toUtf8().constData(), parentid ); - - sqlite3_stmt *ppStmt; - int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - if ( nErr == SQLITE_OK ) - ( void )sqlite3_step( ppStmt ); - - sqlite3_finalize( ppStmt ); - - return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB ) ); -} - int QgsStyle::addTag( const QString& tagname ) { if ( !mCurrentDB ) @@ -650,6 +559,11 @@ int QgsStyle::addTag( const QString& tagname ) ( void )sqlite3_step( ppStmt ); sqlite3_finalize( ppStmt ); + QSettings settings; + settings.setValue( QStringLiteral( "qgis/symbolsListGroupsIndex" ), 0 ); + + emit groupsModified(); + return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB ) ); } @@ -676,69 +590,60 @@ QStringList QgsStyle::tags() const void QgsStyle::rename( StyleEntity type, int id, const QString& newName ) { + bool groupRenamed = false; char *query; switch ( type ) { case SymbolEntity: query = sqlite3_mprintf( "UPDATE symbol SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id ); break; - case GroupEntity: - query = sqlite3_mprintf( "UPDATE symgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id ); - break; - case TagEntity: - query = sqlite3_mprintf( "UPDATE tag SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id ); - break; case ColorrampEntity: query = sqlite3_mprintf( "UPDATE colorramp SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id ); break; + case TagEntity: + query = sqlite3_mprintf( "UPDATE tag SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id ); + groupRenamed = true; + break; case SmartgroupEntity: query = sqlite3_mprintf( "UPDATE smartgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id ); + groupRenamed = true; break; default: QgsDebugMsg( "Invalid Style Entity indicated" ); return; } if ( !runEmptyQuery( query ) ) + { mErrorString = QStringLiteral( "Could not rename!" ); -} - -char* QgsStyle::getGroupRemoveQuery( int id ) -{ - char *query = sqlite3_mprintf( "SELECT parent FROM symgroup WHERE id=%d", id ); - - sqlite3_stmt *ppStmt; - int err = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - - int parentid = 0; - if ( err == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) - parentid = sqlite3_column_int( ppStmt, 0 ); - - sqlite3_finalize( ppStmt ); - - return sqlite3_mprintf( "UPDATE symbol SET groupid=%d WHERE groupid=%d;" - "UPDATE symgroup SET parent=%d WHERE parent=%d;" - "DELETE FROM symgroup WHERE id=%d", parentid, id, parentid, id, id ); + } + else + { + if ( groupRenamed ) + { + emit groupsModified(); + } + } } void QgsStyle::remove( StyleEntity type, int id ) { + bool groupRemoved = false; char *query; switch ( type ) { case SymbolEntity: query = sqlite3_mprintf( "DELETE FROM symbol WHERE id=%d; DELETE FROM tagmap WHERE symbol_id=%d", id, id ); break; - case GroupEntity: - query = getGroupRemoveQuery( id ); - break; - case TagEntity: - query = sqlite3_mprintf( "DELETE FROM tag WHERE id=%d; DELETE FROM tagmap WHERE tag_id=%d", id, id ); - break; case ColorrampEntity: query = sqlite3_mprintf( "DELETE FROM colorramp WHERE id=%d", id ); break; + case TagEntity: + query = sqlite3_mprintf( "DELETE FROM tag WHERE id=%d; DELETE FROM tagmap WHERE tag_id=%d", id, id ); + groupRemoved = true; + break; case SmartgroupEntity: query = sqlite3_mprintf( "DELETE FROM smartgroup WHERE id=%d", id ); + groupRemoved = true; break; default: QgsDebugMsg( "Invalid Style Entity indicated" ); @@ -749,6 +654,16 @@ void QgsStyle::remove( StyleEntity type, int id ) { QgsDebugMsg( "Could not delete entity!" ); } + else + { + if ( groupRemoved ) + { + QSettings settings; + settings.setValue( QStringLiteral( "qgis/symbolsListGroupsIndex" ), 0 ); + + emit groupsModified(); + } + } } bool QgsStyle::runEmptyQuery( char *query, bool freeQuery ) @@ -772,17 +687,38 @@ bool QgsStyle::runEmptyQuery( char *query, bool freeQuery ) return zErr == SQLITE_OK; } -bool QgsStyle::group( StyleEntity type, const QString& name, int groupid ) +bool QgsStyle::addFavorite( StyleEntity type, const QString& name ) { char *query; switch ( type ) { case SymbolEntity: - query = sqlite3_mprintf( "UPDATE symbol SET groupid=%d WHERE name='%q'", groupid, name.toUtf8().constData() ); + query = sqlite3_mprintf( "UPDATE symbol SET favorite=1 WHERE name='%q'", name.toUtf8().constData() ); break; case ColorrampEntity: - query = sqlite3_mprintf( "UPDATE colorramp SET groupid=%d WHERE name='%q'", groupid, name.toUtf8().constData() ); + query = sqlite3_mprintf( "UPDATE colorramp SET favorite=1 WHERE name='%q'", name.toUtf8().constData() ); + break; + + default: + QgsDebugMsg( "Wrong entity value. cannot apply group" ); + return false; + } + + return runEmptyQuery( query ); +} + +bool QgsStyle::removeFavorite( StyleEntity type, const QString& name ) +{ + char *query; + + switch ( type ) + { + case SymbolEntity: + query = sqlite3_mprintf( "UPDATE symbol SET favorite=0 WHERE name='%q'", name.toUtf8().constData() ); + break; + case ColorrampEntity: + query = sqlite3_mprintf( "UPDATE colorramp SET favorite=0 WHERE name='%q'", name.toUtf8().constData() ); break; default: @@ -882,37 +818,41 @@ bool QgsStyle::tagSymbol( StyleEntity type, const QString& symbol, const QString return false; } - - Q_FOREACH ( const QString &tag, tags ) + QString tag; + Q_FOREACH ( const QString &t, tags ) { - // sql: gets the id of the tag if present or insert the tag and get the id of the tag - char *query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() ); - - sqlite3_stmt *ppStmt; - int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - - int tagid; - if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) + tag = t.trimmed(); + if ( tag != "" ) { - tagid = sqlite3_column_int( ppStmt, 0 ); - } - else - { - tagid = addTag( tag ); - } + // sql: gets the id of the tag if present or insert the tag and get the id of the tag + char *query = sqlite3_mprintf( "SELECT id FROM tag WHERE LOWER(name)='%q'", tag.toUtf8().toLower().constData() ); - sqlite3_finalize( ppStmt ); + sqlite3_stmt *ppStmt; + int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); - // 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 ); + int tagid; + if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) + { + tagid = sqlite3_column_int( ppStmt, 0 ); + } + else + { + tagid = addTag( tag ); + } - char *zErr = nullptr; - nErr = sqlite3_exec( mCurrentDB, query, nullptr, nullptr, &zErr ); - if ( nErr ) - { - QgsDebugMsg( zErr ); + 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 ) + { + QgsDebugMsg( zErr ); + } } } @@ -977,6 +917,45 @@ bool QgsStyle::detagSymbol( StyleEntity type, const QString& symbol, const QStri return true; } +bool QgsStyle::detagSymbol( StyleEntity type, const QString& symbol ) +{ + if ( !mCurrentDB ) + { + QgsDebugMsg( "Sorry! Cannot open database for detgging." ); + return false; + } + + char *query = type == SymbolEntity + ? sqlite3_mprintf( "SELECT id FROM symbol WHERE name='%q'", symbol.toUtf8().constData() ) + : sqlite3_mprintf( "SELECT id FROM colorramp WHERE name='%q'", symbol.toUtf8().constData() ); + sqlite3_stmt *ppStmt; + int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); + + int symbolid = 0; + if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) + { + symbolid = sqlite3_column_int( ppStmt, 0 ); + } + else + { + sqlite3_finalize( ppStmt ); + return false; + } + + sqlite3_finalize( ppStmt ); + + // remove all tags + query = type == SymbolEntity + ? sqlite3_mprintf( "DELETE FROM tagmap WHERE symbol_id=%d", symbolid ) + : sqlite3_mprintf( "DELETE FROM ctagmap WHERE colorramp_id=%d", symbolid ); + runEmptyQuery( query ); + + // TODO Perform tag cleanup + // check the number of entries for a given tag in the tagmap + // if the count is 0, then remove( TagEntity, tagid ) + return true; +} + QStringList QgsStyle::tagsOfSymbol( StyleEntity type, const QString& symbol ) { if ( !mCurrentDB ) @@ -1018,7 +997,7 @@ QStringList QgsStyle::tagsOfSymbol( StyleEntity type, const QString& symbol ) int QgsStyle::getId( const QString& table, const QString& name ) { - char *query = sqlite3_mprintf( "SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() ); + char *query = sqlite3_mprintf( "SELECT id FROM %q WHERE LOWER(name)='%q'", table.toUtf8().constData(), name.toUtf8().toLower().constData() ); sqlite3_stmt *ppStmt; int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, nullptr ); @@ -1062,16 +1041,6 @@ int QgsStyle::colorrampId( const QString& name ) return getId( QStringLiteral( "colorramp" ), name ); } -int QgsStyle::groupId( const QString& name ) -{ - return getId( QStringLiteral( "symgroup" ), name ); -} - -QString QgsStyle::groupName( int groupId ) const -{ - return getName( QStringLiteral( "symgroup" ), groupId ); -} - int QgsStyle::tagId( const QString& name ) { return getId( QStringLiteral( "tag" ), name ); @@ -1113,6 +1082,10 @@ int QgsStyle::addSmartgroup( const QString& name, const QString& op, const QgsSm if ( runEmptyQuery( query ) ) { + QSettings settings; + settings.setValue( QStringLiteral( "qgis/symbolsListGroupsIndex" ), 0 ); + + emit groupsModified(); return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB ) ); } else @@ -1211,12 +1184,6 @@ QStringList QgsStyle::symbolsOfSmartgroup( StyleEntity type, int id ) { resultNames = symbolsWithTag( type, tagId( param ) ); } - else if ( constraint == QLatin1String( "group" ) ) - { - // XXX Validating group id might be a good idea here - resultNames = symbolsOfGroup( type, groupId( param ) ); - - } else if ( constraint == QLatin1String( "name" ) ) { if ( type == SymbolEntity ) @@ -1237,15 +1204,6 @@ QStringList QgsStyle::symbolsOfSmartgroup( StyleEntity type, int id ) resultNames.removeAll( name ); } } - else if ( constraint == QLatin1String( "!group" ) ) - { - resultNames = type == SymbolEntity ? symbolNames() : colorRampNames(); - QStringList unwanted = symbolsOfGroup( type, groupId( param ) ); - Q_FOREACH ( const QString& name, unwanted ) - { - resultNames.removeAll( name ); - } - } else if ( constraint == QLatin1String( "!name" ) ) { QStringList all = type == SymbolEntity ? symbolNames() : colorRampNames(); diff --git a/src/core/symbology-ng/qgsstyle.h b/src/core/symbology-ng/qgsstyle.h index 6c0edcf3262..9e415b00069 100644 --- a/src/core/symbology-ng/qgsstyle.h +++ b/src/core/symbology-ng/qgsstyle.h @@ -41,8 +41,6 @@ typedef QMap QgsSymbolGroupMap; * The supported constraints are: * tag -> symbol has the tag matching the parameter * !tag -> symbol doesnot have the tag matching the parameter - * group -> symbol belongs to group specified by the parameter - * !group -> symbol doesn't belong to the group specified by the parameter * name -> symbol has a part of its name matching the parameter * !name -> symbol doesn't have any part of the name matching the parameter * @@ -56,11 +54,10 @@ typedef QMap QgsSymbolGroupMap; typedef QMultiMap QgsSmartConditionMap; // enumerators representing sqlite DB columns -enum SymbolTable { SymbolId, SymbolName, SymbolXML, SymbolGroupId }; -enum SymgroupTable { SymgroupId, SymgroupName, SymgroupParent }; +enum SymbolTable { SymbolId, SymbolName, SymbolXML, SymbolFavoriteId }; enum TagTable { TagId, TagName }; enum TagmapTable { TagmapTagId, TagmapSymbolId }; -enum ColorrampTable { ColorrampId, ColorrampName, ColorrampXML, ColorrampGroupId }; +enum ColorrampTable { ColorrampId, ColorrampName, ColorrampXML, ColorrampFavoriteId }; enum SmartgroupTable { SmartgroupId, SmartgroupName, SmartgroupXML }; /** \ingroup core @@ -74,13 +71,23 @@ class CORE_EXPORT QgsStyle : public QObject QgsStyle(); ~QgsStyle(); - //! Enum for Entities involved in a style - /*! - The enumerator is used for identifying the entity being operated on when generic - database functions are being run. - \sa group(), rename(), remove(), symbolsOfGroup(), symbolsWithTag(), symbolsOfSmartgroup() + /** Enum for Entities involved in a style + * + * The enumerator is used for identifying the entity being operated on when generic + * database functions are being run. + * \sa rename(), remove(), symbolsOfFavorite(), symbolsWithTag(), symbolsOfSmartgroup() */ - enum StyleEntity { SymbolEntity, GroupEntity, TagEntity, ColorrampEntity, SmartgroupEntity }; + enum StyleEntity { SymbolEntity, TagEntity, ColorrampEntity, SmartgroupEntity }; + + /** Adds a symbol to style and takes symbol's ownership + * + * \note Adding a symbol with the name of existing one replaces it. + * \param name is the name of the symbol being added or updated + * \param symbol is the Vector symbol + * \param update set to true when the style DB has to be updated, by default it is false + * \return success status of the operation + */ + bool addSymbol( const QString& name, QgsSymbol* symbol, bool update = false ); /** Adds a color ramp to the style. Calling this method takes the ramp's ownership. * \note Adding a color ramp with the name of existing one replaces it. @@ -91,49 +98,29 @@ class CORE_EXPORT QgsStyle : public QObject */ bool addColorRamp( const QString& name, QgsColorRamp* colorRamp, bool update = false ); - //! adds a new group and returns the group's id - /*! - * \param groupName the name of the new group as QString - * \param parent is the id of the parent group when a subgrouo is to be created. By default it is 0 indicating it is not a sub-group - * \return returns an int, which is the DB id of the new group created, 0 if the group couldn't be created + /** Adds a new tag and returns the tag's id + * + * \param tagName the name of the new tag to be created + * \return returns an int, which is the DB id of the new tag created, 0 if the tag couldn't be created */ - int addGroup( const QString& groupName, int parent = 0 ); + int addTag( const QString& tagName ); - //! adds new smartgroup to the database and returns the id - /*! + /** Adds a new smartgroup to the database and returns the id + * * \param name is the name of the new Smart Group to be added * \param op is the operator between the conditions; AND/OR as QString * \param conditions are the smart group conditions */ int addSmartgroup( const QString& name, const QString& op, const QgsSmartConditionMap& conditions ); - //! add symbol to style. takes symbol's ownership - /*! - * \note Adding a symbol with the name of existing one replaces it. - * \param name is the name of the symbol being added or updated - * \param symbol is the Vector symbol - * \param update set to true when the style DB has to be updated, by default it is false - * \return success status of the operation - */ - bool addSymbol( const QString& name, QgsSymbol* symbol, bool update = false ); - - //! adds a new tag and returns the tag's id - /*! - * \param tagName the name of the new tag to be created - * \return returns an int, which is the DB id of the new tag created, 0 if the tag couldn't be created - */ - int addTag( const QString& tagName ); - /** Returns a list of all tags in the style database + * * @note added in QGIS 2.16 * @see addTag() */ QStringList tags() const; - //! return a map of groupid and names for the given parent group - QgsSymbolGroupMap childGroupNames( const QString& parent = "" ); - - //! remove all contents of the style + //! Removes all contents of the style void clear(); /** Returns a new copy of the specified color ramp. The caller @@ -141,24 +128,25 @@ class CORE_EXPORT QgsStyle : public QObject */ QgsColorRamp* colorRamp( const QString& name ) const; - //! return count of color ramps + //! Returns count of color ramps int colorRampCount(); - //! return a list of names of color ramps + //! Returns a list of names of color ramps QStringList colorRampNames(); - //! return a const pointer to a symbol (doesn't create new instance) + //! Returns a const pointer to a symbol (doesn't create new instance) const QgsColorRamp* colorRampRef( const QString& name ) const; - //! return the id in the style database for the given colorramp name - //! returns 0 if not found + /** Returns the id in the style database for the given colorramp name + * returns 0 if not found + */ int colorrampId( const QString& name ); - //! return default application-wide style + //! Returns default application-wide style static QgsStyle* defaultStyle(); - //! tags the symbol with the tags in the list - /*! + /** Tags the symbol with the tags in the list + * * Applies the given tags to the given symbol or colorramp * \param type is either SymbolEntity or ColorrampEntity * \param symbol is the name of the symbol or colorramp as QString @@ -167,8 +155,8 @@ class CORE_EXPORT QgsStyle : public QObject */ bool tagSymbol( StyleEntity type, const QString& symbol, const QStringList& tags ); - //! detags the symbol with the given list - /*! + /** Detags the symbol with the given list + * * Removes the given tags for the specified symbol or colorramp * \param type is either SymbolEntity or ColorrampEntity * \param symbol is the name of the symbol or colorramp @@ -177,150 +165,157 @@ class CORE_EXPORT QgsStyle : public QObject */ bool detagSymbol( StyleEntity type, const QString& symbol, const QStringList& tags ); - //! remove symbol from style (and delete it) + /** Clears the symbol from all attached tags + * + * Removes all tags for the specified symbol or colorramp + * \param type is either SymbolEntity or ColorrampEntity + * \param symbol is the name of the symbol or colorramp + * \return returns the success state of the operation + */ + bool detagSymbol( StyleEntity type, const QString& symbol ); + + //! Removes symbol from style (and delete it) bool removeSymbol( const QString& name ); - //! change symbol's name + //! Changessymbol's name bool renameSymbol( const QString& oldName, const QString& newName ); - //! return a NEW copy of symbol + //! Returns a NEW copy of symbol QgsSymbol* symbol( const QString& name ); - //! return a const pointer to a symbol (doesn't create new instance) + //! Returns a const pointer to a symbol (doesn't create new instance) const QgsSymbol* symbolRef( const QString& name ) const; - //! return count of symbols in style + //! Returns count of symbols in style int symbolCount(); - //! return a list of names of symbols + //! Returns a list of names of symbols QStringList symbolNames(); - //! return the id in the style database for the given symbol name - //! returns 0 if not found + /** Returns the id in the style database for the given symbol name + * returns 0 if not found + */ int symbolId( const QString& name ); - //! return the DB id for the given group name - int groupId( const QString& group ); - //! return the group name for the given DB id - QString groupName( int groupId ) const; - //! return the DB id for the given tag name + //! Returns the DB id for the given tag name int tagId( const QString& tag ); - //! return the DB id for the given smartgroup name + //! Returns the DB id for the given smartgroup name int smartgroupId( const QString& smartgroup ); - //! return the all the groups in the style - QStringList groupNames(); - - //! return the ids of all the groups in the style - QList groupIds() const; - - //! returns the symbolnames of a given groupid - /*! + /** Returns the symbol names which are flagged as favorite + * * \param type is either SymbolEntity or ColorampEntity - * \param groupid is id of the group to which the symbols belong to, as int - * \return A QStringList of the symbol or colorramp names for the given group id + * \return A QStringList of the symbol or colorramp names flagged as favorite */ - QStringList symbolsOfGroup( StyleEntity type, int groupid ); + QStringList symbolsOfFavorite( StyleEntity type ) const; - //! returns the symbol names with which have the given tag - /*! + /** Returns the symbol names with which have the given tag + * * \param type is either SymbolEntity or ColorampEntity * \param tagid is id of the tag which has been applied over the symbol as int * \return A QStringList of the symbol or colorramp names for the given tag id */ - QStringList symbolsWithTag( StyleEntity type, int tagid ); + QStringList symbolsWithTag( StyleEntity type, int tagid ) const; - //! applies the specified group to the symbol or colorramp specified by StyleEntity - /*! + /** Adds the specified symbol to favorites + * * \param type is either SymbolEntity of ColorrampEntity - * \param name is the name of the symbol or coloramp whose group is to be set - * \param groupid is the id of the group to which the entity is assigned + * \param name is the name of the symbol or coloramp whose is to be added to favorites * \return returns the success state as bool */ - bool group( StyleEntity type, const QString& name, int groupid ); + bool addFavorite( StyleEntity type, const QString& name ); - //! rename the given entity with the specified id - /*! + /** Removes the specified symbol from favorites + * + * \param type is either SymbolEntity of ColorrampEntity + * \param name is the name of the symbol or coloramp whose is to be removed from favorites + * \return returns the success state as bool + */ + bool removeFavorite( StyleEntity type, const QString& name ); + + /** Renames the given entity with the specified id + * * \param type is any of the style entites. Refer enum StyleEntity. * \param id is the DB id of the entity which is to be renamed * \param newName is the new name of the entity */ void rename( StyleEntity type, int id, const QString& newName ); - //! remove the specified entity from the db - /*! + /** Removes the specified entity from the db + * * \param type is any of the style entites. Refer enum StyleEntity. * \param id is the DB id of the entity to be removed */ void remove( StyleEntity type, int id ); - //! add the symbol to the DB with the tags - /*! + /** Adds the symbol to the DB with the tags + * * \param name is the name of the symbol as QString * \param symbol is the pointer to the new QgsSymbol being saved - * \param groupid is the id of the group to which the symbol belongs. Pass 0 if it doesn't belong to any group or not known. + * \param favorite is a boolean value to specify whether the symbol should be added to favorites * \param tags is a list of tags that are associated with the symbol as a QStringList. * \return returns the success state of the save operation */ - bool saveSymbol( const QString& name, QgsSymbol* symbol, int groupid, const QStringList& tags ); + bool saveSymbol( const QString& name, QgsSymbol* symbol, bool favorite, const QStringList& tags ); - //! add the colorramp to the DB - /*! + /** Adds the colorramp to the DB + * * \param name is the name of the colorramp as QString * \param ramp is the pointer to the new QgsColorRamp being saved - * \param groupid is the id of the group to which the Color Ramp belongs. Pass 0 if it doesn't belong to any group or not known. + * \param favorite is a boolean value to specify whether the colorramp should be added to favorites * \param tags is a list of tags that are associated with the color ramp as a QStringList. * \return returns the success state of the save operation */ - bool saveColorRamp( const QString& name, QgsColorRamp* ramp, int groupid, const QStringList& tags ); + bool saveColorRamp( const QString& name, QgsColorRamp* ramp, bool favorite, const QStringList& tags ); - //! remove color ramp from style (and delete it) + //! Removes color ramp from style (and delete it) bool removeColorRamp( const QString& name ); - //! change ramp's name + //! Changes ramp's name bool renameColorRamp( const QString& oldName, const QString& newName ); - //! load a file into the style + //! Loads a file into the style bool load( const QString& filename ); - //! save style into a file (will use current filename if empty string is passed) + //! Saves style into a file (will use current filename if empty string is passed) bool save( QString filename = QString() ); - //! return last error from load/save operation + //! Returns last error from load/save operation QString errorString() { return mErrorString; } - //! return current file name of the style + //! Returns current file name of the style QString fileName() { return mFileName; } - //! return the names of the symbols which have a matching 'substring' in its defintion - /*! + /** Returns the names of the symbols which have a matching 'substring' in its defintion + * * \param type is either SymbolEntity or ColorrampEntity * \param qword is the query string to search the symbols or colorramps. * \return A QStringList of the matched symbols or colorramps * */ QStringList findSymbols( StyleEntity type, const QString& qword ); - //! return the tags associated with the symbol - /*! + /** Returns the tags associated with the symbol + * * \param type is either SymbolEntity or ColorrampEntity * \param symbol is the name of the symbol or color ramp * \return A QStringList of the tags that have been applied to that symbol/colorramp */ QStringList tagsOfSymbol( StyleEntity type, const QString& symbol ); - //! returns the smart groups map with id as key and name as value + //! Returns the smart groups map with id as key and name as value QgsSymbolGroupMap smartgroupsListMap(); - //! returns the smart groups list + //! Returns the smart groups list QStringList smartgroupNames(); - //! returns the QgsSmartConditionMap for the given id + //! Returns the QgsSmartConditionMap for the given id QgsSmartConditionMap smartgroup( int id ); - //! returns the operator for the smartgroup - //clumsy implementation TODO create a class for smartgroups + /** Returns the operator for the smartgroup + * clumsy implementation TODO create a class for smartgroups + */ QString smartgroupOperator( int id ); - //! returns the symbols for the smartgroup + //! Returns the symbols for the smartgroup QStringList symbolsOfSmartgroup( StyleEntity type, int id ); //! Exports the style as a XML file @@ -330,7 +325,10 @@ class CORE_EXPORT QgsStyle : public QObject bool importXml( const QString& filename ); signals: + //! Is emitted every time a new symbol has been added to the database void symbolSaved( const QString& name, QgsSymbol* symbol ); + //! Is emitted every time a tag or smartgroup has been added, removed, or renamed + void groupsModified(); protected: @@ -344,26 +342,25 @@ class CORE_EXPORT QgsStyle : public QObject static QgsStyle* mDefaultStyle; - //! convenience function to open the DB and return a sqlite3 object + //! Convenience function to open the DB and return a sqlite3 object bool openDB( const QString& filename ); - //! convenience function that would run queries which don't generate return values - //! \param query query to run - //! \param freeQuery release query memory - //! \return success true on success + /** Convenience function that would run queries which don't generate return values + * + * \param query query to run + * \param freeQuery release query memory + * \return success true on success + */ bool runEmptyQuery( char* query, bool freeQuery = true ); - //! prepares the complex query for removing a group, so that the children are not abandoned - char* getGroupRemoveQuery( int id ); - - //! gets the id from the table for the given name from the database, 0 if not found + //! Gets the id from the table for the given name from the database, 0 if not found int getId( const QString& table, const QString& name ); - //! gets the name from the table for the given id from the database, empty if not found + //! Gets the name from the table for the given id from the database, empty if not found QString getName( const QString& table, int id ) const; - //! updates the properties of an existing symbol/colorramp - /*! + /** Updates the properties of an existing symbol/colorramp + * * \note This should not be called separately, only called through addSymbol or addColorRamp * \param type is either SymbolEntity or ColorrampEntity * \param name is the name of an existing symbol or a color ramp diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index fe02b7cade1..4f91772b43c 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -38,6 +38,7 @@ SET(QGIS_GUI_SRCS symbology-ng/qgsstyleexportimportdialog.cpp symbology-ng/qgsstylegroupselectiondialog.cpp symbology-ng/qgsstylemanagerdialog.cpp + symbology-ng/qgsstylesavedialog.cpp symbology-ng/qgssvgselectorwidget.cpp symbology-ng/qgssymbollayerwidget.cpp symbology-ng/qgssymbollevelsdialog.cpp @@ -511,6 +512,7 @@ SET(QGIS_GUI_MOC_HDRS symbology-ng/qgsstyleexportimportdialog.h symbology-ng/qgsstylegroupselectiondialog.h symbology-ng/qgsstylemanagerdialog.h + symbology-ng/qgsstylesavedialog.h symbology-ng/qgssvgselectorwidget.h symbology-ng/qgssymbollayerwidget.h symbology-ng/qgssymbollevelsdialog.h diff --git a/src/gui/symbology-ng/qgssmartgroupeditordialog.cpp b/src/gui/symbology-ng/qgssmartgroupeditordialog.cpp index 7f60c0d5ac4..55a895c4788 100644 --- a/src/gui/symbology-ng/qgssmartgroupeditordialog.cpp +++ b/src/gui/symbology-ng/qgssmartgroupeditordialog.cpp @@ -31,10 +31,8 @@ QgsSmartGroupCondition::QgsSmartGroupCondition( int id, QWidget* parent ) : QWid mConditionId = id; mCondCombo->addItem( tr( "has the tag" ), QVariant( "tag" ) ); - mCondCombo->addItem( tr( "is a member of group" ), QVariant( "group" ) ); mCondCombo->addItem( tr( "has a part of name matching" ), QVariant( "name" ) ); mCondCombo->addItem( tr( "does NOT have the tag" ), QVariant( "!tag" ) ); - mCondCombo->addItem( tr( "is NOT a member of group" ), QVariant( "!group" ) ); mCondCombo->addItem( tr( "has NO part of name matching" ), QVariant( "!name" ) ); mRemoveBtn->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) ); @@ -159,7 +157,7 @@ QString QgsSmartGroupEditorDialog::conditionOperator() void QgsSmartGroupEditorDialog::setConditionMap( const QgsSmartConditionMap& map ) { QStringList constraints; - constraints << QStringLiteral( "tag" ) << QStringLiteral( "group" ) << QStringLiteral( "name" ) << QStringLiteral( "!tag" ) << QStringLiteral( "!group" ) << QStringLiteral( "!name" ); + constraints << QStringLiteral( "tag" ) << QStringLiteral( "name" ) << QStringLiteral( "!tag" ) << QStringLiteral( "!name" ); // clear any defaults Q_FOREACH ( int id, mConditionMap.keys() ) diff --git a/src/gui/symbology-ng/qgsstyleexportimportdialog.cpp b/src/gui/symbology-ng/qgsstyleexportimportdialog.cpp index eb2792cc30f..8e3a96127ae 100644 --- a/src/gui/symbology-ng/qgsstyleexportimportdialog.cpp +++ b/src/gui/symbology-ng/qgsstyleexportimportdialog.cpp @@ -35,7 +35,7 @@ QgsStyleExportImportDialog::QgsStyleExportImportDialog( QgsStyle* style, QWidget *parent, Mode mode ) : QDialog( parent ) , mDialogMode( mode ) - , mQgisStyle( style ) + , mStyle( style ) { setupUi( this ); @@ -73,12 +73,7 @@ QgsStyleExportImportDialog::QgsStyleExportImportDialog( QgsStyle* style, QWidget importTypeCombo->addItem( tr( "URL specified below" ), QVariant( "url" ) ); connect( importTypeCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( importTypeChanged( int ) ) ); - QStringList groups = mQgisStyle->groupNames(); - groupCombo->addItem( QStringLiteral( "imported" ), QVariant( "new" ) ); - Q_FOREACH ( const QString& gName, groups ) - { - groupCombo->addItem( gName ); - } + mSymbolTags->setText( "imported" ); btnBrowse->setText( QStringLiteral( "Browse" ) ); connect( btnBrowse, SIGNAL( clicked() ), this, SLOT( browse() ) ); @@ -96,14 +91,17 @@ QgsStyleExportImportDialog::QgsStyleExportImportDialog( QgsStyle* style, QWidget locationLabel->setHidden( true ); locationLineEdit->setHidden( true ); + mFavorite->setHidden( true ); + pb = new QPushButton( tr( "Select by group" ) ); buttonBox->addButton( pb, QDialogButtonBox::ActionRole ); connect( pb, SIGNAL( clicked() ), this, SLOT( selectByGroup() ) ); - groupLabel->setHidden( true ); - groupCombo->setHidden( true ); + tagLabel->setHidden( true ); + mSymbolTags->setHidden( true ); + tagHintLabel->setHidden( true ); buttonBox->button( QDialogButtonBox::Ok )->setText( tr( "Export" ) ); - if ( !populateStyles( mQgisStyle ) ) + if ( !populateStyles( mStyle ) ) { QApplication::postEvent( this, new QCloseEvent() ); } @@ -142,7 +140,7 @@ void QgsStyleExportImportDialog::doExportImport() mFileName = fileName; - moveStyles( &selection, mQgisStyle, mTempStyle ); + moveStyles( &selection, mStyle, mTempStyle ); if ( !mTempStyle->exportXml( mFileName ) ) { QMessageBox::warning( this, tr( "Export/import error" ), @@ -153,7 +151,7 @@ void QgsStyleExportImportDialog::doExportImport() } else // import { - moveStyles( &selection, mTempStyle, mQgisStyle ); + moveStyles( &selection, mTempStyle, mStyle ); // clear model QStandardItemModel* model = qobject_cast( listItems->model() ); @@ -222,26 +220,13 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl bool isSymbol = true; bool prompt = true; bool overwrite = true; - int groupid = 0; + QStringList tags; // get the groupid when going for import if ( mDialogMode == Import ) { // get the name the user entered - QString name = groupCombo->currentText(); - if ( name.isEmpty() ) - { - // import to "ungrouped" - groupid = 0; - } - else if ( dst->groupNames().contains( name ) ) - { - groupid = dst->groupId( name ); - } - else - { - groupid = dst->addGroup( name ); - } + tags = mSymbolTags->text().split( ',' ); } for ( int i = 0; i < selection->size(); ++i ) @@ -272,7 +257,7 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl case QMessageBox::Yes: dst->addSymbol( symbolName, symbol ); if ( mDialogMode == Import ) - dst->saveSymbol( symbolName, symbol, groupid, QStringList() ); + dst->saveSymbol( symbolName, symbol, mFavorite->isChecked(), tags ); continue; case QMessageBox::YesToAll: prompt = false; @@ -289,7 +274,7 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl { dst->addSymbol( symbolName, symbol ); if ( mDialogMode == Import ) - dst->saveSymbol( symbolName, symbol, groupid, QStringList() ); + dst->saveSymbol( symbolName, symbol, mFavorite->isChecked(), tags ); } else if ( dst->symbolNames().contains( symbolName ) && !overwrite ) { @@ -299,7 +284,7 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl { dst->addSymbol( symbolName, symbol ); if ( mDialogMode == Import ) - dst->saveSymbol( symbolName, symbol, groupid, QStringList() ); + dst->saveSymbol( symbolName, symbol, mFavorite->isChecked(), tags ); } } else @@ -319,7 +304,7 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl case QMessageBox::Yes: dst->addColorRamp( symbolName, ramp ); if ( mDialogMode == Import ) - dst->saveColorRamp( symbolName, ramp, groupid, QStringList() ); + dst->saveColorRamp( symbolName, ramp, mFavorite->isChecked(), tags ); continue; case QMessageBox::YesToAll: prompt = false; @@ -336,7 +321,7 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl { dst->addColorRamp( symbolName, ramp ); if ( mDialogMode == Import ) - dst->saveColorRamp( symbolName, ramp, groupid, QStringList() ); + dst->saveColorRamp( symbolName, ramp, mFavorite->isChecked(), tags ); } else if ( dst->colorRampNames().contains( symbolName ) && !overwrite ) { @@ -346,7 +331,7 @@ void QgsStyleExportImportDialog::moveStyles( QModelIndexList* selection, QgsStyl { dst->addColorRamp( symbolName, ramp ); if ( mDialogMode == Import ) - dst->saveColorRamp( symbolName, ramp, groupid, QStringList() ); + dst->saveColorRamp( symbolName, ramp, mFavorite->isChecked() , tags ); } } } @@ -394,36 +379,31 @@ void QgsStyleExportImportDialog::deselectSymbols( const QStringList& symbolNames } } -void QgsStyleExportImportDialog::selectGroup( const QString& groupName ) +void QgsStyleExportImportDialog::selectTag( const QString& tagName ) { - QStringList symbolNames = mQgisStyle->symbolsOfGroup( QgsStyle::SymbolEntity, mQgisStyle->groupId( groupName ) ); - selectSymbols( symbolNames ); - symbolNames = mQgisStyle->symbolsOfGroup( QgsStyle::ColorrampEntity, mQgisStyle->groupId( groupName ) ); + QStringList symbolNames = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( tagName ) ); selectSymbols( symbolNames ); } - -void QgsStyleExportImportDialog::deselectGroup( const QString& groupName ) +void QgsStyleExportImportDialog::deselectTag( const QString& tagName ) { - QStringList symbolNames = mQgisStyle->symbolsOfGroup( QgsStyle::SymbolEntity, mQgisStyle->groupId( groupName ) ); - deselectSymbols( symbolNames ); - symbolNames = mQgisStyle->symbolsOfGroup( QgsStyle::ColorrampEntity, mQgisStyle->groupId( groupName ) ); + QStringList symbolNames = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, mStyle->tagId( tagName ) ); deselectSymbols( symbolNames ); } void QgsStyleExportImportDialog::selectSmartgroup( const QString& groupName ) { - QStringList symbolNames = mQgisStyle->symbolsOfSmartgroup( QgsStyle::SymbolEntity, mQgisStyle->smartgroupId( groupName ) ); + QStringList symbolNames = mStyle->symbolsOfSmartgroup( QgsStyle::SymbolEntity, mStyle->smartgroupId( groupName ) ); selectSymbols( symbolNames ); - symbolNames = mQgisStyle->symbolsOfSmartgroup( QgsStyle::ColorrampEntity, mQgisStyle->smartgroupId( groupName ) ); + symbolNames = mStyle->symbolsOfSmartgroup( QgsStyle::ColorrampEntity, mStyle->smartgroupId( groupName ) ); selectSymbols( symbolNames ); } void QgsStyleExportImportDialog::deselectSmartgroup( const QString& groupName ) { - QStringList symbolNames = mQgisStyle->symbolsOfSmartgroup( QgsStyle::SymbolEntity, mQgisStyle->smartgroupId( groupName ) ); + QStringList symbolNames = mStyle->symbolsOfSmartgroup( QgsStyle::SymbolEntity, mStyle->smartgroupId( groupName ) ); deselectSymbols( symbolNames ); - symbolNames = mQgisStyle->symbolsOfSmartgroup( QgsStyle::ColorrampEntity, mQgisStyle->smartgroupId( groupName ) ); + symbolNames = mStyle->symbolsOfSmartgroup( QgsStyle::ColorrampEntity, mStyle->smartgroupId( groupName ) ); deselectSymbols( symbolNames ); } @@ -431,10 +411,10 @@ void QgsStyleExportImportDialog::selectByGroup() { if ( ! mGroupSelectionDlg ) { - mGroupSelectionDlg = new QgsStyleGroupSelectionDialog( mQgisStyle, this ); + mGroupSelectionDlg = new QgsStyleGroupSelectionDialog( mStyle, this ); mGroupSelectionDlg->setWindowTitle( tr( "Select symbols by group" ) ); - connect( mGroupSelectionDlg, SIGNAL( groupSelected( const QString ) ), this, SLOT( selectGroup( const QString ) ) ); - connect( mGroupSelectionDlg, SIGNAL( groupDeselected( const QString ) ), this, SLOT( deselectGroup( const QString ) ) ); + connect( mGroupSelectionDlg, SIGNAL( tagSelected( const QString ) ), this, SLOT( selectTag( const QString ) ) ); + connect( mGroupSelectionDlg, SIGNAL( tagDeselected( const QString ) ), this, SLOT( deselectTag( const QString ) ) ); connect( mGroupSelectionDlg, SIGNAL( allSelected() ), this, SLOT( selectAll() ) ); connect( mGroupSelectionDlg, SIGNAL( allDeselected() ), this, SLOT( clearSelection() ) ); connect( mGroupSelectionDlg, SIGNAL( smartgroupSelected( const QString ) ), this, SLOT( selectSmartgroup( const QString ) ) ); @@ -481,8 +461,8 @@ void QgsStyleExportImportDialog::browse() return; } QFileInfo pathInfo( mFileName ); - QString groupName = pathInfo.fileName().remove( QStringLiteral( ".xml" ) ); - groupCombo->setItemText( 0, groupName ); + QString tag = pathInfo.fileName().remove( QStringLiteral( ".xml" ) ); + mSymbolTags->setText( tag ); locationLineEdit->setText( mFileName ); populateStyles( mTempStyle ); } diff --git a/src/gui/symbology-ng/qgsstyleexportimportdialog.h b/src/gui/symbology-ng/qgsstyleexportimportdialog.h index 7ad6ecd2718..007e35123c9 100644 --- a/src/gui/symbology-ng/qgsstyleexportimportdialog.h +++ b/src/gui/symbology-ng/qgsstyleexportimportdialog.h @@ -80,16 +80,16 @@ class GUI_EXPORT QgsStyleExportImportDialog : public QDialog, private Ui::QgsSty void clearSelection(); /** - * Select the symbols belonging to the given group - * @param groupName the name of the group to be selected + * Select the symbols belonging to the given tag + * @param tagName the name of the group to be selected */ - void selectGroup( const QString& groupName ); + void selectTag( const QString& tagName ); /** - * Deselect the symbols belonging to the given group - * @param groupName the name of the group to be deselected + * Deselect the symbols belonging to the given tag + * @param tagName the name of the group to be deselected */ - void deselectGroup( const QString& groupName ); + void deselectTag( const QString& tagName ); /** * @brief selectSmartgroup selects all symbols from a smart group @@ -127,7 +127,7 @@ class GUI_EXPORT QgsStyleExportImportDialog : public QDialog, private Ui::QgsSty QString mFileName; Mode mDialogMode; - QgsStyle* mQgisStyle; + QgsStyle* mStyle; QgsStyle* mTempStyle; }; diff --git a/src/gui/symbology-ng/qgsstylegroupselectiondialog.cpp b/src/gui/symbology-ng/qgsstylegroupselectiondialog.cpp index 2b8a95d2281..ae15608f8e8 100644 --- a/src/gui/symbology-ng/qgsstylegroupselectiondialog.cpp +++ b/src/gui/symbology-ng/qgsstylegroupselectiondialog.cpp @@ -37,24 +37,19 @@ QgsStyleGroupSelectionDialog::QgsStyleGroupSelectionDialog( QgsStyle *style, QWi setBold( allSymbols ); model->appendRow( allSymbols ); - QStandardItem *group = new QStandardItem( QLatin1String( "" ) ); //require empty name to get first order groups - group->setData( "groupsheader", Qt::UserRole + 2 ); - group->setEditable( false ); - group->setFlags( group->flags() & ~Qt::ItemIsSelectable ); - buildGroupTree( group ); - group->setText( tr( "Groups" ) );//set title later - QStandardItem *ungrouped = new QStandardItem( tr( "Ungrouped" ) ); - ungrouped->setData( 0 ); - ungrouped->setData( "group", Qt::UserRole + 2 ); - setBold( ungrouped ); - setBold( group ); - group->appendRow( ungrouped ); - model->appendRow( group ); + QStandardItem *tags = new QStandardItem( QLatin1String( "" ) ); //require empty name to get first order groups + tags->setData( "tagsheader", Qt::UserRole + 2 ); + tags->setEditable( false ); + tags->setFlags( tags->flags() & ~Qt::ItemIsSelectable ); + buildTagTree( tags ); + tags->setText( tr( "Tags" ) );//set title later + setBold( tags ); + model->appendRow( tags ); QStandardItem *tag = new QStandardItem( tr( "Smart Groups" ) ); tag->setData( "smartgroupsheader" , Qt::UserRole + 2 ); tag->setEditable( false ); - tag->setFlags( group->flags() & ~Qt::ItemIsSelectable ); + tag->setFlags( tag->flags() & ~Qt::ItemIsSelectable ); setBold( tag ); QgsSymbolGroupMap sgMap = mStyle->smartgroupsListMap(); QgsSymbolGroupMap::const_iterator i = sgMap.constBegin(); @@ -100,7 +95,7 @@ void QgsStyleGroupSelectionDialog::groupTreeSelectionChanged( const QItemSelecti Q_FOREACH ( index, deselectedItems ) { - if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "groupsheader" ) ) + if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "tagssheader" ) ) { // Ignore: it's the group header } @@ -116,14 +111,14 @@ void QgsStyleGroupSelectionDialog::groupTreeSelectionChanged( const QItemSelecti { emit smartgroupDeselected( index.data().toString() ); } - else if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "group" ) ) - { // It's a group - emit groupDeselected( index.data().toString() ); + else if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "tag" ) ) + { // It's a tag + emit tagDeselected( index.data().toString() ); } } Q_FOREACH ( index, selectedItems ) { - if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "groupsheader" ) ) + if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "tagssheader" ) ) { // Ignore: it's the group header } @@ -139,27 +134,25 @@ void QgsStyleGroupSelectionDialog::groupTreeSelectionChanged( const QItemSelecti { emit smartgroupSelected( index.data().toString() ); } - else if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "group" ) ) - { // It's a group - emit groupSelected( index.data().toString() ); + else if ( index.data( Qt::UserRole + 2 ).toString() == QLatin1String( "tag" ) ) + { // It's a tag + emit tagSelected( index.data().toString() ); } } } -void QgsStyleGroupSelectionDialog::buildGroupTree( QStandardItem* &parent ) +void QgsStyleGroupSelectionDialog::buildTagTree( QStandardItem* &parent ) { - QgsSymbolGroupMap groups = mStyle->childGroupNames( parent->text() ); - QgsSymbolGroupMap::const_iterator i = groups.constBegin(); - while ( i != groups.constEnd() ) + QStringList tags = mStyle->tags(); + tags.sort(); + Q_FOREACH ( const QString& tag, tags ) { - QStandardItem *item = new QStandardItem( i.value() ); - item->setData( i.key() ); - item->setData( "group" , Qt::UserRole + 2 ); + QStandardItem *item = new QStandardItem( tag ); + item->setData( mStyle->tagId( tag ) ); + item->setData( "tag" , Qt::UserRole + 2 ); item->setEditable( false ); parent->appendRow( item ); - buildGroupTree( item ); - ++i; } } diff --git a/src/gui/symbology-ng/qgsstylegroupselectiondialog.h b/src/gui/symbology-ng/qgsstylegroupselectiondialog.h index ec370dbbc75..988efaddcc1 100644 --- a/src/gui/symbology-ng/qgsstylegroupselectiondialog.h +++ b/src/gui/symbology-ng/qgsstylegroupselectiondialog.h @@ -38,10 +38,10 @@ class GUI_EXPORT QgsStyleGroupSelectionDialog : public QDialog, private Ui::Symb void setBold( QStandardItem *item ); signals: - //! group with groupName has been selected - void groupSelected( const QString& groupName ); - //! group with groupName has been deselected - void groupDeselected( const QString& groupName ); + //! tag with tagName has been selected + void tagSelected( const QString& tagName ); + //! tag with tagName has been deselected + void tagDeselected( const QString& tagName ); //! smartgroup with groupName has been selected void smartgroupSelected( const QString& groupName ); //! smart group with groupName has been deselected @@ -60,7 +60,7 @@ class GUI_EXPORT QgsStyleGroupSelectionDialog : public QDialog, private Ui::Symb * @brief build group tree * @param parent */ - void buildGroupTree( QStandardItem *&parent ); + void buildTagTree( QStandardItem *&parent ); QgsStyle* mStyle; }; diff --git a/src/gui/symbology-ng/qgsstylemanagerdialog.cpp b/src/gui/symbology-ng/qgsstylemanagerdialog.cpp index f9ad62764a5..ecb8be3d62d 100644 --- a/src/gui/symbology-ng/qgsstylemanagerdialog.cpp +++ b/src/gui/symbology-ng/qgsstylemanagerdialog.cpp @@ -14,6 +14,7 @@ ***************************************************************************/ #include "qgsstylemanagerdialog.h" +#include "qgsstylesavedialog.h" #include "qgsstyle.h" #include "qgssymbol.h" @@ -111,16 +112,15 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle* style, QWidget* parent ) this, SLOT( groupRenamed( QStandardItem* ) ) ); QMenu *groupMenu = new QMenu( tr( "Group actions" ), this ); - connect( actnGroupSymbols, SIGNAL( triggered() ), this, SLOT( groupSymbolsAction() ) ); - groupMenu->addAction( actnGroupSymbols ); - connect( actnFinishGrouping, SIGNAL( triggered() ), this, SLOT( groupSymbolsAction() ) ); - actnFinishGrouping->setVisible( false ); - groupMenu->addAction( actnFinishGrouping ); + connect( actnTagSymbols, SIGNAL( triggered() ), this, SLOT( tagSymbolsAction() ) ); + groupMenu->addAction( actnTagSymbols ); + connect( actnFinishTagging, SIGNAL( triggered() ), this, SLOT( tagSymbolsAction() ) ); + actnFinishTagging->setVisible( false ); + groupMenu->addAction( actnFinishTagging ); groupMenu->addAction( actnEditSmartGroup ); btnManageGroups->setMenu( groupMenu ); connect( searchBox, SIGNAL( textChanged( QString ) ), this, SLOT( filterSymbols( QString ) ) ); - tagsLineEdit->installEventFilter( this ); // Context menu for groupTree groupTree->setContextMenuPolicy( Qt::CustomContextMenu ); @@ -144,13 +144,18 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle* style, QWidget* parent ) // Context menu for symbols/colorramps. The menu entries for every group are created when displaying the menu. mGroupMenu = new QMenu( this ); + connect( actnAddFavorite, SIGNAL( triggered( bool ) ), this, SLOT( addFavoriteSelectedSymbols() ) ); + mGroupMenu->addAction( actnAddFavorite ); + connect( actnRemoveFavorite, SIGNAL( triggered( bool ) ), this, SLOT( removeFavoriteSelectedSymbols() ) ); + mGroupMenu->addAction( actnRemoveFavorite ); + mGroupMenu->addSeparator()->setParent( this ); mGroupListMenu = new QMenu( mGroupMenu ); - mGroupListMenu->setTitle( tr( "Add to group" ) ); + mGroupListMenu->setTitle( tr( "Add to tag" ) ); mGroupListMenu->setEnabled( false ); mGroupMenu->addMenu( mGroupListMenu ); - actnUngroup->setData( 0 ); - connect( actnUngroup, SIGNAL( triggered( bool ) ), this, SLOT( groupSelectedSymbols() ) ); - mGroupMenu->addAction( actnUngroup ); + actnDetag->setData( 0 ); + connect( actnDetag, SIGNAL( triggered( bool ) ), this, SLOT( detagSelectedSymbols() ) ); + mGroupMenu->addAction( actnDetag ); mGroupMenu->addSeparator()->setParent( this ); mGroupMenu->addAction( actnRemoveItem ); mGroupMenu->addAction( actnEditItem ); @@ -391,20 +396,19 @@ bool QgsStyleManagerDialog::addSymbol() return false; } - // get unique name - bool nameInvalid = true; + QgsStyleSaveDialog saveDlg( this ); + if ( !saveDlg.exec() ) + { + delete symbol; + return false; + } + name = saveDlg.name(); + + // request valid/unique name + bool nameInvalid = true; while ( nameInvalid ) { - bool ok; - name = QInputDialog::getText( this, tr( "Symbol Name" ), - tr( "Please enter a name for new symbol:" ), - QLineEdit::Normal, name, &ok ); - if ( !ok ) - { - delete symbol; - return false; - } // validate name if ( name.isEmpty() ) { @@ -419,6 +423,7 @@ bool QgsStyleManagerDialog::addSymbol() QMessageBox::Yes | QMessageBox::No ); if ( res == QMessageBox::Yes ) { + mStyle->removeSymbol( name ); nameInvalid = false; } } @@ -427,11 +432,26 @@ bool QgsStyleManagerDialog::addSymbol() // valid name nameInvalid = false; } + if ( nameInvalid ) + { + bool ok; + name = QInputDialog::getText( this, tr( "Symbol Name" ), + tr( "Please enter a name for new symbol:" ), + QLineEdit::Normal, name, &ok ); + if ( !ok ) + { + delete symbol; + return false; + } + } } + QStringList symbolTags = saveDlg.tags().split( ',' ); + // add new symbol to style and re-populate the list - mStyle->addSymbol( name, symbol, true ); - // TODO groups and tags + mStyle->addSymbol( name, symbol ); + mStyle->saveSymbol( name, symbol, saveDlg.isFavorite(), symbolTags ); + mModified = true; return true; } @@ -521,19 +541,18 @@ QString QgsStyleManagerDialog::addColorRampStatic( QWidget* parent, QgsStyle* st return QString(); } - // get unique name - bool nameInvalid = true; + QgsStyleSaveDialog saveDlg( parent, QgsStyle::ColorrampEntity ); + if ( !saveDlg.exec() ) + { + return QString(); + } + name = saveDlg.name(); + + // get valid/unique name + bool nameInvalid = true; while ( nameInvalid ) { - bool ok; - name = QInputDialog::getText( parent, tr( "Color Ramp Name" ), - tr( "Please enter a name for new color ramp:" ), - QLineEdit::Normal, name, &ok ); - if ( !ok ) - { - return QString(); - } // validate name if ( name.isEmpty() ) { @@ -556,11 +575,26 @@ QString QgsStyleManagerDialog::addColorRampStatic( QWidget* parent, QgsStyle* st // valid name nameInvalid = false; } + if ( nameInvalid ) + { + bool ok; + name = QInputDialog::getText( parent, tr( "Color Ramp Name" ), + tr( "Please enter a name for new color ramp:" ), + QLineEdit::Normal, name, &ok ); + if ( !ok ) + { + return QString(); + } + } } + QStringList colorRampTags = saveDlg.tags().split( ',' ); + QgsColorRamp* r = ramp.take(); + // add new symbol to style and re-populate the list - style->addColorRamp( name, ramp.take(), true ); - // TODO groups and tags, using saveColorRamp + style->addColorRamp( name, r ); + style->saveColorRamp( name, r, saveDlg.isFavorite(), colorRampTags ); + return name; } @@ -854,40 +888,49 @@ void QgsStyleManagerDialog::populateGroups() QStandardItemModel *model = qobject_cast( groupTree->model() ); model->clear(); + QStandardItem *favoriteSymbols = new QStandardItem( tr( "Favorites" ) ); + favoriteSymbols->setData( "favorite" ); + favoriteSymbols->setEditable( false ); + setBold( favoriteSymbols ); + model->appendRow( favoriteSymbols ); + QStandardItem *allSymbols = new QStandardItem( tr( "All Symbols" ) ); allSymbols->setData( "all" ); allSymbols->setEditable( false ); setBold( allSymbols ); model->appendRow( allSymbols ); - QStandardItem *group = new QStandardItem( QLatin1String( "" ) ); //require empty name to get first order groups - group->setData( "groups" ); - group->setEditable( false ); - buildGroupTree( group ); - group->setText( tr( "Groups" ) );//set title later - QStandardItem *ungrouped = new QStandardItem( tr( "Ungrouped" ) ); - ungrouped->setData( 0 ); - setBold( ungrouped ); - setBold( group ); - group->appendRow( ungrouped ); - model->appendRow( group ); + QStandardItem *taggroup = new QStandardItem( QLatin1String( "" ) ); //require empty name to get first order groups + taggroup->setData( "tags" ); + taggroup->setEditable( false ); + QStringList tags = mStyle->tags(); + tags.sort(); + Q_FOREACH ( const QString& tag, tags ) + { + QStandardItem *item = new QStandardItem( tag ); + item->setData( mStyle->tagId( tag ) ); + taggroup->appendRow( item ); + } + taggroup->setText( tr( "Tags" ) );//set title later + setBold( taggroup ); + model->appendRow( taggroup ); - QStandardItem *tag = new QStandardItem( tr( "Smart Groups" ) ); - tag->setData( "smartgroups" ); - tag->setEditable( false ); - setBold( tag ); + QStandardItem *smart = new QStandardItem( tr( "Smart Groups" ) ); + smart->setData( "smartgroups" ); + smart->setEditable( false ); + setBold( smart ); QgsSymbolGroupMap sgMap = mStyle->smartgroupsListMap(); QgsSymbolGroupMap::const_iterator i = sgMap.constBegin(); while ( i != sgMap.constEnd() ) { QStandardItem *item = new QStandardItem( i.value() ); item->setData( i.key() ); - tag->appendRow( item ); + smart->appendRow( item ); ++i; } - model->appendRow( tag ); + model->appendRow( smart ); - // expand things in the grouo tree + // expand things in the group tree int rows = model->rowCount( model->indexFromItem( model->invisibleRootItem() ) ); for ( int i = 0; i < rows; i++ ) { @@ -895,20 +938,6 @@ void QgsStyleManagerDialog::populateGroups() } } -void QgsStyleManagerDialog::buildGroupTree( QStandardItem* &parent ) -{ - QgsSymbolGroupMap groups = mStyle->childGroupNames( parent->text() ); - QgsSymbolGroupMap::const_iterator i = groups.constBegin(); - while ( i != groups.constEnd() ) - { - QStandardItem *item = new QStandardItem( i.value() ); - item->setData( i.key() ); - parent->appendRow( item ); - buildGroupTree( item ); - ++i; - } -} - void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) { QStringList symbolNames; @@ -922,42 +951,41 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) } QString category = index.data( Qt::UserRole + 1 ).toString(); - if ( category == QLatin1String( "all" ) || category == QLatin1String( "groups" ) || category == QLatin1String( "smartgroups" ) ) + if ( category == QLatin1String( "all" ) || category == QLatin1String( "tags" ) || category == QLatin1String( "smartgroups" ) ) { enableGroupInputs( false ); - if ( category == QLatin1String( "groups" ) || category == QLatin1String( "smartgroups" ) ) + if ( category == QLatin1String( "tags" ) || category == QLatin1String( "smartgroups" ) ) { btnAddGroup->setEnabled( true ); actnAddGroup->setEnabled( true ); } symbolNames = currentItemType() < 3 ? mStyle->symbolNames() : mStyle->colorRampNames(); } - else + else if ( category == QLatin1String( "favorite" ) ) { - //determine groups and tags - if ( index.parent().data( Qt::UserRole + 1 ) == "smartgroups" ) + 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(); + symbolNames = mStyle->symbolsOfSmartgroup( type, groupId ); + } + else // tags + { + enableGroupInputs( true ); + int tagId = index.data( Qt::UserRole + 1 ).toInt(); + symbolNames = mStyle->symbolsWithTag( type, tagId ); + if ( mGrouppingMode && tagId ) { - btnAddGroup->setEnabled( false ); - actnAddGroup->setEnabled( false ); - btnRemoveGroup->setEnabled( true ); - actnRemoveGroup->setEnabled( true ); - btnManageGroups->setEnabled( true ); - int groupId = index.data( Qt::UserRole + 1 ).toInt(); - symbolNames = mStyle->symbolsOfSmartgroup( type, groupId ); - } - else // then it must be a group - { - if (( !index.data( Qt::UserRole + 1 ).toInt() && ( index.data() == "Ungrouped" ) ) || mGrouppingMode ) - enableGroupInputs( false ); - else - enableGroupInputs( true ); - int groupId = index.data( Qt::UserRole + 1 ).toInt(); - symbolNames = mStyle->symbolsOfGroup( type, groupId ); - if ( mGrouppingMode && groupId ) - { - groupSymbols = symbolNames; - symbolNames += mStyle->symbolsOfGroup( type, 0 ); - } + groupSymbols = symbolNames; + symbolNames = type == QgsStyle::SymbolEntity ? mStyle->symbolNames() : mStyle->colorRampNames(); } } @@ -969,16 +997,19 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) { populateColorRamps( symbolNames, mGrouppingMode ); } + if ( mGrouppingMode ) + { setSymbolsChecked( groupSymbols ); + } actnEditSmartGroup->setVisible( false ); actnAddGroup->setVisible( false ); actnRemoveGroup->setVisible( false ); - actnGroupSymbols->setVisible( false ); - actnFinishGrouping->setVisible( false ); + actnTagSymbols->setVisible( false ); + actnFinishTagging->setVisible( false ); - if ( index.parent().isValid() && ( index.data().toString() != QLatin1String( "Ungrouped" ) ) ) + if ( index.parent().isValid() ) { if ( index.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "smartgroups" ) ) { @@ -987,12 +1018,12 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) else { actnAddGroup->setVisible( !mGrouppingMode ); - actnGroupSymbols->setVisible( !mGrouppingMode ); - actnFinishGrouping->setVisible( mGrouppingMode ); + actnTagSymbols->setVisible( !mGrouppingMode ); + actnFinishTagging->setVisible( mGrouppingMode ); } actnRemoveGroup->setVisible( true ); } - else if ( index.data( Qt::UserRole + 1 ) == "groups" || index.data( Qt::UserRole + 1 ) == "smartgroups" ) + else if ( index.data( Qt::UserRole + 1 ) == "tags" || index.data( Qt::UserRole + 1 ) == "smartgroups" ) { actnAddGroup->setVisible( !mGrouppingMode ); } @@ -1001,11 +1032,11 @@ void QgsStyleManagerDialog::groupChanged( const QModelIndex& index ) void QgsStyleManagerDialog::addGroup() { QStandardItemModel *model = qobject_cast( groupTree->model() ); - QModelIndex parentIndex = groupTree->currentIndex(); + QModelIndex index = groupTree->currentIndex(); - // Violation 1: Creating sub-groups of system defined groups - QString parentData = parentIndex.data( Qt::UserRole + 1 ).toString(); - if ( parentData == QLatin1String( "all" ) || ( parentIndex.data() == "Ungrouped" && parentData == QLatin1String( "0" ) ) ) + // 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" ) { int err = QMessageBox::critical( this, tr( "Invalid Selection" ), tr( "The parent group you have selected is not user editable.\n" @@ -1014,24 +1045,19 @@ void QgsStyleManagerDialog::addGroup() return; } - // Violation 2: Creating a nested tag - if ( parentIndex.parent().data( Qt::UserRole + 1 ).toString() == QLatin1String( "smartgroups" ) ) + QString itemName; + int id; + + // + if ( index.parent() != QModelIndex() ) { - int err = QMessageBox::critical( this, tr( "Operation Not Allowed" ), - tr( "Creation of nested smart groups are not allowed\n" - "Select the 'Smart Group' to create a new group." ) ); - if ( err ) - return; + index = index.parent(); + data = index.data( Qt::UserRole + 1 ).toString(); } - QString itemName; - bool isGroup = true; - - int id; - if ( parentData == QLatin1String( "smartgroups" ) ) + if ( data == QLatin1String( "smartgroups" ) ) { - // create a smart group - + // create a smartgroup QgsSmartGroupEditorDialog dlg( mStyle, this ); if ( dlg.exec() == QDialog::Rejected ) return; @@ -1039,34 +1065,39 @@ void QgsStyleManagerDialog::addGroup() if ( !id ) return; itemName = dlg.smartgroupName(); - isGroup = false; } else { - // create a simple child-group to the selected + // 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; - itemName = QString( tr( "New Group" ) ); - int parentid = ( parentData == QLatin1String( "groups" ) ) ? 0 : parentData.toInt(); // parentid is 0 for top-level groups - id = mStyle->addGroup( itemName, parentid ); + 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 group could not be created.\n" + tr( "New tag could not be created.\n" "There was a problem with your symbol database." ) ); return; } } - QStandardItem *parentItem = model->itemFromIndex( parentIndex ); + QStandardItem *parentItem = model->itemFromIndex( index ); QStandardItem *childItem = new QStandardItem( itemName ); childItem->setData( id ); parentItem->appendRow( childItem ); groupTree->setCurrentIndex( childItem->index() ); - if ( isGroup ) - { - groupTree->edit( childItem->index() ); - } } void QgsStyleManagerDialog::removeGroup() @@ -1074,9 +1105,9 @@ void QgsStyleManagerDialog::removeGroup() QStandardItemModel *model = qobject_cast( groupTree->model() ); QModelIndex index = groupTree->currentIndex(); - // Violation: removing system groups + // do not allow removal of system-defined groupings QString data = index.data( Qt::UserRole + 1 ).toString(); - if ( data == QLatin1String( "all" ) || data == QLatin1String( "groups" ) || data == QLatin1String( "smartgroups" ) || index.data() == "Ungrouped" ) + if ( data == QLatin1String( "all" ) || data == QLatin1String( "favorite" ) || data == QLatin1String( "tags" ) || index.data() == "smartgroups" ) { int err = QMessageBox::critical( this, tr( "Invalid selection" ), tr( "Cannot delete system defined categories.\n" @@ -1092,16 +1123,7 @@ void QgsStyleManagerDialog::removeGroup() } else { - mStyle->remove( QgsStyle::GroupEntity, index.data( Qt::UserRole + 1 ).toInt() ); - QStandardItem *item = model->itemFromIndex( index ); - if ( item->hasChildren() ) - { - QStandardItem *parent = item->parent(); - for ( int i = 0; i < item->rowCount(); i++ ) - { - parent->appendRow( item->takeChild( i ) ); - } - } + mStyle->remove( QgsStyle::TagEntity, index.data( Qt::UserRole + 1 ).toInt() ); } parentItem->removeRow( index.row() ); } @@ -1117,11 +1139,11 @@ void QgsStyleManagerDialog::groupRenamed( QStandardItem * item ) } else { - mStyle->rename( QgsStyle::GroupEntity, id, name ); + mStyle->rename( QgsStyle::TagEntity, id, name ); } } -void QgsStyleManagerDialog::groupSymbolsAction() +void QgsStyleManagerDialog::tagSymbolsAction() { QStandardItemModel *treeModel = qobject_cast( groupTree->model() ); @@ -1130,8 +1152,8 @@ void QgsStyleManagerDialog::groupSymbolsAction() if ( mGrouppingMode ) { mGrouppingMode = false; - actnGroupSymbols->setVisible( true ); - actnFinishGrouping->setVisible( false ); + actnTagSymbols->setVisible( true ); + actnFinishTagging->setVisible( false ); // disconnect slot which handles regrouping disconnect( model, SIGNAL( itemChanged( QStandardItem* ) ), this, SLOT( regrouped( QStandardItem* ) ) ); @@ -1155,21 +1177,20 @@ void QgsStyleManagerDialog::groupSymbolsAction() QModelIndex present = groupTree->currentIndex(); while ( present.parent().isValid() ) { - if ( present.parent().data() == "Groups" ) + if ( present.parent().data() == "Tags" ) { validGroup = true; break; } - else - present = present.parent(); + present = present.parent(); } if ( !validGroup ) return; mGrouppingMode = true; // Change visibility of actions - actnGroupSymbols->setVisible( false ); - actnFinishGrouping->setVisible( true ); + actnTagSymbols->setVisible( false ); + actnFinishTagging->setVisible( true ); // Remove all Symbol editing functionalities disconnect( treeModel, SIGNAL( itemChanged( QStandardItem* ) ), this, SLOT( groupRenamed( QStandardItem* ) ) ); @@ -1199,20 +1220,23 @@ void QgsStyleManagerDialog::regrouped( QStandardItem *item ) QgsDebugMsg( "Unknown style entity" ); return; } - int groupid = groupTree->currentIndex().data( Qt::UserRole + 1 ).toInt(); + + QStandardItemModel *treeModel = qobject_cast( groupTree->model() ); + QString tag = treeModel->itemFromIndex( groupTree->currentIndex() )->text(); + QString symbolName = item->text(); bool regrouped; if ( item->checkState() == Qt::Checked ) - regrouped = mStyle->group( type, symbolName, groupid ); + regrouped = mStyle->tagSymbol( type, symbolName, QStringList( tag ) ); else - regrouped = mStyle->group( type, symbolName, 0 ); + regrouped = mStyle->detagSymbol( type, symbolName, QStringList( tag ) ); if ( !regrouped ) { int er = QMessageBox::critical( this, tr( "Database Error" ), tr( "There was a problem with the Symbols database while regrouping." ) ); // call the slot again to get back to normal if ( er ) - groupSymbolsAction(); + tagSymbolsAction(); } } @@ -1242,69 +1266,8 @@ void QgsStyleManagerDialog::filterSymbols( const QString& qword ) } } -void QgsStyleManagerDialog::tagsChanged() -{ - QModelIndexList indexes = listItems->selectionModel()->selection().indexes(); - QStringList addtags; - QStringList removetags; - - QStringList oldtags = mTagList; - QStringList newtags = tagsLineEdit->text().split( ',', QString::SkipEmptyParts ); - - QgsStyle::StyleEntity type; - if ( currentItemType() < 3 ) - { - type = QgsStyle::SymbolEntity; - } - else if ( currentItemType() == 3 ) - { - type = QgsStyle::ColorrampEntity; - } - else - { - QgsDebugMsg( "Unknown Style Entity!" ); - return; - } - // compare old with new to find removed tags - Q_FOREACH ( const QString &tag, oldtags ) - { - if ( !newtags.contains( tag ) ) - removetags.append( tag ); - } - if ( !removetags.isEmpty() ) - { - Q_FOREACH ( const QModelIndex& index, indexes ) - { - mStyle->detagSymbol( type, index.data().toString(), removetags ); - } - } - // compare new with old to find added tags - Q_FOREACH ( const QString &tag, newtags ) - { - if ( !oldtags.contains( tag ) ) - addtags.append( tag ); - } - if ( !addtags.isEmpty() ) - { - Q_FOREACH ( const QModelIndex& index, indexes ) - { - mStyle->tagSymbol( type, index.data().toString(), addtags ); - } - } -} - void QgsStyleManagerDialog::symbolSelected( const QModelIndex& index ) { - // Populate the tags for the symbol - tagsLineEdit->clear(); - if ( index.isValid() ) - { - QStandardItem *item = static_cast( listItems->model() )->itemFromIndex( index ); - QgsStyle::StyleEntity type = ( currentItemType() < 3 ) ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity; - mTagList = mStyle->tagsOfSymbol( type, item->data().toString() ); - tagsLineEdit->setText( mTagList.join( QStringLiteral( "," ) ) ); - } - actnEditItem->setEnabled( index.isValid() && !mGrouppingMode ); } @@ -1314,8 +1277,10 @@ void QgsStyleManagerDialog::selectedSymbolsChanged( const QItemSelection& select Q_UNUSED( deselected ); bool nothingSelected = listItems->selectionModel()->selectedIndexes().empty(); actnRemoveItem->setDisabled( nothingSelected ); + actnAddFavorite->setDisabled( nothingSelected ); + actnRemoveFavorite->setDisabled( nothingSelected ); mGroupListMenu->setDisabled( nothingSelected ); - actnUngroup->setDisabled( nothingSelected ); + actnDetag->setDisabled( nothingSelected ); actnExportAsPNG->setDisabled( nothingSelected ); actnExportAsSVG->setDisabled( nothingSelected ); actnEditItem->setDisabled( nothingSelected ); @@ -1330,7 +1295,6 @@ void QgsStyleManagerDialog::enableSymbolInputs( bool 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 ); - tagsLineEdit->setEnabled( enable ); } void QgsStyleManagerDialog::enableGroupInputs( bool enable ) @@ -1346,19 +1310,8 @@ void QgsStyleManagerDialog::enableItemsForGroupingMode( bool enable ) QStandardItemModel *treeModel = qobject_cast( groupTree->model() ); for ( int i = 0; i < treeModel->rowCount(); i++ ) { - if ( treeModel->item( i )->data() != "groups" ) - { - treeModel->item( i )->setEnabled( enable ); - } - if ( treeModel->item( i )->data() == "groups" ) - { - treeModel->item( i )->setEnabled( enable ); - for ( int k = 0; k < treeModel->item( i )->rowCount(); k++ ) - { - if ( !treeModel->item( i )->child( k )->data().toInt() ) - treeModel->item( i )->child( k )->setEnabled( enable ); - } - } + treeModel->item( i )->setEnabled( enable ); + if ( treeModel->item( i )->data() == "smartgroups" ) { for ( int j = 0; j < treeModel->item( i )->rowCount(); j++ ) @@ -1401,19 +1354,54 @@ void QgsStyleManagerDialog::listitemsContextMenu( QPoint point ) mGroupListMenu->clear(); QAction* a; - QList groupIds = mStyle->groupIds(); - Q_FOREACH ( int groupId, groupIds ) + QStringList tags = mStyle->tags(); + tags.sort(); + Q_FOREACH ( const QString& tag, tags ) { - a = new QAction( mStyle->groupName( groupId ), mGroupListMenu ); - a->setData( groupId ); - connect( a, SIGNAL( triggered( bool ) ), this, SLOT( groupSelectedSymbols() ) ); + a = new QAction( tag, mGroupListMenu ); + a->setData( tag ); + connect( a, SIGNAL( triggered( bool ) ), this, SLOT( tagSelectedSymbols() ) ); mGroupListMenu->addAction( a ); } mGroupMenu->popup( globalPos ); } -void QgsStyleManagerDialog::groupSelectedSymbols() +void QgsStyleManagerDialog::addFavoriteSelectedSymbols() +{ + QgsStyle::StyleEntity type = ( currentItemType() < 3 ) ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity; + if ( currentItemType() > 3 ) + { + QgsDebugMsg( "unknown entity type" ); + return; + } + + QModelIndexList indexes = listItems->selectionModel()->selectedIndexes(); + Q_FOREACH ( const QModelIndex& index, indexes ) + { + mStyle->addFavorite( type, index.data().toString() ); + } + populateList(); +} + +void QgsStyleManagerDialog::removeFavoriteSelectedSymbols() +{ + QgsStyle::StyleEntity type = ( currentItemType() < 3 ) ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity; + if ( currentItemType() > 3 ) + { + QgsDebugMsg( "unknown entity type" ); + return; + } + + QModelIndexList indexes = listItems->selectionModel()->selectedIndexes(); + Q_FOREACH ( const QModelIndex& index, indexes ) + { + mStyle->removeFavorite( type, index.data().toString() ); + } + populateList(); +} + +void QgsStyleManagerDialog::tagSelectedSymbols() { QAction* selectedItem = qobject_cast( sender() ); @@ -1425,11 +1413,34 @@ void QgsStyleManagerDialog::groupSelectedSymbols() QgsDebugMsg( "unknown entity type" ); return; } - int groupId = selectedItem->data().toInt(); + QString tag = selectedItem->data().toString(); QModelIndexList indexes = listItems->selectionModel()->selectedIndexes(); Q_FOREACH ( const QModelIndex& index, indexes ) { - mStyle->group( type, index.data().toString(), groupId ); + mStyle->tagSymbol( type, index.data().toString(), QStringList( tag ) ); + } + populateList(); + + QgsDebugMsg( "Selected Action: " + selectedItem->text() ); + } +} + +void QgsStyleManagerDialog::detagSelectedSymbols() +{ + QAction* selectedItem = qobject_cast( sender() ); + + if ( selectedItem ) + { + QgsStyle::StyleEntity type = ( currentItemType() < 3 ) ? QgsStyle::SymbolEntity : QgsStyle::ColorrampEntity; + if ( currentItemType() > 3 ) + { + QgsDebugMsg( "unknown entity type" ); + return; + } + QModelIndexList indexes = listItems->selectionModel()->selectedIndexes(); + Q_FOREACH ( const QModelIndex& index, indexes ) + { + mStyle->detagSymbol( type, index.data().toString() ); } populateList(); @@ -1474,14 +1485,4 @@ void QgsStyleManagerDialog::editSmartgroupAction() groupChanged( present ); } -bool QgsStyleManagerDialog::eventFilter( QObject *obj, QEvent *event ) -{ - - if (( obj == tagsLineEdit ) && ( event->type() == QEvent::FocusOut ) ) - { - tagsChanged(); - return true; - } - return false; -} diff --git a/src/gui/symbology-ng/qgsstylemanagerdialog.h b/src/gui/symbology-ng/qgsstylemanagerdialog.h index 3582112b6a3..7132838af44 100644 --- a/src/gui/symbology-ng/qgsstylemanagerdialog.h +++ b/src/gui/symbology-ng/qgsstylemanagerdialog.h @@ -66,8 +66,8 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan void addGroup(); void removeGroup(); - //! carryout symbol grouping using check boxes - void groupSymbolsAction(); + //! carry out symbol tagging using check boxes + void tagSymbolsAction(); //! edit the selected smart group void editSmartgroupAction(); @@ -78,9 +78,6 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan //! filter the symbols based on input search term void filterSymbols( const QString& ); - //! Listen to tag changes - void tagsChanged(); - //! Perform symbol specific tasks when selected void symbolSelected( const QModelIndex& ); @@ -95,7 +92,14 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan protected slots: bool addColorRamp( QAction* action ); - void groupSelectedSymbols(); + //! Add selected symbols to favorites + void addFavoriteSelectedSymbols(); + //! Remove selected symbols from favorites + void removeFavoriteSelectedSymbols(); + //! Tag selected symbols using menu item selection + void tagSelectedSymbols(); + //! Remove all tags from selected symbols + void detagSelectedSymbols(); protected: @@ -104,8 +108,6 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan //! populate the groups void populateGroups(); - //! build the groups tree - void buildGroupTree( QStandardItem* &parent ); //! to set symbols checked when in editing mode void setSymbolsChecked( const QStringList& ); @@ -136,9 +138,6 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan //! Enables or diables the groupTree items for grouping mode void enableItemsForGroupingMode( bool ); - //! Event filter to capture tagsLineEdit out of focus - bool eventFilter( QObject*, QEvent* ) override; - //! sets the text of the item with bold font void setBold( QStandardItem* ); diff --git a/src/gui/symbology-ng/qgsstylesavedialog.cpp b/src/gui/symbology-ng/qgsstylesavedialog.cpp new file mode 100644 index 00000000000..4087ebe66ec --- /dev/null +++ b/src/gui/symbology-ng/qgsstylesavedialog.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** + qgssymbolsavedialog.cpp + --------------------------------------- + begin : November 2016 + copyright : (C) 2016 by Mathieu Pellerin + email : nirvn dot asia at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsstylesavedialog.h" + +#include "qgis.h" +#include "qgsstyle.h" + +#include +#include + +QgsStyleSaveDialog::QgsStyleSaveDialog( QWidget* parent, QgsStyle::StyleEntity type ) + : QDialog( parent ) +{ + setupUi( this ); + + if ( type == QgsStyle::SymbolEntity ) + { + this->setWindowTitle( tr( "Save new symbol" ) ); + } + else if ( type == QgsStyle::ColorrampEntity ) + { + this->setWindowTitle( tr( "Save new color ramp" ) ); + } +} + +QgsStyleSaveDialog::~QgsStyleSaveDialog() { } + +QString QgsStyleSaveDialog::name() const +{ + return mName->text(); +} + +QString QgsStyleSaveDialog::tags() const +{ + return mTags->text(); +} + +bool QgsStyleSaveDialog::isFavorite() const +{ + return mFavorite->isChecked(); +} diff --git a/src/gui/symbology-ng/qgsstylesavedialog.h b/src/gui/symbology-ng/qgsstylesavedialog.h new file mode 100644 index 00000000000..8fb4b2cd922 --- /dev/null +++ b/src/gui/symbology-ng/qgsstylesavedialog.h @@ -0,0 +1,57 @@ +/*************************************************************************** + qgssymbolsavedialog.h + ------------------------------------- + begin : November 2016 + copyright : (C) 2016 by Mathieu Pellerin + email : nirvn dot asia at gmail dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSSTYLESAVEDIALOG_H +#define QGSSTYLESAVEDIALOG_H + +#include +#include "ui_qgsstylesavedialog.h" + +#include "qgsstyle.h" + +/** \ingroup gui + * \brief a dialog for setting properties of a newly saved style. + * \note added in QGIS 3.0 +*/ +class GUI_EXPORT QgsStyleSaveDialog: public QDialog, private Ui::QgsStyleSaveDialog +{ + Q_OBJECT + + public: + + /** Constructor for QgsSymbolSaveDialog + * @param parent parent widget + * @param type the QgsStyle entity type being saved + */ + QgsStyleSaveDialog( QWidget* parent = nullptr, QgsStyle::StyleEntity type = QgsStyle::SymbolEntity ); + + ~QgsStyleSaveDialog(); + + //! returns the text value of the name element + QString name() const; + + //! returns the text value of the tags element + QString tags() const; + + //! returns whether the favorite element is checked + bool isFavorite() const; + + + +}; + +#endif // QGSSTYLESAVEDIALOG_H diff --git a/src/gui/symbology-ng/qgssymbolslistwidget.cpp b/src/gui/symbology-ng/qgssymbolslistwidget.cpp index 235aa8e7ab5..08548a86c7b 100644 --- a/src/gui/symbology-ng/qgssymbolslistwidget.cpp +++ b/src/gui/symbology-ng/qgssymbolslistwidget.cpp @@ -19,6 +19,7 @@ #include "qgssizescalewidget.h" #include "qgsstylemanagerdialog.h" +#include "qgsstylesavedialog.h" #include "qgsdatadefined.h" #include "qgssymbol.h" @@ -29,6 +30,8 @@ #include "qgsapplication.h" #include "qgsvectorlayer.h" +#include +#include #include #include #include @@ -38,6 +41,7 @@ #include #include #include +#include #include @@ -67,26 +71,20 @@ QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbol* symbol, QgsStyle* style, } mClipFeaturesAction = new QAction( tr( "Clip features to canvas extent" ), this ); mClipFeaturesAction->setCheckable( true ); - connect( mClipFeaturesAction, SIGNAL( toggled( bool ) ), this, SLOT( clipFeaturesToggled( bool ) ) ); - - // populate the groups - groupsCombo->addItem( QLatin1String( "" ) ); - populateGroups(); - QStringList groups = style->smartgroupNames(); - Q_FOREACH ( const QString& group, groups ) - { - groupsCombo->addItem( group, QVariant( "smart" ) ); - } + connect( mClipFeaturesAction, &QAction::toggled, this, &QgsSymbolsListWidget::clipFeaturesToggled ); QStandardItemModel* model = new QStandardItemModel( viewSymbols ); viewSymbols->setModel( model ); connect( viewSymbols->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ), this, SLOT( setSymbolFromStyle( const QModelIndex & ) ) ); - connect( mStyle, SIGNAL( symbolSaved( QString, QgsSymbol* ) ), this, SLOT( symbolAddedToStyle( QString, QgsSymbol* ) ) ); - connect( openStyleManagerButton, SIGNAL( pressed() ), this, SLOT( openStyleManager() ) ); + connect( mStyle, &QgsStyle::symbolSaved , this, &QgsSymbolsListWidget::symbolAddedToStyle ); + connect( mStyle, &QgsStyle::groupsModified , this, &QgsSymbolsListWidget::populateGroups ); + + connect( openStyleManagerButton, &QPushButton::pressed, this, &QgsSymbolsListWidget::openStyleManager ); lblSymbolName->setText( QLatin1String( "" ) ); - populateSymbolView(); + + populateGroups(); if ( mSymbol ) { @@ -119,7 +117,7 @@ QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbol* symbol, QgsStyle* style, btnColor->setColorDialogTitle( tr( "Select color" ) ); btnColor->setContext( QStringLiteral( "symbology" ) ); - connect( btnSaveSymbol, SIGNAL( clicked() ), this, SLOT( saveSymbol() ) ); + connect( btnSaveSymbol, &QPushButton::clicked, this, &QgsSymbolsListWidget::saveSymbol ); } QgsSymbolsListWidget::~QgsSymbolsListWidget() @@ -148,30 +146,72 @@ QgsSymbolWidgetContext QgsSymbolsListWidget::context() const return mContext; } -void QgsSymbolsListWidget::populateGroups( const QString& parent, const QString& prepend ) +void QgsSymbolsListWidget::populateGroups() { - QgsSymbolGroupMap groups = mStyle->childGroupNames( parent ); - QgsSymbolGroupMap::const_iterator i = groups.constBegin(); - while ( i != groups.constEnd() ) + groupsCombo->blockSignals( true ); + groupsCombo->clear(); + + groupsCombo->addItem( tr( "Favorites" ), QVariant( "favorite" ) ); + groupsCombo->addItem( tr( "All Symbols" ), QVariant( "all" ) ); + + int index = 2; + QStringList tags = mStyle->tags(); + if ( tags.count() > 0 ) { - QString text; - if ( !prepend.isEmpty() ) + tags.sort(); + groupsCombo->insertSeparator( index ); + Q_FOREACH ( const QString& tag, tags ) { - text = prepend + '/' + i.value(); + groupsCombo->addItem( tag, QVariant( "tag" ) ); + index++; } - else - { - text = i.value(); - } - groupsCombo->addItem( text, QVariant( i.key() ) ); - populateGroups( i.value(), text ); - ++i; } + + QStringList groups = mStyle->smartgroupNames(); + if ( groups.count() > 0 ) + { + groups.sort(); + groupsCombo->insertSeparator( index + 1 ); + Q_FOREACH ( const QString& group, groups ) + { + groupsCombo->addItem( group, QVariant( "smartgroup" ) ); + } + } + groupsCombo->blockSignals( false ); + + QSettings settings; + index = settings.value( "qgis/symbolsListGroupsIndex", 0 ).toInt(); + groupsCombo->setCurrentIndex( index ); + + populateSymbolView(); } void QgsSymbolsListWidget::populateSymbolView() { - populateSymbols( mStyle->symbolNames() ); + QStringList symbols; + QString text = groupsCombo->currentText(); + int id; + + if ( groupsCombo->currentData().toString() == QLatin1String( "favorite" ) ) + { + symbols = mStyle->symbolsOfFavorite( QgsStyle::SymbolEntity ); + } + else if ( groupsCombo->currentData().toString() == QLatin1String( "all" ) ) + { + symbols = mStyle->symbolNames(); + } + else if ( groupsCombo->currentData().toString() == QLatin1String( "smartgroup" ) ) + { + id = mStyle->smartgroupId( text ); + symbols = mStyle->symbolsOfSmartgroup( QgsStyle::SymbolEntity, id ); + } + else + { + id = mStyle->tagId( text ); + symbols = mStyle->symbolsWithTag( QgsStyle::SymbolEntity, id ); + } + + populateSymbols( symbols ); } void QgsSymbolsListWidget::populateSymbols( const QStringList& names ) @@ -357,30 +397,34 @@ void QgsSymbolsListWidget::addSymbolToStyle() void QgsSymbolsListWidget::saveSymbol() { - bool ok; - QString name = QInputDialog::getText( this, tr( "Symbol name" ), - tr( "Please enter name for the symbol:" ), QLineEdit::Normal, tr( "New symbol" ), &ok ); - if ( !ok || name.isEmpty() ) + QgsStyleSaveDialog saveDlg( this ); + if ( !saveDlg.exec() ) + return; + + if ( saveDlg.name().isEmpty() ) return; // check if there is no symbol with same name - if ( mStyle->symbolNames().contains( name ) ) + if ( mStyle->symbolNames().contains( saveDlg.name() ) ) { int res = QMessageBox::warning( this, tr( "Save symbol" ), tr( "Symbol with name '%1' already exists. Overwrite?" ) - .arg( name ), + .arg( saveDlg.name() ), QMessageBox::Yes | QMessageBox::No ); if ( res != QMessageBox::Yes ) { return; } + mStyle->removeSymbol( saveDlg.name() ); } + QStringList symbolTags = saveDlg.tags().split( ',' ); + // add new symbol to style and re-populate the list - mStyle->addSymbol( name, mSymbol->clone() ); + mStyle->addSymbol( saveDlg.name(), mSymbol->clone() ); // make sure the symbol is stored - mStyle->saveSymbol( name, mSymbol->clone(), 0, QStringList() ); + mStyle->saveSymbol( saveDlg.name(), mSymbol->clone(), saveDlg.isFavorite(), symbolTags ); } void QgsSymbolsListWidget::on_mSymbolUnitWidget_changed() @@ -537,7 +581,7 @@ void QgsSymbolsListWidget::setSymbolFromStyle( const QModelIndex & index ) // get new instance of symbol from style QgsSymbol* s = mStyle->symbol( symbolName ); QgsUnitTypes::RenderUnit unit = s->outputUnit(); - // remove all symbol layers from original symbol + // remove all symbol layers from original symbolgroupsCombo while ( mSymbol->symbolLayerCount() ) mSymbol->deleteSymbolLayer( 0 ); // move all symbol layers to our symbol @@ -557,32 +601,8 @@ void QgsSymbolsListWidget::setSymbolFromStyle( const QModelIndex & index ) void QgsSymbolsListWidget::on_groupsCombo_currentIndexChanged( int index ) { - QStringList symbols; - QString text = groupsCombo->itemText( index ); - // List all symbols when empty list item is selected - if ( text.isEmpty() ) - { - symbols = mStyle->symbolNames(); - } - else - { - int groupid; - if ( groupsCombo->itemData( index ).toString() == QLatin1String( "smart" ) ) - { - groupid = mStyle->smartgroupId( text ); - symbols = mStyle->symbolsOfSmartgroup( QgsStyle::SymbolEntity, groupid ); - } - else - { - groupid = groupsCombo->itemData( index ).toInt(); - symbols = mStyle->symbolsOfGroup( QgsStyle::SymbolEntity, groupid ); - } - } - populateSymbols( symbols ); -} + QSettings settings; + settings.setValue( QStringLiteral( "qgis/symbolsListGroupsIndex" ), index ); -void QgsSymbolsListWidget::on_groupsCombo_editTextChanged( const QString &text ) -{ - QStringList symbols = mStyle->findSymbols( QgsStyle::SymbolEntity, text ); - populateSymbols( symbols ); + populateSymbolView(); } diff --git a/src/gui/symbology-ng/qgssymbolslistwidget.h b/src/gui/symbology-ng/qgssymbolslistwidget.h index 3e65c4255b4..2ad3ba79103 100644 --- a/src/gui/symbology-ng/qgssymbolslistwidget.h +++ b/src/gui/symbology-ng/qgssymbolslistwidget.h @@ -67,12 +67,15 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW void setLineWidth( double width ); void addSymbolToStyle(); void saveSymbol(); + void symbolAddedToStyle( const QString& name, QgsSymbol* symbol ); + void on_mSymbolUnitWidget_changed(); void on_mTransparencySlider_valueChanged( int value ); + //! Pupulates the groups combo box with available tags and smartgroups + void populateGroups(); void on_groupsCombo_currentIndexChanged( int index ); - void on_groupsCombo_editTextChanged( const QString &text ); void openStyleManager(); void clipFeaturesToggled( bool checked ); @@ -99,8 +102,6 @@ class GUI_EXPORT QgsSymbolsListWidget : public QWidget, private Ui::SymbolsListW //! Displays alpha value as transparency in mTransparencyLabel void displayTransparency( double alpha ); - //! Recursive function to create the group tree in the widget - void populateGroups( const QString& parent = "", const QString& prepend = "" ); QgsSymbolWidgetContext mContext; diff --git a/src/ui/qgsstyleexportimportdialogbase.ui b/src/ui/qgsstyleexportimportdialogbase.ui index 71ff90f74b8..4803407540e 100644 --- a/src/ui/qgsstyleexportimportdialogbase.ui +++ b/src/ui/qgsstyleexportimportdialogbase.ui @@ -43,17 +43,33 @@ - - + + - Save to group + Tag(s) - - - - true + + + + + 0 + 0 + + + + Add to favorites + + + + + + + + + + Tip: separate multiple tags with commas diff --git a/src/ui/qgsstylemanagerdialogbase.ui b/src/ui/qgsstylemanagerdialogbase.ui index 77f5c81c7cb..23e27f7073a 100644 --- a/src/ui/qgsstylemanagerdialogbase.ui +++ b/src/ui/qgsstylemanagerdialogbase.ui @@ -380,26 +380,6 @@ QMenu::item:selected { background-color: gray; } */ - - - - - - - 75 - true - - - - Tags - - - - - - - - @@ -450,15 +430,37 @@ QMenu::item:selected { background-color: gray; } */ Edit item - + false - Ungroup + Add to favorites - Ungroup + Add to favorites + + + + + false + + + Remove from favorites + + + Remove from favorites + + + + + false + + + Clear tags + + + Clear tags @@ -484,17 +486,17 @@ QMenu::item:selected { background-color: gray; } */ Remove group - + - Group symbols + Attach selected tag to symbols - + true - Finish grouping + Finish tagging true diff --git a/src/ui/qgsstylesavedialog.ui b/src/ui/qgsstylesavedialog.ui new file mode 100644 index 00000000000..3357a8959c6 --- /dev/null +++ b/src/ui/qgsstylesavedialog.ui @@ -0,0 +1,126 @@ + + + QgsStyleSaveDialog + + + + 0 + 0 + 489 + 225 + + + + Save new style + + + + + + + + Name + + + + + + + + + + + 0 + 0 + + + + Add to favorites + + + + + + + Tag(s) + + + + + + + + + + Tip: separate multiple tags with commas + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Save + + + + + + + mName + mTags + mFavorite + + + + + buttonBox + accepted() + QgsStyleSaveDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + QgsStyleSaveDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/ui/symbollayer/widget_symbolslist.ui b/src/ui/symbollayer/widget_symbolslist.ui index beb23af9c99..31e73bbdf3c 100644 --- a/src/ui/symbollayer/widget_symbolslist.ui +++ b/src/ui/symbollayer/widget_symbolslist.ui @@ -72,7 +72,7 @@ - Symbols in group + Symbols in @@ -131,17 +131,11 @@ - - - 70 - 16777215 - - Save symbol - Save + Save symbol diff --git a/tests/src/core/testqgsstyle.cpp b/tests/src/core/testqgsstyle.cpp index 3ee9353d5dc..fecf6e6f245 100644 --- a/tests/src/core/testqgsstyle.cpp +++ b/tests/src/core/testqgsstyle.cpp @@ -65,6 +65,7 @@ class TestStyle : public QObject void testCreateColorRamps(); void testLoadColorRamps(); void testSaveLoad(); + void testFavorites(); void testTags(); }; @@ -258,6 +259,35 @@ void TestStyle::testSaveLoad() testLoadColorRamps(); } +void TestStyle::testFavorites() +{ + mStyle->clear(); + + // save initial number of favorites to compare against additions / substractions + QStringList favorites; + favorites = mStyle->symbolsOfFavorite( QgsStyle::SymbolEntity ); + int count = favorites.count(); + + // add some symbols to favorites + mStyle->saveSymbol( "symbolA", QgsMarkerSymbol::createSimple( QgsStringMap() ), true, QStringList() ); + mStyle->saveSymbol( "symbolB", QgsMarkerSymbol::createSimple( QgsStringMap() ), false, QStringList() ); + mStyle->saveSymbol( "symbolC", QgsMarkerSymbol::createSimple( QgsStringMap() ), true, QStringList() ); + + // check for added symbols to favorites + favorites = mStyle->symbolsOfFavorite( QgsStyle::SymbolEntity ); + QCOMPARE( favorites.count(), count + 2 ); + QVERIFY( favorites.contains( "symbolA" ) ); + QVERIFY( favorites.contains( "symbolC" ) ); + + // remove one symbol from favorites + mStyle->removeFavorite( QgsStyle::SymbolEntity, "symbolA" ); + + // insure favorites updated after removal + favorites = mStyle->symbolsOfFavorite( QgsStyle::SymbolEntity ); + QCOMPARE( favorites.count(), count + 1 ); + QVERIFY( favorites.contains( "symbolC" ) ); +} + void TestStyle::testTags() { mStyle->clear(); @@ -289,7 +319,7 @@ void TestStyle::testTags() QVERIFY( !tags.contains( "purple" ) ); //add some symbols - QVERIFY( mStyle->saveSymbol( "symbol1", QgsMarkerSymbol::createSimple( QgsStringMap() ), 0, QStringList() << "red" << "starry" ) ); + QVERIFY( mStyle->saveSymbol( "symbol1", QgsMarkerSymbol::createSimple( QgsStringMap() ), false, QStringList() << "red" << "starry" ) ); mStyle->addSymbol( QStringLiteral( "blue starry" ), QgsMarkerSymbol::createSimple( QgsStringMap() ), true ); mStyle->addSymbol( QStringLiteral( "red circle" ), QgsMarkerSymbol::createSimple( QgsStringMap() ), true );