40 #include <QDomDocument>
41 #include <QDomElement>
43 #include <QDomNodeList>
45 #include <QTextStream>
52 #define STYLE_CURRENT_VERSION "2"
77 QgsStyle *QgsStyle::sDefaultStyle =
nullptr;
82 std::unique_ptr< QgsSimpleMarkerSymbolLayer > simpleMarker = std::make_unique< QgsSimpleMarkerSymbolLayer >(
Qgis::MarkerShape::Circle,
84 simpleMarker->setStrokeWidth( 0.4 );
85 mPatchMarkerSymbol = std::make_unique< QgsMarkerSymbol >(
QgsSymbolLayerList() << simpleMarker.release() );
87 std::unique_ptr< QgsSimpleLineSymbolLayer > simpleLine = std::make_unique< QgsSimpleLineSymbolLayer >( QColor( 84, 176, 74 ), 0.6 );
88 mPatchLineSymbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << simpleLine.release() );
90 std::unique_ptr< QgsGradientFillSymbolLayer > gradientFill = std::make_unique< QgsGradientFillSymbolLayer >( QColor( 66, 150, 63 ), QColor( 84, 176, 74 ) );
91 std::unique_ptr< QgsSimpleLineSymbolLayer > simpleOutline = std::make_unique< QgsSimpleLineSymbolLayer >( QColor( 56, 128, 54 ), 0.26 );
92 mPatchFillSymbol = std::make_unique< QgsFillSymbol >(
QgsSymbolLayerList() << gradientFill.release() << simpleOutline.release() );
113 switch ( entity->
type() )
147 if ( !sDefaultStyle )
153 if ( !QFile::exists( styleFilename ) )
161 sDefaultStyle->createStyleMetadataTableIfNeeded();
168 sDefaultStyle->
load( styleFilename );
169 sDefaultStyle->upgradeIfRequired();
171 sDefaultStyle->
setName( QObject::tr(
"Default" ) );
173 return sDefaultStyle;
178 delete sDefaultStyle;
179 sDefaultStyle =
nullptr;
184 qDeleteAll( mSymbols );
185 qDeleteAll( mColorRamps );
186 qDeleteAll( m3dSymbols );
190 mTextFormats.clear();
194 mCachedFavorites.clear();
203 if ( mSymbols.contains(
name ) )
206 delete mSymbols.value(
name );
224 QDomDocument doc( QStringLiteral(
"dummy" ) );
226 if ( symEl.isNull() )
228 QgsDebugMsg( QStringLiteral(
"Couldn't convert symbol to valid XML!" ) );
233 QTextStream stream( &xmlArray );
234 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
235 stream.setCodec(
"UTF-8" );
237 symEl.save( stream, 4 );
239 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
241 if ( !runEmptyQuery( query ) )
243 QgsDebugMsg( QStringLiteral(
"Couldn't insert symbol into the database!" ) );
299 return mSymbols.value(
name );
304 return mSymbols.count();
309 return mSymbols.keys();
319 if ( mColorRamps.contains(
name ) )
322 delete mColorRamps.value(
name );
340 if ( mTextFormats.contains(
name ) )
343 mTextFormats.remove(
name );
344 mTextFormats.insert(
name, format );
350 mTextFormats.insert(
name, format );
361 if ( mLabelSettings.contains(
name ) )
364 mLabelSettings.remove(
name );
365 mLabelSettings.insert(
name, settings );
371 mLabelSettings.insert(
name, settings );
382 if ( mLegendPatchShapes.contains(
name ) )
385 mLegendPatchShapes.remove(
name );
386 mLegendPatchShapes.insert(
name, shape );
392 mLegendPatchShapes.insert(
name, shape );
403 if ( m3dSymbols.contains(
name ) )
406 delete m3dSymbols.take(
name );
424 QDomDocument doc( QStringLiteral(
"dummy" ) );
427 if ( rampEl.isNull() )
429 QgsDebugMsg( QStringLiteral(
"Couldn't convert color ramp to valid XML!" ) );
434 QTextStream stream( &xmlArray );
435 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
436 stream.setCodec(
"UTF-8" );
438 rampEl.save( stream, 4 );
439 QString query =
qgs_sqlite3_mprintf(
"INSERT INTO colorramp VALUES (NULL, '%q', '%q', %d);",
440 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
441 if ( !runEmptyQuery( query ) )
443 QgsDebugMsg( QStringLiteral(
"Couldn't insert colorramp into the database!" ) );
465 return ramp ? ramp->
clone() :
nullptr;
470 return mColorRamps.value(
name );
475 return mColorRamps.count();
480 return mColorRamps.keys();
483 void QgsStyle::handleDeferred3DSymbolCreation()
485 for (
auto it = mDeferred3DsymbolElements.constBegin(); it != mDeferred3DsymbolElements.constEnd(); ++it )
487 const QString symbolType = it.value().attribute( QStringLiteral(
"type" ) );
497 QgsDebugMsg(
"Cannot open 3d symbol " + it.key() );
501 mDeferred3DsymbolElements.clear();
504 bool QgsStyle::openDatabase(
const QString &filename )
506 int rc = mCurrentDB.
open( filename );
509 mErrorString = QStringLiteral(
"Couldn't open the style database: %1" ).arg( mCurrentDB.
errorMessage() );
518 mErrorString.clear();
519 if ( !openDatabase( filename ) )
521 mErrorString = QStringLiteral(
"Unable to create database" );
533 mErrorString.clear();
534 if ( !openDatabase( QStringLiteral(
":memory:" ) ) )
536 mErrorString = QStringLiteral(
"Unable to create temporary memory database" );
549 "id INTEGER PRIMARY KEY,"\
552 "favorite INTEGER);"\
553 "CREATE TABLE colorramp("\
554 "id INTEGER PRIMARY KEY,"\
557 "favorite INTEGER);"\
558 "CREATE TABLE textformat("\
559 "id INTEGER PRIMARY KEY,"\
562 "favorite INTEGER);"\
563 "CREATE TABLE labelsettings("\
564 "id INTEGER PRIMARY KEY,"\
567 "favorite INTEGER);"\
568 "CREATE TABLE legendpatchshapes("\
569 "id INTEGER PRIMARY KEY,"\
572 "favorite INTEGER);"\
573 "CREATE TABLE symbol3d("\
574 "id INTEGER PRIMARY KEY,"\
577 "favorite INTEGER);"\
579 "id INTEGER PRIMARY KEY,"\
581 "CREATE TABLE tagmap("\
582 "tag_id INTEGER NOT NULL,"\
583 "symbol_id INTEGER);"\
584 "CREATE TABLE ctagmap("\
585 "tag_id INTEGER NOT NULL,"\
586 "colorramp_id INTEGER);"\
587 "CREATE TABLE tftagmap("\
588 "tag_id INTEGER NOT NULL,"\
589 "textformat_id INTEGER);"\
590 "CREATE TABLE lstagmap("\
591 "tag_id INTEGER NOT NULL,"\
592 "labelsettings_id INTEGER);"\
593 "CREATE TABLE lpstagmap("\
594 "tag_id INTEGER NOT NULL,"\
595 "legendpatchshape_id INTEGER);"\
596 "CREATE TABLE symbol3dtagmap("\
597 "tag_id INTEGER NOT NULL,"\
598 "symbol3d_id INTEGER);"\
599 "CREATE TABLE smartgroup("\
600 "id INTEGER PRIMARY KEY,"\
603 runEmptyQuery( query );
608 mErrorString.clear();
611 if ( !openDatabase( filename ) )
613 mErrorString = QStringLiteral(
"Unable to open database file specified" );
619 QString query =
qgs_sqlite3_mprintf(
"SELECT name FROM sqlite_master WHERE name='textformat'" );
622 statement = mCurrentDB.
prepare( query, rc );
623 if ( rc != SQLITE_OK || sqlite3_step( statement.get() ) != SQLITE_ROW )
626 "id INTEGER PRIMARY KEY,"\
629 "favorite INTEGER);"\
630 "CREATE TABLE tftagmap("\
631 "tag_id INTEGER NOT NULL,"\
632 "textformat_id INTEGER);" );
633 runEmptyQuery( query );
636 query =
qgs_sqlite3_mprintf(
"SELECT name FROM sqlite_master WHERE name='labelsettings'" );
637 statement = mCurrentDB.
prepare( query, rc );
638 if ( rc != SQLITE_OK || sqlite3_step( statement.get() ) != SQLITE_ROW )
641 "id INTEGER PRIMARY KEY,"\
644 "favorite INTEGER);"\
645 "CREATE TABLE lstagmap("\
646 "tag_id INTEGER NOT NULL,"\
647 "labelsettings_id INTEGER);" );
648 runEmptyQuery( query );
651 query =
qgs_sqlite3_mprintf(
"SELECT name FROM sqlite_master WHERE name='legendpatchshapes'" );
652 statement = mCurrentDB.
prepare( query, rc );
653 if ( rc != SQLITE_OK || sqlite3_step( statement.get() ) != SQLITE_ROW )
656 "id INTEGER PRIMARY KEY,"\
659 "favorite INTEGER);"\
660 "CREATE TABLE lpstagmap("\
661 "tag_id INTEGER NOT NULL,"\
662 "legendpatchshape_id INTEGER);" );
663 runEmptyQuery( query );
667 statement = mCurrentDB.
prepare( query, rc );
668 if ( rc != SQLITE_OK || sqlite3_step( statement.get() ) != SQLITE_ROW )
671 "id INTEGER PRIMARY KEY,"\
674 "favorite INTEGER);"\
675 "CREATE TABLE symbol3dtagmap("\
676 "tag_id INTEGER NOT NULL,"\
677 "symbol3d_id INTEGER);" );
678 runEmptyQuery( query );
683 "UPDATE colorramp SET favorite=0 WHERE favorite IS NULL;"
684 "UPDATE textformat SET favorite=0 WHERE favorite IS NULL;"
685 "UPDATE labelsettings SET favorite=0 WHERE favorite IS NULL;"
686 "UPDATE legendpatchshapes SET favorite=0 WHERE favorite IS NULL;"
687 "UPDATE symbol3d SET favorite=0 WHERE favorite IS NULL;"
689 runEmptyQuery( query );
695 statement = mCurrentDB.
prepare( query, rc );
697 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
703 if ( !doc.setContent( xmlstring ) )
709 QDomElement symElement = doc.documentElement();
712 mSymbols.insert( symbolName,
symbol );
719 statement = mCurrentDB.
prepare( query, rc );
720 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
726 if ( !doc.setContent( xmlstring ) )
731 QDomElement rampElement = doc.documentElement();
734 mColorRamps.insert( rampName, ramp );
741 statement = mCurrentDB.
prepare( query, rc );
742 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
748 if ( !doc.setContent( xmlstring ) )
750 QgsDebugMsg(
"Cannot open text format " + formatName );
753 QDomElement formatElement = doc.documentElement();
756 mTextFormats.insert( formatName, format );
763 statement = mCurrentDB.
prepare( query, rc );
764 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
770 if ( !doc.setContent( xmlstring ) )
772 QgsDebugMsg(
"Cannot open label settings " + settingsName );
775 QDomElement settingsElement = doc.documentElement();
778 mLabelSettings.insert( settingsName, settings );
785 statement = mCurrentDB.
prepare( query, rc );
786 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
792 if ( !doc.setContent( xmlstring ) )
794 QgsDebugMsg(
"Cannot open legend patch shape " + settingsName );
797 QDomElement settingsElement = doc.documentElement();
800 mLegendPatchShapes.insert( settingsName, shape );
807 statement = mCurrentDB.
prepare( query, rc );
811 while ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
817 if ( !doc.setContent( xmlstring ) )
819 QgsDebugMsg(
"Cannot open 3d symbol " + settingsName );
822 QDomElement settingsElement = doc.documentElement();
824 if ( !registry3dPopulated )
826 mDeferred3DsymbolElements.insert( settingsName, settingsElement );
830 const QString symbolType = settingsElement.attribute( QStringLiteral(
"type" ) );
835 m3dSymbols.insert( settingsName,
symbol.release() );
839 QgsDebugMsg(
"Cannot open 3d symbol " + settingsName );
846 mFileName = filename;
847 createStyleMetadataTableIfNeeded();
853 mErrorString.clear();
855 if ( !filename.isEmpty() )
856 mFileName = filename;
863 mFileName = filename;
868 if ( mSymbols.contains( newName ) )
870 QgsDebugMsg( QStringLiteral(
"Symbol of new name already exists" ) );
878 mSymbols.insert( newName,
symbol );
882 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database to tag." ) );
889 QgsDebugMsg( QStringLiteral(
"No such symbol for tagging in database: " ) + oldName );
908 if ( mColorRamps.contains( newName ) )
910 QgsDebugMsg( QStringLiteral(
"Color ramp of new name already exists." ) );
918 mColorRamps.insert( newName, ramp );
924 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM colorramp WHERE name='%q'", oldName.toUtf8().constData() );
926 statement = mCurrentDB.
prepare( query, nErr );
927 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
929 rampid = sqlite3_column_int( statement.get(), 0 );
944 QDomDocument doc( QStringLiteral(
"dummy" ) );
947 if ( formatElem.isNull() )
949 QgsDebugMsg( QStringLiteral(
"Couldn't convert text format to valid XML!" ) );
954 QTextStream stream( &xmlArray );
955 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
956 stream.setCodec(
"UTF-8" );
958 formatElem.save( stream, 4 );
959 QString query =
qgs_sqlite3_mprintf(
"INSERT INTO textformat VALUES (NULL, '%q', '%q', %d);",
960 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
961 if ( !runEmptyQuery( query ) )
963 QgsDebugMsg( QStringLiteral(
"Couldn't insert text format into the database!" ) );
984 if ( mTextFormats.contains( newName ) )
986 QgsDebugMsg( QStringLiteral(
"Text format of new name already exists." ) );
990 if ( !mTextFormats.contains( oldName ) )
994 mTextFormats.insert( newName, format );
1000 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM textformat WHERE name='%q'", oldName.toUtf8().constData() );
1002 statement = mCurrentDB.
prepare( query, nErr );
1003 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1005 textFormatId = sqlite3_column_int( statement.get(), 0 );
1020 QDomDocument doc( QStringLiteral(
"dummy" ) );
1023 if ( settingsElem.isNull() )
1025 QgsDebugMsg( QStringLiteral(
"Couldn't convert label settings to valid XML!" ) );
1029 QByteArray xmlArray;
1030 QTextStream stream( &xmlArray );
1031 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1032 stream.setCodec(
"UTF-8" );
1034 settingsElem.save( stream, 4 );
1035 QString query =
qgs_sqlite3_mprintf(
"INSERT INTO labelsettings VALUES (NULL, '%q', '%q', %d);",
1036 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
1037 if ( !runEmptyQuery( query ) )
1039 QgsDebugMsg( QStringLiteral(
"Couldn't insert label settings into the database!" ) );
1060 if ( mLabelSettings.contains( newName ) )
1062 QgsDebugMsg( QStringLiteral(
"Label settings of new name already exists." ) );
1066 if ( !mLabelSettings.contains( oldName ) )
1070 mLabelSettings.insert( newName, settings );
1076 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM labelsettings WHERE name='%q'", oldName.toUtf8().constData() );
1078 statement = mCurrentDB.
prepare( query, nErr );
1079 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1096 QDomDocument doc( QStringLiteral(
"dummy" ) );
1097 QDomElement shapeElem = doc.createElement( QStringLiteral(
"shape" ) );
1100 QByteArray xmlArray;
1101 QTextStream stream( &xmlArray );
1102 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1103 stream.setCodec(
"UTF-8" );
1105 shapeElem.save( stream, 4 );
1106 QString query =
qgs_sqlite3_mprintf(
"INSERT INTO legendpatchshapes VALUES (NULL, '%q', '%q', %d);",
1107 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
1108 if ( !runEmptyQuery( query ) )
1110 QgsDebugMsg( QStringLiteral(
"Couldn't insert legend patch shape into the database!" ) );
1125 if ( mLegendPatchShapes.contains( newName ) )
1127 QgsDebugMsg( QStringLiteral(
"Legend patch shape of new name already exists." ) );
1131 if ( !mLegendPatchShapes.contains( oldName ) )
1135 mLegendPatchShapes.insert( newName, shape );
1141 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM legendpatchshapes WHERE name='%q'", oldName.toUtf8().constData() );
1143 statement = mCurrentDB.
prepare( query, nErr );
1144 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1162 if ( mDefaultPatchCache[
static_cast< int >( type ) ].contains( size ) )
1163 return mDefaultPatchCache[
static_cast< int >( type ) ].value( size );
1169 geom =
QgsGeometry( std::make_unique< QgsPoint >(
static_cast< int >( size.width() ) / 2,
static_cast< int >( size.height() ) / 2 ) );
1176 double y =
static_cast< int >( size.height() ) / 2 + 0.5;
1177 geom =
QgsGeometry( std::make_unique< QgsLineString >( ( QVector< double >() << 0 << size.width() ),
1178 ( QVector< double >() << y << y ) ) );
1184 geom =
QgsGeometry( std::make_unique< QgsPolygon >(
1185 new QgsLineString( QVector< double >() << 0 <<
static_cast< int >( size.width() ) <<
static_cast< int >( size.width() ) << 0 << 0,
1186 QVector< double >() <<
static_cast< int >( size.height() ) <<
static_cast< int >( size.height() ) << 0 << 0 <<
static_cast< int >( size.height() ) ) ) );
1195 mDefaultPatchCache[
static_cast< int >( type ) ][size ] = res;
1202 return QList<QList<QPolygonF> >();
1204 if ( mDefaultPatchQPolygonFCache[
static_cast< int >( type ) ].contains( size ) )
1205 return mDefaultPatchQPolygonFCache[
static_cast< int >( type ) ].value( size );
1208 mDefaultPatchQPolygonFCache[
static_cast< int >( type ) ][size ] = res;
1214 return textFormat( QStringLiteral(
"Default" ) );
1234 QDomDocument doc( QStringLiteral(
"dummy" ) );
1235 QDomElement elem = doc.createElement( QStringLiteral(
"symbol" ) );
1236 elem.setAttribute( QStringLiteral(
"type" ),
symbol->
type() );
1239 QByteArray xmlArray;
1240 QTextStream stream( &xmlArray );
1241 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1242 stream.setCodec(
"UTF-8" );
1244 elem.save( stream, 4 );
1245 QString query =
qgs_sqlite3_mprintf(
"INSERT INTO symbol3d VALUES (NULL, '%q', '%q', %d);",
1246 name.toUtf8().constData(), xmlArray.constData(), ( favorite ? 1 : 0 ) );
1247 if ( !runEmptyQuery( query ) )
1249 QgsDebugMsg( QStringLiteral(
"Couldn't insert 3d symbol into the database!" ) );
1264 if ( m3dSymbols.contains( newName ) )
1266 QgsDebugMsg( QStringLiteral(
"3d symbol of new name already exists." ) );
1270 if ( !m3dSymbols.contains( oldName ) )
1274 m3dSymbols.insert( newName,
symbol );
1280 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM symbol3d WHERE name='%q'", oldName.toUtf8().constData() );
1282 statement = mCurrentDB.
prepare( query, nErr );
1283 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1298 return m3dSymbols.keys();
1305 QgsDebugMsg( QStringLiteral(
"Cannot Open database for getting favorite symbols" ) );
1306 return QStringList();
1314 QgsDebugMsg( QStringLiteral(
"No such style entity" ) );
1315 return QStringList();
1318 query =
qgs_sqlite3_mprintf( QStringLiteral(
"SELECT name FROM %1 WHERE favorite=1" ).arg( entityTableName( type ) ).toLocal8Bit().data() );
1324 statement = mCurrentDB.
prepare( query, nErr );
1326 QStringList symbols;
1327 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1339 QgsDebugMsg( QStringLiteral(
"Cannot open database to get symbols of tagid %1" ).arg( tagid ) );
1340 return QStringList();
1348 QgsDebugMsg( QStringLiteral(
"Unknown Entity" ) );
1349 return QStringList();
1352 subquery =
qgs_sqlite3_mprintf( QStringLiteral(
"SELECT %1 FROM %2 WHERE tag_id=%d" ).arg( tagmapEntityIdFieldName( type ),
1353 tagmapTableName( type ) ).toLocal8Bit().data(), tagid );
1359 statement = mCurrentDB.
prepare( subquery, nErr );
1362 QStringList symbols;
1363 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1365 int id = sqlite3_column_int( statement.get(), 0 );
1367 const QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"SELECT name FROM %1 WHERE id=%d" ).arg( entityTableName( type ) ).toLocal8Bit().data(),
id );
1371 statement2 = mCurrentDB.
prepare( query, rc );
1372 while ( rc == SQLITE_OK && sqlite3_step( statement2.get() ) == SQLITE_ROW )
1387 QString query =
qgs_sqlite3_mprintf(
"INSERT INTO tag VALUES (NULL, '%q')", tagname.toUtf8().constData() );
1389 statement = mCurrentDB.
prepare( query, nErr );
1390 if ( nErr == SQLITE_OK )
1391 ( void )sqlite3_step( statement.get() );
1394 settings.
setValue( QStringLiteral(
"qgis/symbolsListGroupsIndex" ), 0 );
1398 return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB.get() ) );
1404 return QStringList();
1410 statement = mCurrentDB.
prepare( query, nError );
1412 QStringList tagList;
1413 while ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1423 const QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"UPDATE %1 SET name='%q' WHERE id=%d" ).arg( entityTableName( type ) ).toLocal8Bit().data(), newName.toUtf8().constData(),
id );
1425 const bool result = runEmptyQuery( query );
1428 mErrorString = QStringLiteral(
"Could not rename!" );
1432 mCachedTags.clear();
1433 mCachedFavorites.clear();
1458 bool groupRemoved =
false;
1463 query =
qgs_sqlite3_mprintf(
"DELETE FROM tag WHERE id=%d; DELETE FROM tagmap WHERE tag_id=%d",
id,
id );
1464 groupRemoved =
true;
1468 groupRemoved =
true;
1472 query =
qgs_sqlite3_mprintf( QStringLiteral(
"DELETE FROM %1 WHERE id=%d; DELETE FROM %2 WHERE %3=%d" ).arg(
1473 entityTableName( type ),
1474 tagmapTableName( type ),
1475 tagmapEntityIdFieldName( type )
1476 ).toLocal8Bit().data(),
id,
id );
1480 bool result =
false;
1481 if ( !runEmptyQuery( query ) )
1483 QgsDebugMsg( QStringLiteral(
"Could not delete entity!" ) );
1487 mCachedTags.clear();
1488 mCachedFavorites.clear();
1493 settings.
setValue( QStringLiteral(
"qgis/symbolsListGroupsIndex" ), 0 );
1512 std::unique_ptr< QgsSymbol >
symbol( mSymbols.take(
name ) );
1521 std::unique_ptr< QgsAbstract3DSymbol >
symbol( m3dSymbols.take(
name ) );
1530 std::unique_ptr< QgsColorRamp > ramp( mColorRamps.take(
name ) );
1538 if ( !mTextFormats.contains(
name ) )
1541 mTextFormats.remove(
name );
1547 if ( !mLabelSettings.contains(
name ) )
1550 mLabelSettings.remove(
name );
1556 if ( !mLegendPatchShapes.contains(
name ) )
1559 mLegendPatchShapes.remove(
name );
1566 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database to modify." ) );
1573 QgsDebugMsg(
"No matching entity for deleting in database: " +
name );
1576 const bool result =
remove( type,
id );
1579 mCachedTags[ type ].remove(
name );
1580 mCachedFavorites[ type ].remove(
name );
1609 bool QgsStyle::runEmptyQuery(
const QString &query )
1614 char *zErr =
nullptr;
1615 int nErr = sqlite3_exec( mCurrentDB.get(), query.toUtf8().constData(),
nullptr,
nullptr, &zErr );
1617 if ( nErr != SQLITE_OK )
1620 sqlite3_free( zErr );
1623 return nErr == SQLITE_OK;
1634 QgsDebugMsg( QStringLiteral(
"Wrong entity value. cannot apply group" ) );
1638 query =
qgs_sqlite3_mprintf( QStringLiteral(
"UPDATE %1 SET favorite=1 WHERE name='%q'" ).arg( entityTableName( type ) ).toLocal8Bit().data(),
1639 name.toUtf8().constData() );
1643 const bool res = runEmptyQuery( query );
1653 mCachedFavorites[ type ].insert(
name,
true );
1670 QgsDebugMsg( QStringLiteral(
"Wrong entity value. cannot apply group" ) );
1674 query =
qgs_sqlite3_mprintf( QStringLiteral(
"UPDATE %1 SET favorite=0 WHERE name='%q'" ).arg( entityTableName( type ) ).toLocal8Bit().data(),
name.toUtf8().constData() );
1678 const bool res = runEmptyQuery( query );
1681 mCachedFavorites[ type ].insert(
name,
false );
1692 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database to search" ) );
1693 return QStringList();
1702 return QStringList();
1705 item = entityTableName( type );
1710 item.toUtf8().constData(), qword.toUtf8().constData() );
1713 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1715 QSet< QString > symbols;
1716 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1722 query =
qgs_sqlite3_mprintf(
"SELECT id FROM tag WHERE name LIKE '%%%q%%'", qword.toUtf8().constData() );
1723 statement = mCurrentDB.
prepare( query, nErr );
1726 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1731 QString dummy = tagids.join( QLatin1String(
", " ) );
1732 query =
qgs_sqlite3_mprintf( QStringLiteral(
"SELECT %1 FROM %2 WHERE tag_id IN (%q)" ).arg( tagmapEntityIdFieldName( type ),
1733 tagmapTableName( type ) ).toLocal8Bit().data(), dummy.toUtf8().constData() );
1735 statement = mCurrentDB.
prepare( query, nErr );
1737 QStringList symbolids;
1738 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1743 dummy = symbolids.join( QLatin1String(
", " ) );
1745 item.toUtf8().constData(), dummy.toUtf8().constData() );
1746 statement = mCurrentDB.
prepare( query, nErr );
1747 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1752 return qgis::setToList( symbols );
1759 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database to tag." ) );
1777 QgsDebugMsg( QStringLiteral(
"No such symbol for tagging in database: " ) +
symbol );
1782 const auto constTags =
tags;
1783 for (
const QString &t : constTags )
1786 if ( !
tag.isEmpty() )
1798 QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"INSERT INTO %1 VALUES (%d,%d)" ).arg( tagmapTableName( type ) ).toLocal8Bit().data(), tagid, symbolid );
1800 char *zErr =
nullptr;
1802 nErr = sqlite3_exec( mCurrentDB.get(), query.toUtf8().constData(),
nullptr,
nullptr, &zErr );
1806 sqlite3_free( zErr );
1812 clearCachedTags( type,
symbol );
1822 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database for detagging." ) );
1837 if ( symbolid == 0 )
1842 const auto constTags =
tags;
1843 for (
const QString &
tag : constTags )
1848 statement2 = mCurrentDB.
prepare( query, nErr );
1851 if ( nErr == SQLITE_OK && sqlite3_step( statement2.get() ) == SQLITE_ROW )
1853 tagid = sqlite3_column_int( statement2.get(), 0 );
1859 const QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"DELETE FROM %1 WHERE tag_id=%d AND %2=%d" ).arg( tagmapTableName( type ), tagmapEntityIdFieldName( type ) ).toLocal8Bit().data(), tagid, symbolid );
1860 runEmptyQuery( query );
1864 clearCachedTags( type,
symbol );
1877 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database for detagging." ) );
1892 if ( symbolid == 0 )
1898 const QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"DELETE FROM %1 WHERE %2=%d" ).arg( tagmapTableName( type ),
1899 tagmapEntityIdFieldName( type ) ).toLocal8Bit().data(), symbolid );
1900 runEmptyQuery( query );
1902 clearCachedTags( type,
symbol );
1917 return QStringList();
1920 if ( mCachedTags[ type ].contains(
symbol ) )
1921 return mCachedTags[ type ].value(
symbol );
1927 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database for getting the tags." ) );
1928 return QStringList();
1933 return QStringList();
1936 const QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"SELECT tag_id FROM %1 WHERE %2=%d" ).arg( tagmapTableName( type ),
1937 tagmapEntityIdFieldName( type ) ).toLocal8Bit().data(), symbolid );
1940 int nErr; statement = mCurrentDB.
prepare( query, nErr );
1942 QStringList tagList;
1943 while ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
1945 QString subquery =
qgs_sqlite3_mprintf(
"SELECT name FROM tag WHERE id=%d", sqlite3_column_int( statement.get(), 0 ) );
1949 statement2 = mCurrentDB.
prepare( subquery, pErr );
1950 if ( pErr == SQLITE_OK && sqlite3_step( statement2.get() ) == SQLITE_ROW )
1957 mCachedTags[ type ].insert(
symbol, tagList );
1966 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database for getting the tags." ) );
1977 if ( mCachedFavorites[ type ].contains(
name ) )
1978 return mCachedFavorites[ type ].value(
name );
1982 const QStringList names =
allNames( type );
1983 if ( !names.contains(
name ) )
1989 for (
const QString &n : names )
1991 const bool isFav = favorites.contains( n );
1995 mCachedFavorites[ type ].insert( n, isFav );
2004 QgsDebugMsg( QStringLiteral(
"Sorry! Cannot open database for getting the tags." ) );
2031 const QString query =
qgs_sqlite3_mprintf( QStringLiteral(
"SELECT tag_id FROM %1 WHERE tag_id=%d AND %2=%d" ).arg( tagmapTableName( type ),
2032 tagmapEntityIdFieldName( type ) ).toLocal8Bit().data(), tagid, symbolid );
2035 int nErr; statement = mCurrentDB.
prepare( query, nErr );
2037 return ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW );
2049 statement = mCurrentDB.
prepare( query, nError );
2052 if ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2060 int QgsStyle::getId(
const QString &table,
const QString &name )
2062 QString lowerName(
name.toLower() );
2063 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM %q WHERE LOWER(name)='%q'", table.toUtf8().constData(), lowerName.toUtf8().constData() );
2066 int nErr; statement = mCurrentDB.
prepare( query, nErr );
2069 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2071 id = sqlite3_column_int( statement.get(), 0 );
2076 QString query =
qgs_sqlite3_mprintf(
"SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(),
name.toUtf8().constData() );
2079 int nErr; statement = mCurrentDB.
prepare( query, nErr );
2080 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2082 id = sqlite3_column_int( statement.get(), 0 );
2089 QString QgsStyle::getName(
const QString &table,
int id )
const
2091 QString query =
qgs_sqlite3_mprintf(
"SELECT name FROM %q WHERE id='%q'", table.toUtf8().constData(), QString::number(
id ).toUtf8().constData() );
2094 int nErr; statement = mCurrentDB.
prepare( query, nErr );
2097 if ( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2107 return getId( QStringLiteral(
"symbol" ),
name );
2112 return getId( entityTableName( type ),
name );
2117 return getId( QStringLiteral(
"colorramp" ),
name );
2122 return mTextFormats.value(
name );
2127 return mTextFormats.count();
2132 return mTextFormats.keys();
2137 return getId( QStringLiteral(
"textformat" ),
name );
2142 return mLabelSettings.value(
name );
2147 return mLegendPatchShapes.value(
name );
2152 return mLegendPatchShapes.count();
2157 if ( !mLegendPatchShapes.contains(
name ) )
2160 return mLegendPatchShapes.value(
name ).symbolType();
2165 return m3dSymbols.contains(
name ) ? m3dSymbols.value(
name )->clone() :
nullptr;
2170 return m3dSymbols.count();
2175 if ( !m3dSymbols.contains(
name ) )
2176 return QList<QgsWkbTypes::GeometryType>();
2178 return m3dSymbols.value(
name )->compatibleGeometryTypes();
2183 if ( !mLabelSettings.contains(
name ) )
2186 return mLabelSettings.value(
name ).layerType;
2191 return mLabelSettings.count();
2196 return mLabelSettings.keys();
2201 return getId( QStringLiteral(
"labelsettings" ),
name );
2206 return mLegendPatchShapes.keys();
2214 return mPatchMarkerSymbol.get();
2217 return mPatchLineSymbol.get();
2220 return mPatchFillSymbol.get();
2230 return getId( QStringLiteral(
"tag" ),
name );
2235 return getId( QStringLiteral(
"smartgroup" ),
name );
2266 return QStringList();
2272 conditions.values( QStringLiteral(
"!tag" ) ),
2273 conditions.values( QStringLiteral(
"name" ) ),
2274 conditions.values( QStringLiteral(
"!name" ) ) );
2277 int QgsStyle::addSmartgroup(
const QString &name,
const QString &op,
const QStringList &matchTag,
const QStringList &noMatchTag,
const QStringList &matchName,
const QStringList &noMatchName )
2279 QDomDocument doc( QStringLiteral(
"dummy" ) );
2280 QDomElement smartEl = doc.createElement( QStringLiteral(
"smartgroup" ) );
2281 smartEl.setAttribute( QStringLiteral(
"name" ),
name );
2282 smartEl.setAttribute( QStringLiteral(
"operator" ), op );
2284 auto addCondition = [&doc, &smartEl](
const QString & constraint,
const QStringList & parameters )
2286 for (
const QString ¶m : parameters )
2288 QDomElement condEl = doc.createElement( QStringLiteral(
"condition" ) );
2289 condEl.setAttribute( QStringLiteral(
"constraint" ), constraint );
2290 condEl.setAttribute( QStringLiteral(
"param" ), param );
2291 smartEl.appendChild( condEl );
2294 addCondition( QStringLiteral(
"tag" ), matchTag );
2295 addCondition( QStringLiteral(
"!tag" ), noMatchTag );
2296 addCondition( QStringLiteral(
"name" ), matchName );
2297 addCondition( QStringLiteral(
"!name" ), noMatchName );
2299 QByteArray xmlArray;
2300 QTextStream stream( &xmlArray );
2301 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2302 stream.setCodec(
"UTF-8" );
2304 smartEl.save( stream, 4 );
2306 name.toUtf8().constData(), xmlArray.constData() );
2308 if ( runEmptyQuery( query ) )
2311 settings.
setValue( QStringLiteral(
"qgis/symbolsListGroupsIndex" ), 0 );
2314 return static_cast< int >( sqlite3_last_insert_rowid( mCurrentDB.get() ) );
2318 QgsDebugMsg( QStringLiteral(
"Couldn't add the smart group into the database!" ) );
2327 QgsDebugMsg( QStringLiteral(
"Cannot open database for listing groups" ) );
2336 statement = mCurrentDB.
prepare( query, nError );
2339 while ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2342 groupNames.insert( sqlite3_column_int( statement.get(),
SmartgroupId ), group );
2352 QgsDebugMsg( QStringLiteral(
"Cannot open database for listing groups" ) );
2353 return QStringList();
2361 statement = mCurrentDB.
prepare( query, nError );
2364 while ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2374 QStringList symbols;
2379 int nErr; statement = mCurrentDB.
prepare( query, nErr );
2380 if ( !( nErr == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW ) )
2382 return QStringList();
2388 if ( !doc.setContent( xmlstr ) )
2390 QgsDebugMsg( QStringLiteral(
"Cannot open smartgroup id: %1" ).arg(
id ) );
2392 QDomElement smartEl = doc.documentElement();
2393 QString op = smartEl.attribute( QStringLiteral(
"operator" ) );
2394 QDomNodeList conditionNodes = smartEl.childNodes();
2396 bool firstSet =
true;
2397 for (
int i = 0; i < conditionNodes.count(); i++ )
2399 QDomElement condEl = conditionNodes.at( i ).toElement();
2400 QString constraint = condEl.attribute( QStringLiteral(
"constraint" ) );
2401 QString param = condEl.attribute( QStringLiteral(
"param" ) );
2403 QStringList resultNames;
2405 if ( constraint == QLatin1String(
"tag" ) )
2409 else if ( constraint == QLatin1String(
"name" ) )
2411 resultNames =
allNames( type ).filter( param, Qt::CaseInsensitive );
2413 else if ( constraint == QLatin1String(
"!tag" ) )
2417 for (
const QString &
name : unwanted )
2419 resultNames.removeAll(
name );
2422 else if ( constraint == QLatin1String(
"!name" ) )
2424 const QStringList all =
allNames( type );
2425 for (
const QString &
str : all )
2427 if ( !
str.contains( param, Qt::CaseInsensitive ) )
2435 symbols = resultNames;
2440 if ( op == QLatin1String(
"OR" ) )
2442 symbols << resultNames;
2444 else if ( op == QLatin1String(
"AND" ) )
2446 QStringList dummy = symbols;
2448 for (
const QString &result : std::as_const( resultNames ) )
2450 if ( dummy.contains( result ) )
2459 QStringList unique = qgis::setToList( qgis::listToSet( symbols ) );
2460 std::sort( unique.begin(), unique.end() );
2468 QgsDebugMsg( QStringLiteral(
"Cannot open database for listing groups" ) );
2478 statement = mCurrentDB.
prepare( query, nError );
2479 if ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2483 if ( !doc.setContent( xmlstr ) )
2485 QgsDebugMsg( QStringLiteral(
"Cannot open smartgroup id: %1" ).arg(
id ) );
2488 QDomElement smartEl = doc.documentElement();
2489 QDomNodeList conditionNodes = smartEl.childNodes();
2491 for (
int i = 0; i < conditionNodes.count(); i++ )
2493 QDomElement condEl = conditionNodes.at( i ).toElement();
2494 QString constraint = condEl.attribute( QStringLiteral(
"constraint" ) );
2495 QString param = condEl.attribute( QStringLiteral(
"param" ) );
2497 condition.insert( constraint, param );
2508 QgsDebugMsg( QStringLiteral(
"Cannot open database for listing groups" ) );
2518 statement = mCurrentDB.
prepare( query, nError );
2519 if ( nError == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
2523 if ( !doc.setContent( xmlstr ) )
2525 QgsDebugMsg( QStringLiteral(
"Cannot open smartgroup id: %1" ).arg(
id ) );
2527 QDomElement smartEl = doc.documentElement();
2528 op = smartEl.attribute( QStringLiteral(
"operator" ) );
2536 if ( filename.isEmpty() )
2538 QgsDebugMsg( QStringLiteral(
"Invalid filename for style export." ) );
2542 QDomDocument doc( QStringLiteral(
"qgis_style" ) );
2543 QDomElement root = doc.createElement( QStringLiteral(
"qgis_style" ) );
2545 doc.appendChild( root );
2555 QDomNodeList symbolsList = symbolsElem.elementsByTagName( QStringLiteral(
"symbol" ) );
2556 int nbSymbols = symbolsList.count();
2557 for (
int i = 0; i < nbSymbols; ++i )
2559 QDomElement
symbol = symbolsList.at( i ).toElement();
2560 QString
name =
symbol.attribute( QStringLiteral(
"name" ) );
2562 if (
tags.count() > 0 )
2564 symbol.setAttribute( QStringLiteral(
"tags" ),
tags.join(
',' ) );
2566 if ( favoriteSymbols.contains(
name ) )
2568 symbol.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
2573 QDomElement rampsElem = doc.createElement( QStringLiteral(
"colorramps" ) );
2574 for ( QMap<QString, QgsColorRamp *>::const_iterator itr = mColorRamps.constBegin(); itr != mColorRamps.constEnd(); ++itr )
2578 if (
tags.count() > 0 )
2580 rampEl.setAttribute( QStringLiteral(
"tags" ),
tags.join(
',' ) );
2582 if ( favoriteColorramps.contains( itr.key() ) )
2584 rampEl.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
2586 rampsElem.appendChild( rampEl );
2590 QDomElement textFormatsElem = doc.createElement( QStringLiteral(
"textformats" ) );
2591 for (
auto it = mTextFormats.constBegin(); it != mTextFormats.constEnd(); ++it )
2593 QDomElement textFormatEl = doc.createElement( QStringLiteral(
"textformat" ) );
2594 textFormatEl.setAttribute( QStringLiteral(
"name" ), it.key() );
2596 textFormatEl.appendChild( textStyleEl );
2598 if (
tags.count() > 0 )
2600 textFormatEl.setAttribute( QStringLiteral(
"tags" ),
tags.join(
',' ) );
2602 if ( favoriteTextFormats.contains( it.key() ) )
2604 textFormatEl.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
2606 textFormatsElem.appendChild( textFormatEl );
2610 QDomElement labelSettingsElem = doc.createElement( QStringLiteral(
"labelsettings" ) );
2611 for (
auto it = mLabelSettings.constBegin(); it != mLabelSettings.constEnd(); ++it )
2613 QDomElement labelSettingsEl = doc.createElement( QStringLiteral(
"labelsetting" ) );
2614 labelSettingsEl.setAttribute( QStringLiteral(
"name" ), it.key() );
2616 labelSettingsEl.appendChild( defEl );
2618 if (
tags.count() > 0 )
2620 labelSettingsEl.setAttribute( QStringLiteral(
"tags" ),
tags.join(
',' ) );
2622 if ( favoriteTextFormats.contains( it.key() ) )
2624 labelSettingsEl.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
2626 labelSettingsElem.appendChild( labelSettingsEl );
2630 QDomElement legendPatchShapesElem = doc.createElement( QStringLiteral(
"legendpatchshapes" ) );
2631 for (
auto it = mLegendPatchShapes.constBegin(); it != mLegendPatchShapes.constEnd(); ++it )
2633 QDomElement legendPatchShapeEl = doc.createElement( QStringLiteral(
"legendpatchshape" ) );
2634 legendPatchShapeEl.setAttribute( QStringLiteral(
"name" ), it.key() );
2635 QDomElement defEl = doc.createElement( QStringLiteral(
"definition" ) );
2637 legendPatchShapeEl.appendChild( defEl );
2639 if (
tags.count() > 0 )
2641 legendPatchShapeEl.setAttribute( QStringLiteral(
"tags" ),
tags.join(
',' ) );
2643 if ( favoriteLegendShapes.contains( it.key() ) )
2645 legendPatchShapeEl.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
2647 legendPatchShapesElem.appendChild( legendPatchShapeEl );
2651 QDomElement symbols3DElem = doc.createElement( QStringLiteral(
"symbols3d" ) );
2652 for (
auto it = m3dSymbols.constBegin(); it != m3dSymbols.constEnd(); ++it )
2654 QDomElement symbolEl = doc.createElement( QStringLiteral(
"symbol3d" ) );
2655 symbolEl.setAttribute( QStringLiteral(
"name" ), it.key() );
2656 QDomElement defEl = doc.createElement( QStringLiteral(
"definition" ) );
2657 defEl.setAttribute( QStringLiteral(
"type" ), it.value()->type() );
2659 symbolEl.appendChild( defEl );
2661 if (
tags.count() > 0 )
2663 symbolEl.setAttribute( QStringLiteral(
"tags" ),
tags.join(
',' ) );
2665 if ( favorite3DSymbols.contains( it.key() ) )
2667 symbolEl.setAttribute( QStringLiteral(
"favorite" ), QStringLiteral(
"1" ) );
2669 symbols3DElem.appendChild( symbolEl );
2672 root.appendChild( symbolsElem );
2673 root.appendChild( rampsElem );
2674 root.appendChild( textFormatsElem );
2675 root.appendChild( labelSettingsElem );
2676 root.appendChild( legendPatchShapesElem );
2677 root.appendChild( symbols3DElem );
2680 QFile f( filename );
2681 if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
2683 mErrorString =
"Couldn't open file for writing: " + filename;
2687 QTextStream ts( &f );
2688 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
2689 ts.setCodec(
"UTF-8" );
2704 mErrorString = QString();
2705 QDomDocument doc( QStringLiteral(
"style" ) );
2706 QFile f( filename );
2707 if ( !f.open( QFile::ReadOnly ) )
2709 mErrorString = QStringLiteral(
"Unable to open the specified file" );
2710 QgsDebugMsg( QStringLiteral(
"Error opening the style XML file." ) );
2714 if ( !doc.setContent( &f ) )
2716 mErrorString = QStringLiteral(
"Unable to understand the style file: %1" ).arg( filename );
2717 QgsDebugMsg( QStringLiteral(
"XML Parsing error" ) );
2723 QDomElement docEl = doc.documentElement();
2724 if ( docEl.tagName() != QLatin1String(
"qgis_style" ) )
2726 mErrorString =
"Incorrect root tag in style: " + docEl.tagName();
2730 const QString version = docEl.attribute( QStringLiteral(
"version" ) );
2731 if ( version != QLatin1String(
STYLE_CURRENT_VERSION ) && version != QLatin1String(
"0" ) && version != QLatin1String(
"1" ) )
2733 mErrorString =
"Unknown style file version: " + version;
2739 QDomElement symbolsElement = docEl.firstChildElement( QStringLiteral(
"symbols" ) );
2740 QDomElement e = symbolsElement.firstChildElement();
2744 runEmptyQuery( query );
2749 for ( ; !e.isNull(); e = e.nextSiblingElement() )
2751 const int entityAddedVersion = e.attribute( QStringLiteral(
"addedVersion" ) ).toInt();
2752 if ( entityAddedVersion != 0 && sinceVersion != -1 && entityAddedVersion <= sinceVersion )
2758 if ( e.tagName() == QLatin1String(
"symbol" ) )
2760 QString
name = e.attribute( QStringLiteral(
"name" ) );
2762 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
2764 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
2766 bool favorite =
false;
2767 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QLatin1String(
"1" ) )
2794 for ( QMap<QString, QgsSymbol *>::iterator it = symbols.begin(); it != symbols.end(); ++it )
2801 QDomElement rampsElement = docEl.firstChildElement( QStringLiteral(
"colorramps" ) );
2802 e = rampsElement.firstChildElement();
2803 for ( ; !e.isNull(); e = e.nextSiblingElement() )
2805 const int entityAddedVersion = e.attribute( QStringLiteral(
"addedVersion" ) ).toInt();
2806 if ( entityAddedVersion != 0 && sinceVersion != -1 && entityAddedVersion <= sinceVersion )
2812 if ( e.tagName() == QLatin1String(
"colorramp" ) )
2814 QString
name = e.attribute( QStringLiteral(
"name" ) );
2816 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
2818 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
2820 bool favorite =
false;
2821 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QLatin1String(
"1" ) )
2845 if ( qobject_cast< QGuiApplication * >( QCoreApplication::instance() ) )
2849 const QDomElement textFormatElement = docEl.firstChildElement( QStringLiteral(
"textformats" ) );
2850 e = textFormatElement.firstChildElement();
2851 for ( ; !e.isNull(); e = e.nextSiblingElement() )
2853 const int entityAddedVersion = e.attribute( QStringLiteral(
"addedVersion" ) ).toInt();
2854 if ( entityAddedVersion != 0 && sinceVersion != -1 && entityAddedVersion <= sinceVersion )
2860 if ( e.tagName() == QLatin1String(
"textformat" ) )
2862 QString
name = e.attribute( QStringLiteral(
"name" ) );
2864 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
2866 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
2868 bool favorite =
false;
2869 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QLatin1String(
"1" ) )
2875 const QDomElement styleElem = e.firstChildElement();
2893 const QDomElement labelSettingsElement = docEl.firstChildElement( QStringLiteral(
"labelsettings" ) );
2894 e = labelSettingsElement.firstChildElement();
2895 for ( ; !e.isNull(); e = e.nextSiblingElement() )
2897 const int entityAddedVersion = e.attribute( QStringLiteral(
"addedVersion" ) ).toInt();
2898 if ( entityAddedVersion != 0 && sinceVersion != -1 && entityAddedVersion <= sinceVersion )
2904 if ( e.tagName() == QLatin1String(
"labelsetting" ) )
2906 QString
name = e.attribute( QStringLiteral(
"name" ) );
2908 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
2910 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
2912 bool favorite =
false;
2913 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QLatin1String(
"1" ) )
2919 const QDomElement styleElem = e.firstChildElement();
2938 const QDomElement legendPatchShapesElement = docEl.firstChildElement( QStringLiteral(
"legendpatchshapes" ) );
2939 e = legendPatchShapesElement.firstChildElement();
2940 for ( ; !e.isNull(); e = e.nextSiblingElement() )
2942 const int entityAddedVersion = e.attribute( QStringLiteral(
"addedVersion" ) ).toInt();
2943 if ( entityAddedVersion != 0 && sinceVersion != -1 && entityAddedVersion <= sinceVersion )
2949 if ( e.tagName() == QLatin1String(
"legendpatchshape" ) )
2951 QString
name = e.attribute( QStringLiteral(
"name" ) );
2953 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
2955 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
2957 bool favorite =
false;
2958 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QLatin1String(
"1" ) )
2964 const QDomElement shapeElem = e.firstChildElement();
2982 const QDomElement symbols3DElement = docEl.firstChildElement( QStringLiteral(
"symbols3d" ) );
2983 e = symbols3DElement.firstChildElement();
2984 for ( ; !e.isNull(); e = e.nextSiblingElement() )
2986 const int entityAddedVersion = e.attribute( QStringLiteral(
"addedVersion" ) ).toInt();
2987 if ( entityAddedVersion != 0 && sinceVersion != -1 && entityAddedVersion <= sinceVersion )
2993 if ( e.tagName() == QLatin1String(
"symbol3d" ) )
2995 QString
name = e.attribute( QStringLiteral(
"name" ) );
2997 if ( e.hasAttribute( QStringLiteral(
"tags" ) ) )
2999 tags = e.attribute( QStringLiteral(
"tags" ) ).split(
',' );
3001 bool favorite =
false;
3002 if ( e.hasAttribute( QStringLiteral(
"favorite" ) ) && e.attribute( QStringLiteral(
"favorite" ) ) == QLatin1String(
"1" ) )
3007 const QDomElement symbolElem = e.firstChildElement();
3008 const QString type = symbolElem.attribute( QStringLiteral(
"type" ) );
3029 runEmptyQuery( query );
3036 QFileInfo fileInfo( path );
3038 if ( fileInfo.suffix().compare( QLatin1String(
"xml" ), Qt::CaseInsensitive ) != 0 )
3042 if ( !QFile::exists( path ) )
3045 QFile inputFile( path );
3046 if ( !inputFile.open( QIODevice::ReadOnly ) )
3049 QTextStream stream( &inputFile );
3050 const QString line = stream.readLine();
3051 return line == QLatin1String(
"<!DOCTYPE qgis_style>" );
3066 mReadOnly = readOnly;
3069 bool QgsStyle::updateSymbol( StyleEntity type,
const QString &name )
3071 QDomDocument doc( QStringLiteral(
"dummy" ) );
3073 QByteArray xmlArray;
3074 QTextStream stream( &xmlArray );
3075 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
3076 stream.setCodec(
"UTF-8" );
3088 QgsDebugMsg( QStringLiteral(
"Update request received for unavailable symbol" ) );
3093 if ( symEl.isNull() )
3095 QgsDebugMsg( QStringLiteral(
"Couldn't convert symbol to valid XML!" ) );
3098 symEl.save( stream, 4 );
3100 xmlArray.constData(),
name.toUtf8().constData() );
3109 QgsDebugMsg( QStringLiteral(
"Update request received for unavailable symbol" ) );
3113 symEl = doc.createElement( QStringLiteral(
"symbol" ) );
3114 symEl.setAttribute( QStringLiteral(
"type" ), m3dSymbols.value(
name )->type() );
3116 if ( symEl.isNull() )
3118 QgsDebugMsg( QStringLiteral(
"Couldn't convert symbol to valid XML!" ) );
3121 symEl.save( stream, 4 );
3123 xmlArray.constData(),
name.toUtf8().constData() );
3131 QgsDebugMsg( QStringLiteral(
"Update requested for unavailable color ramp." ) );
3137 if ( symEl.isNull() )
3139 QgsDebugMsg( QStringLiteral(
"Couldn't convert color ramp to valid XML!" ) );
3142 symEl.save( stream, 4 );
3144 xmlArray.constData(),
name.toUtf8().constData() );
3152 QgsDebugMsg( QStringLiteral(
"Update requested for unavailable text format." ) );
3158 if ( symEl.isNull() )
3160 QgsDebugMsg( QStringLiteral(
"Couldn't convert text format to valid XML!" ) );
3163 symEl.save( stream, 4 );
3165 xmlArray.constData(),
name.toUtf8().constData() );
3173 QgsDebugMsg( QStringLiteral(
"Update requested for unavailable label settings." ) );
3179 if ( symEl.isNull() )
3181 QgsDebugMsg( QStringLiteral(
"Couldn't convert label settings to valid XML!" ) );
3184 symEl.save( stream, 4 );
3186 xmlArray.constData(),
name.toUtf8().constData() );
3194 QgsDebugMsg( QStringLiteral(
"Update requested for unavailable legend patch shape." ) );
3199 symEl = doc.createElement( QStringLiteral(
"shape" ) );
3201 symEl.save( stream, 4 );
3203 xmlArray.constData(),
name.toUtf8().constData() );
3210 QgsDebugMsg( QStringLiteral(
"Updating the unsupported StyleEntity" ) );
3216 if ( !runEmptyQuery( query ) )
3218 QgsDebugMsg( QStringLiteral(
"Couldn't update symbol into the database!" ) );
3254 mCachedTags[ type ].remove(
name );
3257 bool QgsStyle::createStyleMetadataTableIfNeeded()
3260 QString query =
qgs_sqlite3_mprintf(
"SELECT name FROM sqlite_master WHERE name='stylemetadata'" );
3263 statement = mCurrentDB.
prepare( query, rc );
3265 if ( rc != SQLITE_OK || sqlite3_step( statement.get() ) != SQLITE_ROW )
3269 "id INTEGER PRIMARY KEY,"\
3272 runEmptyQuery( query );
3274 runEmptyQuery( query );
3283 void QgsStyle::upgradeIfRequired()
3287 if ( !createStyleMetadataTableIfNeeded() )
3289 const QString query =
qgs_sqlite3_mprintf(
"SELECT value FROM stylemetadata WHERE key='version'" );
3292 if ( rc == SQLITE_OK && sqlite3_step( statement.get() ) == SQLITE_ROW )
3304 runEmptyQuery( query );
3314 return QStringLiteral(
"symbol" );
3317 return QStringLiteral(
"colorramp" );
3320 return QStringLiteral(
"textformat" );
3323 return QStringLiteral(
"labelsettings" );
3326 return QStringLiteral(
"legendpatchshapes" );
3329 return QStringLiteral(
"symbol3d" );
3332 return QStringLiteral(
"tag" );
3335 return QStringLiteral(
"smartgroup" );
3345 return QStringLiteral(
"tagmap" );
3348 return QStringLiteral(
"ctagmap" );
3351 return QStringLiteral(
"tftagmap" );
3354 return QStringLiteral(
"lstagmap" );
3357 return QStringLiteral(
"lpstagmap" );
3360 return QStringLiteral(
"symbol3dtagmap" );
3374 return QStringLiteral(
"symbol_id" );
3377 return QStringLiteral(
"colorramp_id" );
3380 return QStringLiteral(
"textformat_id" );
3383 return QStringLiteral(
"labelsettings_id" );
3386 return QStringLiteral(
"legendpatchshape_id" );
3389 return QStringLiteral(
"symbol3d_id" );