26 #include <QDomDocument> 27 #include <QDomElement> 29 #include <QDomNodeList> 31 #include <QTextStream> 37 #define STYLE_CURRENT_VERSION "1" 39 QgsStyle *QgsStyle::sDefaultStyle =
nullptr;
53 if ( !QFile::exists( styleFilename ) )
65 sDefaultStyle->
load( styleFilename );
74 sDefaultStyle =
nullptr;
79 qDeleteAll( mSymbols );
80 qDeleteAll( mColorRamps );
88 if ( !symbol || name.isEmpty() )
92 if ( mSymbols.contains( name ) )
95 delete mSymbols.value( name );
96 mSymbols.insert( name, symbol );
102 mSymbols.insert( name, symbol );
104 saveSymbol( name, symbol,
false, QStringList() );
113 QDomDocument doc( QStringLiteral(
"dummy" ) );
115 if ( symEl.isNull() )
117 QgsDebugMsg(
"Couldn't convert symbol to valid XML!" );
122 QTextStream stream( &xmlArray );
123 stream.setCodec(
"UTF-8" );
124 symEl.save( stream, 4 );
125 auto query =
QgsSqlite3Mprintf(
"INSERT INTO symbol VALUES (NULL, '%q', '%q', %d);",
126 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
128 if ( !runEmptyQuery( query ) )
130 QgsDebugMsg(
"Couldn't insert symbol into the database!" );
154 QgsDebugMsg(
"Sorry! Cannot open database to tag." );
161 QgsDebugMsg(
"No such symbol for deleting in database: " + name +
". Cheers." );
172 return symbol ? symbol->
clone() :
nullptr;
177 return mSymbols.value( name );
182 return mSymbols.count();
187 return mSymbols.keys();
193 if ( !colorRamp || name.isEmpty() )
197 if ( mColorRamps.contains( name ) )
200 delete mColorRamps.value( name );
201 mColorRamps.insert( name, colorRamp );
207 mColorRamps.insert( name, colorRamp );
218 QDomDocument doc( QStringLiteral(
"dummy" ) );
221 if ( rampEl.isNull() )
223 QgsDebugMsg(
"Couldn't convert color ramp to valid XML!" );
228 QTextStream stream( &xmlArray );
229 stream.setCodec(
"UTF-8" );
230 rampEl.save( stream, 4 );
231 auto query =
QgsSqlite3Mprintf(
"INSERT INTO colorramp VALUES (NULL, '%q', '%q', %d);",
232 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
233 if ( !runEmptyQuery( query ) )
235 QgsDebugMsg(
"Couldn't insert colorramp into the database!" );
250 auto query =
QgsSqlite3Mprintf(
"DELETE FROM colorramp WHERE name='%q'", name.toUtf8().constData() );
251 if ( !runEmptyQuery( query ) )
253 QgsDebugMsg(
"Couldn't remove color ramp from the database." );
265 return ramp ? ramp->
clone() :
nullptr;
270 return mColorRamps.value( name );
275 return mColorRamps.count();
280 return mColorRamps.keys();
283 bool QgsStyle::openDatabase(
const QString &filename )
285 int rc = mCurrentDB.
open( filename );
288 mErrorString = QStringLiteral(
"Couldn't open the style database: %1" ).arg( mCurrentDB.
errorMessage() );
297 mErrorString.clear();
298 if ( !openDatabase( filename ) )
300 mErrorString = QStringLiteral(
"Unable to create database" );
312 mErrorString.clear();
313 if ( !openDatabase( QStringLiteral(
":memory:" ) ) )
315 mErrorString = QStringLiteral(
"Unable to create temporary memory database" );
328 "id INTEGER PRIMARY KEY,"\
331 "favorite INTEGER);"\
332 "CREATE TABLE colorramp("\
333 "id INTEGER PRIMARY KEY,"\
336 "favorite INTEGER);"\
338 "id INTEGER PRIMARY KEY,"\
340 "CREATE TABLE tagmap("\
341 "tag_id INTEGER NOT NULL,"\
342 "symbol_id INTEGER);"\
343 "CREATE TABLE ctagmap("\
344 "tag_id INTEGER NOT NULL,"\
345 "colorramp_id INTEGER);"\
346 "CREATE TABLE smartgroup("\
347 "id INTEGER PRIMARY KEY,"\
350 runEmptyQuery( query );
355 mErrorString.clear();
358 if ( !openDatabase( filename ) )
360 mErrorString = QStringLiteral(
"Unable to open database file specified" );
366 auto query =
QgsSqlite3Mprintf(
"UPDATE symbol SET favorite=0 WHERE favorite IS NULL;" 367 "UPDATE colorramp SET favorite=0 WHERE favorite IS NULL;" 369 runEmptyQuery( query );
376 statement = mCurrentDB.
prepare( query, rc );
378 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
383 if ( !doc.setContent( xmlstring ) )
385 QgsDebugMsg(
"Cannot open symbol " + symbol_name );
389 QDomElement symElement = doc.documentElement();
392 mSymbols.insert( symbol_name, symbol );
396 statement = mCurrentDB.
prepare( query, rc );
397 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
402 if ( !doc.setContent( xmlstring ) )
407 QDomElement rampElement = doc.documentElement();
410 mColorRamps.insert( ramp_name, ramp );
413 mFileName = filename;
421 mErrorString.clear();
423 if ( filename.isEmpty() )
424 filename = mFileName;
429 QDomDocument doc(
"qgis_style" );
430 QDomElement root = doc.createElement(
"qgis_style" );
432 doc.appendChild( root );
436 QDomElement rampsElem = doc.createElement(
"colorramps" );
439 for ( QMap<QString, QgsColorRamp *>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
442 rampsElem.appendChild( rampEl );
445 root.appendChild( symbolsElem );
446 root.appendChild( rampsElem );
450 if ( !f.open( QFile::WriteOnly ) )
452 mErrorString =
"Couldn't open file for writing: " + filename;
455 QTextStream ts( &f );
456 ts.setCodec(
"UTF-8" );
461 mFileName = filename;
467 if ( mSymbols.contains( newName ) )
469 QgsDebugMsg(
"Symbol of new name already exists" );
477 mSymbols.insert( newName, symbol );
481 QgsDebugMsg(
"Sorry! Cannot open database to tag." );
488 QgsDebugMsg(
"No such symbol for tagging in database: " + oldName );
499 if ( mColorRamps.contains( newName ) )
501 QgsDebugMsg(
"Color ramp of new name already exists." );
509 mColorRamps.insert( newName, ramp );
513 auto query =
QgsSqlite3Mprintf(
"SELECT id FROM colorramp WHERE name='%q'", oldName.toUtf8().constData() );
515 statement = mCurrentDB.
prepare( query, nErr );
516 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
518 rampid = sqlite3_column_int( statement.get(), 0 );
529 QgsDebugMsg( QString(
"Cannot Open database for getting favorite symbols" ) );
530 return QStringList();
545 return QStringList();
550 statement = mCurrentDB.
prepare( query, nErr );
553 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
565 QgsDebugMsg( QString(
"Cannot open database to get symbols of tagid %1" ).arg( tagid ) );
566 return QStringList();
572 subquery =
QgsSqlite3Mprintf(
"SELECT symbol_id FROM tagmap WHERE tag_id=%d", tagid );
576 subquery =
QgsSqlite3Mprintf(
"SELECT colorramp_id FROM ctagmap WHERE tag_id=%d", tagid );
581 return QStringList();
586 statement = mCurrentDB.
prepare( subquery, nErr );
590 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
592 int id = sqlite3_column_int( statement.get(), 0 );
600 statement2 = mCurrentDB.
prepare( query, rc );
601 while ( rc == SQLITE_OK && sqlite3_step( statement2.get() ) == SQLITE_ROW )
603 symbols << QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement2.get(), 0 ) ) );
616 auto query =
QgsSqlite3Mprintf(
"INSERT INTO tag VALUES (NULL, '%q')", tagname.toUtf8().constData() );
618 statement = mCurrentDB.
prepare( query, nErr );
619 if ( nErr == SQLITE_OK )
620 ( void )sqlite3_step( statement.get() );
623 settings.
setValue( QStringLiteral(
"qgis/symbolsListGroupsIndex" ), 0 );
627 return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB.get() ) );
633 return QStringList();
639 statement = mCurrentDB.
prepare( query, nError );
642 while ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
652 bool groupRenamed =
false;
657 query =
QgsSqlite3Mprintf(
"UPDATE symbol SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
660 query =
QgsSqlite3Mprintf(
"UPDATE colorramp SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
663 query =
QgsSqlite3Mprintf(
"UPDATE tag SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
667 query =
QgsSqlite3Mprintf(
"UPDATE smartgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
674 if ( !runEmptyQuery( query ) )
676 mErrorString = QStringLiteral(
"Could not rename!" );
689 bool groupRemoved =
false;
694 query =
QgsSqlite3Mprintf(
"DELETE FROM symbol WHERE id=%d; DELETE FROM tagmap WHERE symbol_id=%d",
id,
id );
700 query =
QgsSqlite3Mprintf(
"DELETE FROM tag WHERE id=%d; DELETE FROM tagmap WHERE tag_id=%d",
id,
id );
712 if ( !runEmptyQuery( query ) )
721 settings.
setValue( QStringLiteral(
"qgis/symbolsListGroupsIndex" ), 0 );
728 bool QgsStyle::runEmptyQuery(
const QString &query )
733 char *zErr =
nullptr;
734 int nErr = sqlite3_exec( mCurrentDB.get(), query.toUtf8().constData(),
nullptr,
nullptr, &zErr );
736 if ( nErr != SQLITE_OK )
739 sqlite3_free( zErr );
742 return zErr == SQLITE_OK;
752 query =
QgsSqlite3Mprintf(
"UPDATE symbol SET favorite=1 WHERE name='%q'", name.toUtf8().constData() );
755 query =
QgsSqlite3Mprintf(
"UPDATE colorramp SET favorite=1 WHERE name='%q'", name.toUtf8().constData() );
759 QgsDebugMsg(
"Wrong entity value. cannot apply group" );
763 return runEmptyQuery( query );
773 query =
QgsSqlite3Mprintf(
"UPDATE symbol SET favorite=0 WHERE name='%q'", name.toUtf8().constData() );
776 query =
QgsSqlite3Mprintf(
"UPDATE colorramp SET favorite=0 WHERE name='%q'", name.toUtf8().constData() );
780 QgsDebugMsg(
"Wrong entity value. cannot apply group" );
784 return runEmptyQuery( query );
791 QgsDebugMsg(
"Sorry! Cannot open database to search" );
792 return QStringList();
796 QString item = ( type ==
SymbolEntity ) ? QStringLiteral(
"symbol" ) : QStringLiteral(
"colorramp" );
798 item.toUtf8().constData(), qword.toUtf8().constData() );
801 int nErr; statement = mCurrentDB.
prepare( query, nErr );
803 QSet< QString > symbols;
804 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
810 query =
QgsSqlite3Mprintf(
"SELECT id FROM tag WHERE name LIKE '%%%q%%'", qword.toUtf8().constData() );
811 statement = mCurrentDB.
prepare( query, nErr );
814 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
816 tagids << QString::fromUtf8( (
const char * ) sqlite3_column_text( statement.get(), 0 ) );
819 QString dummy = tagids.join( QStringLiteral(
", " ) );
824 dummy.toUtf8().constData() );
828 query =
QgsSqlite3Mprintf(
"SELECT colorramp_id FROM ctagmap WHERE tag_id IN (%q)",
829 dummy.toUtf8().constData() );
831 statement = mCurrentDB.
prepare( query, nErr );
833 QStringList symbolids;
834 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
836 symbolids << QString::fromUtf8( (
const char * ) sqlite3_column_text( statement.get(), 0 ) );
839 dummy = symbolids.join( QStringLiteral(
", " ) );
841 item.toUtf8().constData(), dummy.toUtf8().constData() );
842 statement = mCurrentDB.
prepare( query, nErr );
843 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
845 symbols << QString::fromUtf8( (
const char * ) sqlite3_column_text( statement.get(), 0 ) );
848 return symbols.toList();
855 QgsDebugMsg(
"Sorry! Cannot open database to tag." );
862 QgsDebugMsg(
"No such symbol for tagging in database: " + symbol );
867 Q_FOREACH (
const QString &t, tags )
870 if ( !tag.isEmpty() )
873 int tagid(
tagId( tag ) );
886 char *zErr =
nullptr;
888 nErr = sqlite3_exec( mCurrentDB.get(), query.toUtf8().constData(),
nullptr,
nullptr, &zErr );
892 sqlite3_free( zErr );
905 QgsDebugMsg(
"Sorry! Cannot open database for detgging." );
910 ?
QgsSqlite3Mprintf(
"SELECT id FROM symbol WHERE name='%q'", symbol.toUtf8().constData() )
911 :
QgsSqlite3Mprintf(
"SELECT id FROM colorramp WHERE name='%q'", symbol.toUtf8().constData() );
913 int nErr; statement = mCurrentDB.
prepare( query, nErr );
916 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
918 symbolid = sqlite3_column_int( statement.get(), 0 );
925 Q_FOREACH (
const QString &
tag, tags )
927 query =
QgsSqlite3Mprintf(
"SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
930 statement2 = mCurrentDB.
prepare( query, nErr );
933 if ( nErr == SQLITE_OK && sqlite3_step( statement2.get() ) == SQLITE_ROW )
935 tagid = sqlite3_column_int( statement2.get(), 0 );
942 ?
QgsSqlite3Mprintf(
"DELETE FROM tagmap WHERE tag_id=%d AND symbol_id=%d", tagid, symbolid )
943 :
QgsSqlite3Mprintf(
"DELETE FROM ctagmap WHERE tag_id=%d AND colorramp_id=%d", tagid, symbolid );
944 runEmptyQuery( query );
958 QgsDebugMsg(
"Sorry! Cannot open database for detagging." );
963 ?
QgsSqlite3Mprintf(
"SELECT id FROM symbol WHERE name='%q'", symbol.toUtf8().constData() )
964 :
QgsSqlite3Mprintf(
"SELECT id FROM colorramp WHERE name='%q'", symbol.toUtf8().constData() );
967 statement = mCurrentDB.
prepare( query, nErr );
970 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
972 symbolid = sqlite3_column_int( statement.get(), 0 );
983 runEmptyQuery( query );
995 QgsDebugMsg(
"Sorry! Cannot open database for getting the tags." );
996 return QStringList();
1001 return QStringList();
1006 :
QgsSqlite3Mprintf(
"SELECT tag_id FROM ctagmap WHERE colorramp_id=%d", symbolid );
1009 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1011 QStringList tagList;
1012 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1014 auto subquery =
QgsSqlite3Mprintf(
"SELECT name FROM tag WHERE id=%d", sqlite3_column_int( statement.get(), 0 ) );
1018 statement2 = mCurrentDB.
prepare( subquery, pErr );
1019 if ( pErr == SQLITE_OK && sqlite3_step( statement2.get() ) == SQLITE_ROW )
1021 tagList << QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement2.get(), 0 ) ) );
1032 QgsDebugMsg(
"Sorry! Cannot open database for getting the tags." );
1041 int tagid =
tagId( tag );
1049 ?
QgsSqlite3Mprintf(
"SELECT tag_id FROM tagmap WHERE tag_id=%d AND symbol_id=%d", tagid, symbolid )
1050 :
QgsSqlite3Mprintf(
"SELECT tag_id FROM ctagmap WHERE tag_id=%d AND colorramp_id=%d", tagid, symbolid );
1053 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1055 return ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW );
1067 statement = mCurrentDB.
prepare( query, nError );
1070 if ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1078 int QgsStyle::getId(
const QString &table,
const QString &name )
1080 QString lowerName( name.toLower() );
1081 auto query =
QgsSqlite3Mprintf(
"SELECT id FROM %q WHERE LOWER(name)='%q'", table.toUtf8().constData(), lowerName.toUtf8().constData() );
1084 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1087 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1089 id = sqlite3_column_int( statement.get(), 0 );
1094 auto query =
QgsSqlite3Mprintf(
"SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() );
1097 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1098 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1100 id = sqlite3_column_int( statement.get(), 0 );
1107 QString QgsStyle::getName(
const QString &table,
int id )
const 1109 auto query =
QgsSqlite3Mprintf(
"SELECT name FROM %q WHERE id='%q'", table.toUtf8().constData(), QString::number(
id ).toUtf8().constData() );
1112 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1115 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1125 return getId( QStringLiteral(
"symbol" ), name );
1130 return getId( QStringLiteral(
"colorramp" ), name );
1135 return getId( QStringLiteral(
"tag" ), name );
1140 return getId( QStringLiteral(
"smartgroup" ), name );
1145 QDomDocument doc( QStringLiteral(
"dummy" ) );
1146 QDomElement smartEl = doc.createElement( QStringLiteral(
"smartgroup" ) );
1147 smartEl.setAttribute( QStringLiteral(
"name" ), name );
1148 smartEl.setAttribute( QStringLiteral(
"operator" ), op );
1150 QStringList constraints;
1151 constraints << QStringLiteral(
"tag" ) << QStringLiteral(
"group" ) << QStringLiteral(
"name" ) << QStringLiteral(
"!tag" ) << QStringLiteral(
"!group" ) << QStringLiteral(
"!name" );
1153 Q_FOREACH (
const QString &constraint, constraints )
1155 QStringList parameters = conditions.values( constraint );
1156 Q_FOREACH (
const QString ¶m, parameters )
1158 QDomElement condEl = doc.createElement( QStringLiteral(
"condition" ) );
1159 condEl.setAttribute( QStringLiteral(
"constraint" ), constraint );
1160 condEl.setAttribute( QStringLiteral(
"param" ), param );
1161 smartEl.appendChild( condEl );
1165 QByteArray xmlArray;
1166 QTextStream stream( &xmlArray );
1167 stream.setCodec(
"UTF-8" );
1168 smartEl.save( stream, 4 );
1169 auto query =
QgsSqlite3Mprintf(
"INSERT INTO smartgroup VALUES (NULL, '%q', '%q')",
1170 name.toUtf8().constData(), xmlArray.constData() );
1172 if ( runEmptyQuery( query ) )
1175 settings.
setValue( QStringLiteral(
"qgis/symbolsListGroupsIndex" ), 0 );
1178 return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB.get() ) );
1182 QgsDebugMsg(
"Couldn't insert symbol into the database!" );
1191 QgsDebugMsg(
"Cannot open database for listing groups" );
1200 statement = mCurrentDB.
prepare( query, nError );
1203 while ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1206 groupNames.insert( sqlite3_column_int( statement.get(),
SmartgroupId ), group );
1216 QgsDebugMsg(
"Cannot open database for listing groups" );
1217 return QStringList();
1225 statement = mCurrentDB.
prepare( query, nError );
1228 while ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1238 QStringList symbols;
1243 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1244 if ( !( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW ) )
1246 return QStringList();
1252 if ( !doc.setContent( xmlstr ) )
1254 QgsDebugMsg( QString(
"Cannot open smartgroup id: %1" ).arg(
id ) );
1256 QDomElement smartEl = doc.documentElement();
1257 QString op = smartEl.attribute( QStringLiteral(
"operator" ) );
1258 QDomNodeList conditionNodes = smartEl.childNodes();
1260 bool firstSet =
true;
1261 for (
int i = 0; i < conditionNodes.count(); i++ )
1263 QDomElement condEl = conditionNodes.at( i ).toElement();
1264 QString constraint = condEl.attribute( QStringLiteral(
"constraint" ) );
1265 QString param = condEl.attribute( QStringLiteral(
"param" ) );
1267 QStringList resultNames;
1269 if ( constraint == QLatin1String(
"tag" ) )
1273 else if ( constraint == QLatin1String(
"name" ) )
1277 resultNames =
symbolNames().filter( param, Qt::CaseInsensitive );
1281 resultNames =
colorRampNames().filter( param, Qt::CaseInsensitive );
1284 else if ( constraint == QLatin1String(
"!tag" ) )
1288 Q_FOREACH (
const QString &name, unwanted )
1290 resultNames.removeAll( name );
1293 else if ( constraint == QLatin1String(
"!name" ) )
1296 Q_FOREACH (
const QString &str, all )
1298 if ( !str.contains( param, Qt::CaseInsensitive ) )
1306 symbols = resultNames;
1311 if ( op == QLatin1String(
"OR" ) )
1313 symbols << resultNames;
1315 else if ( op == QLatin1String(
"AND" ) )
1317 QStringList dummy = symbols;
1319 Q_FOREACH (
const QString &result, resultNames )
1321 if ( dummy.contains( result ) )
1336 QgsDebugMsg(
"Cannot open database for listing groups" );
1346 statement = mCurrentDB.
prepare( query, nError );
1347 if ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1351 if ( !doc.setContent( xmlstr ) )
1353 QgsDebugMsg( QString(
"Cannot open smartgroup id: %1" ).arg(
id ) );
1356 QDomElement smartEl = doc.documentElement();
1357 QDomNodeList conditionNodes = smartEl.childNodes();
1359 for (
int i = 0; i < conditionNodes.count(); i++ )
1361 QDomElement condEl = conditionNodes.at( i ).toElement();
1362 QString constraint = condEl.attribute( QStringLiteral(
"constraint" ) );
1363 QString param = condEl.attribute( QStringLiteral(
"param" ) );
1365 condition.insert( constraint, param );
1376 QgsDebugMsg(
"Cannot open database for listing groups" );
1386 statement = mCurrentDB.
prepare( query, nError );
1387 if ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1391 if ( !doc.setContent( xmlstr ) )
1393 QgsDebugMsg( QString(
"Cannot open smartgroup id: %1" ).arg(
id ) );
1395 QDomElement smartEl = doc.documentElement();
1396 op = smartEl.attribute( QStringLiteral(
"operator" ) );
1404 if ( filename.isEmpty() )
1406 QgsDebugMsg(
"Invalid filename for style export." );
1410 QDomDocument doc( QStringLiteral(
"qgis_style" ) );
1411 QDomElement root = doc.createElement( QStringLiteral(
"qgis_style" ) );
1413 doc.appendChild( root );
1420 QDomNodeList symbolsList = symbolsElem.elementsByTagName( QStringLiteral(
"symbol" ) );
1421 int nbSymbols = symbolsList.count();
1422 for (
int i = 0; i < nbSymbols; ++i )
1424 QDomElement
symbol = symbolsList.at( i ).toElement();
1425 QString name = symbol.attribute( QStringLiteral(
"name" ) );
1427 if ( tags.count() > 0 )
1429 symbol.setAttribute( QStringLiteral(
"tags" ), tags.join(
',' ) );
1431 if ( favoriteSymbols.contains( name ) )
1433 symbol.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
1438 QDomElement rampsElem = doc.createElement( QStringLiteral(
"colorramps" ) );
1439 for ( QMap<QString, QgsColorRamp *>::const_iterator itr = mColorRamps.constBegin(); itr != mColorRamps.constEnd(); ++itr )
1443 if ( tags.count() > 0 )
1445 rampEl.setAttribute( QStringLiteral(
"tags" ), tags.join(
',' ) );
1447 if ( favoriteColorramps.contains( itr.key() ) )
1449 rampEl.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
1451 rampsElem.appendChild( rampEl );
1454 root.appendChild( symbolsElem );
1455 root.appendChild( rampsElem );
1458 QFile f( filename );
1459 if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
1461 mErrorString =
"Couldn't open file for writing: " + filename;
1465 QTextStream ts( &f );
1466 ts.setCodec(
"UTF-8" );
1470 mFileName = filename;
1476 mErrorString = QString();
1477 QDomDocument doc( QStringLiteral(
"style" ) );
1478 QFile f( filename );
1479 if ( !f.open( QFile::ReadOnly ) )
1481 mErrorString = QStringLiteral(
"Unable to open the specified file" );
1482 QgsDebugMsg(
"Error opening the style XML file." );
1486 if ( !doc.setContent( &f ) )
1488 mErrorString = QStringLiteral(
"Unable to understand the style file: %1" ).arg( filename );
1495 QDomElement docEl = doc.documentElement();
1496 if ( docEl.tagName() != QLatin1String(
"qgis_style" ) )
1498 mErrorString =
"Incorrect root tag in style: " + docEl.tagName();
1502 QString version = docEl.attribute( QStringLiteral(
"version" ) );
1505 mErrorString =
"Unknown style file version: " + version;
1511 QDomElement symbolsElement = docEl.firstChildElement( QStringLiteral(
"symbols" ) );
1512 QDomElement e = symbolsElement.firstChildElement();
1516 runEmptyQuery( query );
1521 while ( !e.isNull() )
1523 if ( e.tagName() == QLatin1String(
"symbol" ) )
1525 QString name = e.attribute( QStringLiteral(
"name" ) );
1527 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
1529 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
1531 bool favorite =
false;
1532 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QStringLiteral(
"1" ) )
1551 e = e.nextSiblingElement();
1560 for ( QMap<QString, QgsSymbol *>::iterator it = symbols.begin(); it != symbols.end(); ++it )
1567 QDomElement rampsElement = docEl.firstChildElement( QStringLiteral(
"colorramps" ) );
1568 e = rampsElement.firstChildElement();
1569 while ( !e.isNull() )
1571 if ( e.tagName() == QLatin1String(
"colorramp" ) )
1573 QString name = e.attribute( QStringLiteral(
"name" ) );
1575 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
1577 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
1579 bool favorite =
false;
1580 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QStringLiteral(
"1" ) )
1599 e = e.nextSiblingElement();
1603 runEmptyQuery( query );
1605 mFileName = filename;
1609 bool QgsStyle::updateSymbol(
StyleEntity type,
const QString &name )
1611 QDomDocument doc( QStringLiteral(
"dummy" ) );
1613 QByteArray xmlArray;
1614 QTextStream stream( &xmlArray );
1615 stream.setCodec(
"UTF-8" );
1624 QgsDebugMsg(
"Update request received for unavailable symbol" );
1629 if ( symEl.isNull() )
1631 QgsDebugMsg(
"Couldn't convert symbol to valid XML!" );
1634 symEl.save( stream, 4 );
1636 xmlArray.constData(), name.toUtf8().constData() );
1642 QgsDebugMsg(
"Update requested for unavailable color ramp." );
1646 std::unique_ptr< QgsColorRamp > ramp(
colorRamp( name ) );
1648 if ( symEl.isNull() )
1650 QgsDebugMsg(
"Couldn't convert color ramp to valid XML!" );
1653 symEl.save( stream, 4 );
1655 xmlArray.constData(), name.toUtf8().constData() );
1659 QgsDebugMsg(
"Updating the unsupported StyleEntity" );
1664 if ( !runEmptyQuery( query ) )
1666 QgsDebugMsg(
"Couldn't insert symbol into the database!" );
bool exportXml(const QString &filename)
Exports the style as a XML file.
The class is used as a container of context for various read/write operations on other objects...
void clear()
Removes all contents of the style.
const QgsColorRamp * colorRampRef(const QString &name) const
Returns a const pointer to a symbol (doesn't create new instance)
bool addColorRamp(const QString &name, QgsColorRamp *colorRamp, bool update=false)
Adds a color ramp to the style.
void symbolSaved(const QString &name, QgsSymbol *symbol)
Is emitted every time a new symbol has been added to the database.
static QString userStylePath()
Returns the path to user's style.
bool symbolHasTag(StyleEntity type, const QString &symbol, const QString &tag)
Returns whether a given tag is associated with the symbol.
bool save(QString filename=QString())
Saves style into a file (will use current filename if empty string is passed)
This class is a composition of two QSettings instances:
QStringList symbolsWithTag(StyleEntity type, int tagid) const
Returns the symbol names with which have the given tag.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
void createTables()
Creates tables structure for new database.
bool load(const QString &filename)
Loads a file into the style.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
void remove(StyleEntity type, int id)
Removes the specified entity from the db.
QStringList tagsOfSymbol(StyleEntity type, const QString &symbol)
Returns the tags associated with the symbol.
Abstract base class for color ramps.
QMap< int, QString > QgsSymbolGroupMap
bool saveColorRamp(const QString &name, QgsColorRamp *ramp, bool favorite, const QStringList &tags)
Adds the colorramp to the DB.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
bool tagSymbol(StyleEntity type, const QString &symbol, const QStringList &tags)
Tags the symbol with the tags in the list.
static QgsSymbol * loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
QgsColorRamp * colorRamp(const QString &name) const
Returns a new copy of the specified color ramp.
bool removeColorRamp(const QString &name)
Removes color ramp from style (and delete it)
#define STYLE_CURRENT_VERSION
static QgsStyle * defaultStyle()
Returns default application-wide style.
StyleEntity
Enum for Entities involved in a style.
static QString defaultStylePath()
Returns the path to default style (works as a starting point).
QString errorMessage() const
Returns the most recent error message encountered by the database.
int symbolCount()
Returns count of symbols in style.
bool renameSymbol(const QString &oldName, const QString &newName)
Changessymbol's name.
QString tag(int id) const
Returns the tag name for the given id.
bool importXml(const QString &filename)
Imports the symbols and colorramps into the default style database from the given XML file...
const QgsSymbol * symbolRef(const QString &name) const
Returns a const pointer to a symbol (doesn't create new instance)
QStringList symbolNames()
Returns a list of names of symbols.
static QDomElement saveSymbols(QgsSymbolMap &symbols, const QString &tagName, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a collection of symbols to XML with specified tagName for the top-level element.
bool removeFavorite(StyleEntity type, const QString &name)
Removes the specified symbol from favorites.
QStringList findSymbols(StyleEntity type, const QString &qword)
Returns the names of the symbols which have a matching 'substring' in its definition.
void groupsModified()
Is emitted every time a tag or smartgroup has been added, removed, or renamed.
QgsStyle()=default
Constructor for QgsStyle.
int addTag(const QString &tagName)
Adds a new tag and returns the tag's id.
static void cleanDefaultStyle()
Deletes the default style. Only to be used by QgsApplication::exitQgis()
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
bool createMemoryDatabase()
Creates a temporary memory database.
QString smartgroupOperator(int id)
Returns the operator for the smartgroup clumsy implementation TODO create a class for smartgroups...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
static QgsSymbolMap loadSymbols(QDomElement &element, const QgsReadWriteContext &context)
Reads a collection of symbols from XML and returns them in a map. Caller is responsible for deleting ...
int open(const QString &path)
Opens the database at the specified file path.
void rename(StyleEntity type, int id, const QString &newName)
Renames the given entity with the specified id.
QgsSmartConditionMap smartgroup(int id)
Returns the QgsSmartConditionMap for the given id.
QStringList colorRampNames()
Returns a list of names of color ramps.
QStringList symbolsOfSmartgroup(StyleEntity type, int id)
Returns the symbols for the smartgroup.
int smartgroupId(const QString &smartgroup)
Returns the DB id for the given smartgroup name.
QStringList smartgroupNames()
Returns the smart groups list.
int tagId(const QString &tag)
Returns the DB id for the given tag name.
bool addSymbol(const QString &name, QgsSymbol *symbol, bool update=false)
Adds a symbol to style and takes symbol's ownership.
QStringList tags() const
Returns a list of all tags in the style database.
int addSmartgroup(const QString &name, const QString &op, const QgsSmartConditionMap &conditions)
Adds a new smartgroup to the database and returns the id.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
bool createDatabase(const QString &filename)
Creates an on-disk database.
virtual QgsSymbol * clone() const =0
Gets a deep copy of this symbol.
int colorrampId(const QString &name)
Returns the id in the style database for the given colorramp name returns 0 if not found...
int symbolId(const QString &name)
Returns the id in the style database for the given symbol name returns 0 if not found.
QMap< QString, QgsSymbol *> QgsSymbolMap
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
bool renameColorRamp(const QString &oldName, const QString &newName)
Changes ramp's name.
int colorRampCount()
Returns count of color ramps.
QString QgsSqlite3Mprintf(const char *format,...)
Wraps sqlite3_mprintf() by automatically freeing the memory.
QgsSymbol * symbol(const QString &name)
Returns a NEW copy of symbol.
bool saveSymbol(const QString &name, QgsSymbol *symbol, bool favorite, const QStringList &tags)
Adds the symbol to the DB with the tags.
bool removeSymbol(const QString &name)
Removes symbol from style (and delete it)
bool addFavorite(StyleEntity type, const QString &name)
Adds the specified symbol to favorites.
bool detagSymbol(StyleEntity type, const QString &symbol, const QStringList &tags)
Detags the symbol with the given list.
QStringList symbolsOfFavorite(StyleEntity type) const
Returns the symbol names which are flagged as favorite.
QMultiMap< QString, QString > QgsSmartConditionMap
A multimap to hold the smart group conditions as constraint and parameter pairs.
QgsSymbolGroupMap smartgroupsListMap()
Returns the smart groups map with id as key and name as value.