QGIS API Documentation  master-59fd5e0
src/core/symbology-ng/qgsstylev2.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsstylev2.cpp
00003     ---------------------
00004     begin                : November 2009
00005     copyright            : (C) 2009 by Martin Dobias
00006     email                : wonder dot sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgsstylev2.h"
00017 
00018 #include "qgssymbolv2.h"
00019 #include "qgsvectorcolorrampv2.h"
00020 
00021 #include "qgssymbollayerv2registry.h"
00022 
00023 #include "qgsapplication.h"
00024 #include "qgslogger.h"
00025 
00026 #include <QDomDocument>
00027 #include <QDomElement>
00028 #include <QDomNode>
00029 #include <QDomNodeList>
00030 #include <QFile>
00031 #include <QTextStream>
00032 #include <QByteArray>
00033 
00034 #include <sqlite3.h>
00035 
00036 #define STYLE_CURRENT_VERSION  "1"
00037 
00038 QgsStyleV2 *QgsStyleV2::mDefaultStyle = 0;
00039 
00040 
00041 QgsStyleV2::QgsStyleV2()
00042 {
00043   mCurrentDB = 0;
00044 }
00045 
00046 QgsStyleV2::~QgsStyleV2()
00047 {
00048   clear();
00049 }
00050 
00051 QgsStyleV2* QgsStyleV2::defaultStyle() // static
00052 {
00053   if ( !mDefaultStyle )
00054   {
00055     QString styleFilename = QgsApplication::userStyleV2Path();
00056 
00057     // copy default style if user style doesn't exist
00058     if ( !QFile::exists( styleFilename ) )
00059     {
00060       QFile::copy( QgsApplication::defaultStyleV2Path(), styleFilename );
00061     }
00062 
00063     mDefaultStyle = new QgsStyleV2;
00064     mDefaultStyle->load( styleFilename );
00065   }
00066   return mDefaultStyle;
00067 }
00068 
00069 
00070 void QgsStyleV2::clear()
00071 {
00072   for ( QMap<QString, QgsSymbolV2*>::iterator its = mSymbols.begin(); its != mSymbols.end(); ++its )
00073     delete its.value();
00074   for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
00075     delete itr.value();
00076 
00077   mSymbols.clear();
00078   mColorRamps.clear();
00079   if ( mCurrentDB )
00080     sqlite3_close( mCurrentDB );
00081 }
00082 
00083 bool QgsStyleV2::addSymbol( QString name, QgsSymbolV2* symbol, bool update )
00084 {
00085   if ( !symbol || name.isEmpty() )
00086     return false;
00087 
00088   // delete previous symbol (if any)
00089   if ( mSymbols.contains( name ) )
00090   {
00091     // TODO remove groups and tags?
00092     delete mSymbols.value( name );
00093     mSymbols.insert( name, symbol );
00094     if ( update )
00095       updateSymbol( SymbolEntity, name );
00096   }
00097   else
00098   {
00099     mSymbols.insert( name, symbol );
00100     if ( update )
00101       saveSymbol( name, symbol, 0, QStringList() );
00102   }
00103 
00104   return true;
00105 }
00106 
00107 bool QgsStyleV2::saveSymbol( QString name, QgsSymbolV2* symbol, int groupid, QStringList tags )
00108 {
00109   // TODO add support for tags and groups
00110   Q_UNUSED( tags );
00111 
00112   QDomDocument doc( "dummy" );
00113   QDomElement symEl = QgsSymbolLayerV2Utils::saveSymbol( name, symbol, doc );
00114   if ( symEl.isNull() )
00115   {
00116     QgsDebugMsg( "Couldn't convert symbol to valid XML!" );
00117     return false;
00118   }
00119 
00120   QByteArray xmlArray;
00121   QTextStream stream( &xmlArray );
00122   symEl.save( stream, 4 );
00123   char *query = sqlite3_mprintf( "INSERT INTO symbol VALUES (NULL, '%q', '%q', %d);",
00124                                  name.toUtf8().constData(), xmlArray.constData(), groupid );
00125 
00126   if ( !runEmptyQuery( query ) )
00127   {
00128     QgsDebugMsg( "Couldn't insert symbol into the database!" );
00129     return false;
00130   }
00131 
00132   return true;
00133 }
00134 
00135 bool QgsStyleV2::removeSymbol( QString name )
00136 {
00137   QgsSymbolV2 *symbol = mSymbols.take( name );
00138   if ( !symbol )
00139     return false;
00140 
00141   // remove from map and delete
00142   delete symbol;
00143 
00144   // TODO
00145   // Simplify this work here, its STUPID to run two DB queries for the sake of remove()
00146   if ( !mCurrentDB )
00147   {
00148     QgsDebugMsg( "Sorry! Cannot open database to tag." );
00149     return false;
00150   }
00151 
00152   int symbolid = symbolId( name );
00153   if ( !symbolid )
00154   {
00155     QgsDebugMsg( "No such symbol for deleting in database: " + name + ". Cheers." );
00156   }
00157 
00158   remove( SymbolEntity, symbolid );
00159 
00160   return true;
00161 }
00162 
00163 QgsSymbolV2* QgsStyleV2::symbol( QString name )
00164 {
00165   const QgsSymbolV2 *symbol = symbolRef( name );
00166   return symbol ? symbol->clone() : 0;
00167 }
00168 
00169 const QgsSymbolV2 *QgsStyleV2::symbolRef( QString name ) const
00170 {
00171   return mSymbols.value( name );
00172 }
00173 
00174 int QgsStyleV2::symbolCount()
00175 {
00176   return mSymbols.count();
00177 }
00178 
00179 QStringList QgsStyleV2::symbolNames()
00180 {
00181   return mSymbols.keys();
00182 }
00183 
00184 
00185 bool QgsStyleV2::addColorRamp( QString name, QgsVectorColorRampV2* colorRamp, bool update )
00186 {
00187   if ( !colorRamp || name.isEmpty() )
00188     return false;
00189 
00190   // delete previous color ramps (if any)
00191   if ( mColorRamps.contains( name ) )
00192   {
00193     // TODO remove groups and tags?
00194     delete mColorRamps.value( name );
00195     mColorRamps.insert( name, colorRamp );
00196     if ( update )
00197       updateSymbol( ColorrampEntity, name );
00198   }
00199   else
00200   {
00201     mColorRamps.insert( name, colorRamp );
00202     if ( update )
00203       saveColorRamp( name, colorRamp, 0, QStringList() );
00204   }
00205 
00206   return true;
00207 }
00208 
00209 bool QgsStyleV2::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, int groupid, QStringList tags )
00210 {
00211   // TODO add support for groups and tags
00212   Q_UNUSED( tags );
00213 
00214   // insert it into the database
00215   QDomDocument doc( "dummy" );
00216   QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( name, ramp, doc );
00217   if ( rampEl.isNull() )
00218   {
00219     QgsDebugMsg( "Couldn't convert color ramp to valid XML!" );
00220     return false;
00221   }
00222 
00223   QByteArray xmlArray;
00224   QTextStream stream( &xmlArray );
00225   rampEl.save( stream, 4 );
00226   char *query = sqlite3_mprintf( "INSERT INTO colorramp VALUES (NULL, '%q', '%q', %d);",
00227                                  name.toUtf8().constData(), xmlArray.constData(), groupid );
00228 
00229   if ( !runEmptyQuery( query ) )
00230   {
00231     QgsDebugMsg( "Couldn't insert colorramp into the database!" );
00232     return false;
00233   }
00234 
00235   return true;
00236 }
00237 
00238 bool QgsStyleV2::removeColorRamp( QString name )
00239 {
00240   QgsVectorColorRampV2 *ramp = mColorRamps.take( name );
00241   if ( !ramp )
00242     return false;
00243 
00244   char *query = sqlite3_mprintf( "DELETE FROM colorramp WHERE name='%q'", name.toUtf8().constData() );
00245   if ( !runEmptyQuery( query ) )
00246   {
00247     QgsDebugMsg( "Couldn't remove color ramp from the database." );
00248     return false;
00249   }
00250 
00251   delete ramp;
00252 
00253   return true;
00254 }
00255 
00256 QgsVectorColorRampV2* QgsStyleV2::colorRamp( QString name )
00257 {
00258   const QgsVectorColorRampV2 *ramp = colorRampRef( name );
00259   return ramp ? ramp->clone() : 0;
00260 }
00261 
00262 const QgsVectorColorRampV2* QgsStyleV2::colorRampRef( QString name ) const
00263 {
00264   return mColorRamps.value( name );
00265 }
00266 
00267 int QgsStyleV2::colorRampCount()
00268 {
00269   return mColorRamps.count();
00270 }
00271 
00272 QStringList QgsStyleV2::colorRampNames()
00273 {
00274   return mColorRamps.keys();
00275 }
00276 
00277 bool QgsStyleV2::openDB( QString filename )
00278 {
00279   int rc = sqlite3_open( filename.toUtf8(), &mCurrentDB );
00280   if ( rc )
00281   {
00282     mErrorString = "Couldn't open the style database: " + QString( sqlite3_errmsg( mCurrentDB ) );
00283     sqlite3_close( mCurrentDB );
00284     return false;
00285   }
00286 
00287   return true;
00288 }
00289 
00290 bool QgsStyleV2::load( QString filename )
00291 {
00292   mErrorString.clear();
00293 
00294   // Open the sqlite database
00295   if ( !openDB( filename ) )
00296   {
00297     mErrorString = "Unable to open database file specified";
00298     QgsDebugMsg( mErrorString );
00299     return false;
00300   }
00301 
00302   // Make sure there are no Null fields in parenting symbols ang groups
00303   char *query = sqlite3_mprintf( "UPDATE symbol SET groupid=0 WHERE groupid IS NULL;"
00304                                  "UPDATE colorramp SET groupid=0 WHERE groupid IS NULL;"
00305                                  "UPDATE symgroup SET parent=0 WHERE parent IS NULL;" );
00306   runEmptyQuery( query );
00307 
00308   // First create all the main symbols
00309   query = sqlite3_mprintf( "SELECT * FROM symbol" );
00310 
00311   sqlite3_stmt *ppStmt;
00312   int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00313   while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00314   {
00315     QDomDocument doc;
00316     QString symbol_name = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymbolName ) );
00317     QString xmlstring = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymbolXML ) );
00318     if ( !doc.setContent( xmlstring ) )
00319     {
00320       QgsDebugMsg( "Cannot open symbol " + symbol_name );
00321       continue;
00322     }
00323 
00324     QDomElement symElement = doc.documentElement();
00325     QgsSymbolV2 *symbol = QgsSymbolLayerV2Utils::loadSymbol( symElement );
00326     if ( symbol != NULL )
00327       mSymbols.insert( symbol_name, symbol );
00328   }
00329 
00330   sqlite3_finalize( ppStmt );
00331 
00332   query = sqlite3_mprintf( "SELECT * FROM colorramp" );
00333   nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00334   while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00335   {
00336     QDomDocument doc;
00337     QString ramp_name = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, ColorrampName ) );
00338     QString xmlstring = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, ColorrampXML ) );
00339     if ( !doc.setContent( xmlstring ) )
00340     {
00341       QgsDebugMsg( "Cannot open symbol " + ramp_name );
00342       continue;
00343     }
00344     QDomElement rampElement = doc.documentElement();
00345     QgsVectorColorRampV2 *ramp = QgsSymbolLayerV2Utils::loadColorRamp( rampElement );
00346     if ( ramp )
00347       mColorRamps.insert( ramp_name, ramp );
00348   }
00349 
00350   mFileName = filename;
00351   return true;
00352 }
00353 
00354 
00355 
00356 bool QgsStyleV2::save( QString filename )
00357 {
00358   mErrorString.clear();
00359 
00360   if ( filename.isEmpty() )
00361     filename = mFileName;
00362 
00363   // TODO evaluate the requirement of this function and change implementation accordingly
00364   // TODO remove QEXPECT_FAIL from TestStyleV2::testSaveLoad() when done
00365 #if 0
00366   QDomDocument doc( "qgis_style" );
00367   QDomElement root = doc.createElement( "qgis_style" );
00368   root.setAttribute( "version", STYLE_CURRENT_VERSION );
00369   doc.appendChild( root );
00370 
00371   QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( mSymbols, "symbols", doc );
00372 
00373   QDomElement rampsElem = doc.createElement( "colorramps" );
00374 
00375   // save color ramps
00376   for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
00377   {
00378     QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( itr.key(), itr.value(), doc );
00379     rampsElem.appendChild( rampEl );
00380   }
00381 
00382   root.appendChild( symbolsElem );
00383   root.appendChild( rampsElem );
00384 
00385   // save
00386   QFile f( filename );
00387   if ( !f.open( QFile::WriteOnly ) )
00388   {
00389     mErrorString = "Couldn't open file for writing: " + filename;
00390     return false;
00391   }
00392   QTextStream ts( &f );
00393   doc.save( ts, 2 );
00394   f.close();
00395 #endif
00396 
00397   mFileName = filename;
00398   return true;
00399 }
00400 
00401 bool QgsStyleV2::renameSymbol( QString oldName, QString newName )
00402 {
00403   QgsSymbolV2 *symbol = mSymbols.take( oldName );
00404   if ( !symbol )
00405     return false;
00406 
00407   mSymbols.insert( newName, symbol );
00408 
00409   if ( !mCurrentDB )
00410   {
00411     QgsDebugMsg( "Sorry! Cannot open database to tag." );
00412     return false;
00413   }
00414 
00415   int symbolid = symbolId( oldName );
00416   if ( !symbolid )
00417   {
00418     QgsDebugMsg( "No such symbol for tagging in database: " + oldName );
00419     return false;
00420   }
00421 
00422   rename( SymbolEntity, symbolid, newName );
00423 
00424   return true;
00425 }
00426 
00427 bool QgsStyleV2::renameColorRamp( QString oldName, QString newName )
00428 {
00429   QgsVectorColorRampV2 *ramp = mColorRamps.take( oldName );
00430   if ( !ramp )
00431     return false;
00432 
00433   mColorRamps.insert( newName, ramp );
00434 
00435   int rampid = 0;
00436   sqlite3_stmt *ppStmt;
00437   char *query = sqlite3_mprintf( "SELECT id FROM colorramp WHERE name='%q'", oldName.toUtf8().constData() );
00438   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00439   if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00440   {
00441     rampid = sqlite3_column_int( ppStmt, 0 );
00442   }
00443   sqlite3_finalize( ppStmt );
00444   rename( ColorrampEntity, rampid, newName );
00445 
00446   return true;
00447 }
00448 
00449 QStringList QgsStyleV2::groupNames()
00450 {
00451   QStringList groupNames;
00452   sqlite3_stmt *ppStmt;
00453   const char *query = "SELECT * FROM symgroup";
00454   int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00455   while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00456   {
00457     groupNames << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymgroupName ) );
00458   }
00459   sqlite3_finalize( ppStmt );
00460   return groupNames;
00461 }
00462 
00463 QgsSymbolGroupMap QgsStyleV2::childGroupNames( QString parent )
00464 {
00465   // get the name list from the sqlite database and return as a QStringList
00466   if ( !mCurrentDB )
00467   {
00468     QgsDebugMsg( "Cannot open database for listing groups" );
00469     return QgsSymbolGroupMap();
00470   }
00471 
00472   char *query = 0;
00473   int nError;
00474   sqlite3_stmt *ppStmt;
00475 
00476   // decide the query to be run based on parent group
00477   if ( parent == "" || parent == QString() )
00478   {
00479     query = sqlite3_mprintf( "SELECT * FROM symgroup WHERE parent=0" );
00480   }
00481   else
00482   {
00483     char *subquery = sqlite3_mprintf( "SELECT * FROM symgroup WHERE name='%q'", parent.toUtf8().constData() );
00484     nError = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt, NULL );
00485     if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00486     {
00487       query = sqlite3_mprintf( "SELECT * FROM symgroup WHERE parent=%d", sqlite3_column_int( ppStmt, SymgroupId ) );
00488     }
00489     sqlite3_finalize( ppStmt );
00490   }
00491 
00492   if ( !query )
00493     return QgsSymbolGroupMap();
00494 
00495   QgsSymbolGroupMap groupNames;
00496 
00497   // Now run the query and retrieve the group names
00498   nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00499   while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00500   {
00501     QString group = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymgroupName ) );
00502     groupNames.insert( sqlite3_column_int( ppStmt, SymgroupId ), group );
00503   }
00504 
00505   sqlite3_finalize( ppStmt );
00506 
00507   return groupNames;
00508 }
00509 
00510 QStringList QgsStyleV2::symbolsOfGroup( StyleEntity type, int groupid )
00511 {
00512   if ( !mCurrentDB )
00513   {
00514     QgsDebugMsg( QString( "Cannot Open database for getting group symbols of groupid: %1" ).arg( groupid ) );
00515     return QStringList();
00516   }
00517 
00518   char *query;
00519   if ( type == SymbolEntity )
00520   {
00521     query = sqlite3_mprintf( "SELECT name FROM symbol WHERE groupid=%d", groupid );
00522   }
00523   else if ( type == ColorrampEntity )
00524   {
00525     query = sqlite3_mprintf( "SELECT name FROM colorramp WHERE groupid=%d", groupid );
00526   }
00527   else
00528   {
00529     QgsDebugMsg( "No such style entity" );
00530     return QStringList();
00531   }
00532 
00533   sqlite3_stmt *ppStmt;
00534   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00535 
00536   QStringList symbols;
00537   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00538   {
00539     symbols << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
00540   }
00541 
00542   sqlite3_finalize( ppStmt );
00543 
00544   return symbols;
00545 }
00546 
00547 QStringList QgsStyleV2::symbolsWithTag( StyleEntity type, int tagid )
00548 {
00549   if ( !mCurrentDB )
00550   {
00551     QgsDebugMsg( QString( "Cannot open database to get symbols of tagid %1" ).arg( tagid ) );
00552     return QStringList();
00553   }
00554 
00555   char *subquery;
00556   if ( type == SymbolEntity )
00557   {
00558     subquery = sqlite3_mprintf( "SELECT symbol_id FROM tagmap WHERE tag_id=%d", tagid );
00559   }
00560   else if ( type == ColorrampEntity )
00561   {
00562     subquery = sqlite3_mprintf( "SELECT symbol_id FROM ctagmap WHERE tag_id=%d", tagid );
00563   }
00564   else
00565   {
00566     QgsDebugMsg( "Unknown Entity" );
00567     return QStringList();
00568   }
00569 
00570   sqlite3_stmt *ppStmt;
00571   int nErr = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt, NULL );
00572 
00573   // get the symbol <-> tag connection from table 'tagmap'
00574   QStringList symbols;
00575   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00576   {
00577     int symbolId = sqlite3_column_int( ppStmt, 0 );
00578 
00579     char *query = type == SymbolEntity
00580                   ? sqlite3_mprintf( "SELECT name FROM symbol WHERE id=%d", symbolId )
00581                   : sqlite3_mprintf( "SELECT name FROM colorramp WHERE id=%d", symbolId );
00582 
00583     sqlite3_stmt *ppStmt2;
00584     int sErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt2, NULL );
00585     while ( sErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
00586     {
00587       symbols << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt2, 0 ) );
00588     }
00589     sqlite3_finalize( ppStmt2 );
00590   }
00591   sqlite3_finalize( ppStmt );
00592 
00593   return symbols;
00594 }
00595 
00596 int QgsStyleV2::addGroup( QString groupName, int parentid )
00597 {
00598   if ( !mCurrentDB )
00599     return 0;
00600 
00601   char *query = sqlite3_mprintf( "INSERT INTO symgroup VALUES (NULL, '%q', %d)", groupName.toUtf8().constData(), parentid );
00602 
00603   sqlite3_stmt *ppStmt;
00604   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00605   if ( nErr == SQLITE_OK )
00606     sqlite3_step( ppStmt );
00607 
00608   sqlite3_finalize( ppStmt );
00609 
00610   return ( int )sqlite3_last_insert_rowid( mCurrentDB );
00611 }
00612 
00613 int QgsStyleV2::addTag( QString tagname )
00614 {
00615   if ( !mCurrentDB )
00616     return 0;
00617   sqlite3_stmt *ppStmt;
00618 
00619   char *query = sqlite3_mprintf( "INSERT INTO tag VALUES (NULL, '%q')", tagname.toUtf8().constData() );
00620   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00621   if ( nErr == SQLITE_OK )
00622     sqlite3_step( ppStmt );
00623   sqlite3_finalize( ppStmt );
00624 
00625   return ( int )sqlite3_last_insert_rowid( mCurrentDB );
00626 }
00627 
00628 void QgsStyleV2::rename( StyleEntity type, int id, QString newName )
00629 {
00630   char *query;
00631   switch ( type )
00632   {
00633     case SymbolEntity:
00634       query = sqlite3_mprintf( "UPDATE symbol SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
00635       break;
00636     case GroupEntity:
00637       query = sqlite3_mprintf( "UPDATE symgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
00638       break;
00639     case TagEntity:
00640       query = sqlite3_mprintf( "UPDATE tag SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
00641       break;
00642     case ColorrampEntity:
00643       query = sqlite3_mprintf( "UPDATE colorramp SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
00644       break;
00645     case SmartgroupEntity:
00646       query = sqlite3_mprintf( "UPDATE smartgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
00647       break;
00648     default:
00649       QgsDebugMsg( "Invalid Style Entity indicated" );
00650       return;
00651   }
00652   if ( !runEmptyQuery( query ) )
00653     mErrorString = "Could not rename!";
00654 }
00655 
00656 char* QgsStyleV2::getGroupRemoveQuery( int id )
00657 {
00658   char *query = sqlite3_mprintf( "SELECT parent FROM symgroup WHERE id=%d", id );
00659 
00660   sqlite3_stmt *ppStmt;
00661   int err = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00662 
00663   int parentid = 0;
00664   if ( err == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00665     parentid = sqlite3_column_int( ppStmt, 0 );
00666 
00667   sqlite3_finalize( ppStmt );
00668 
00669   return sqlite3_mprintf( "UPDATE symbol SET groupid=%d WHERE groupid=%d;"
00670                           "UPDATE symgroup SET parent=%d WHERE parent=%d;"
00671                           "DELETE FROM symgroup WHERE id=%d", parentid, id, parentid, id, id );
00672 }
00673 
00674 void QgsStyleV2::remove( StyleEntity type, int id )
00675 {
00676   char *query;
00677   switch ( type )
00678   {
00679     case SymbolEntity:
00680       query = sqlite3_mprintf( "DELETE FROM symbol WHERE id=%d; DELETE FROM tagmap WHERE symbol_id=%d", id, id );
00681       break;
00682     case GroupEntity:
00683       query = getGroupRemoveQuery( id );
00684       break;
00685     case TagEntity:
00686       query = sqlite3_mprintf( "DELETE FROM tag WHERE id=%d; DELETE FROM tagmap WHERE tag_id=%d", id, id );
00687       break;
00688     case ColorrampEntity:
00689       query = sqlite3_mprintf( "DELETE FROM colorramp WHERE id=%d", id );
00690       break;
00691     case SmartgroupEntity:
00692       query = sqlite3_mprintf( "DELETE FROM smartgroup WHERE id=%d", id );
00693       break;
00694     default:
00695       QgsDebugMsg( "Invalid Style Entity indicated" );
00696       return;
00697   }
00698 
00699   if ( !runEmptyQuery( query ) )
00700   {
00701     QgsDebugMsg( "Could not delete entity!" );
00702   }
00703 }
00704 
00705 bool QgsStyleV2::runEmptyQuery( char *query, bool freeQuery )
00706 {
00707   if ( !mCurrentDB )
00708     return false;
00709 
00710   char *zErr = 0;
00711   int nErr = sqlite3_exec( mCurrentDB, query, NULL, NULL, &zErr );
00712 
00713   if ( freeQuery )
00714   {
00715     sqlite3_free( query );
00716   }
00717 
00718   if ( nErr != SQLITE_OK )
00719   {
00720     QgsDebugMsg( zErr );
00721   }
00722 
00723   return zErr == SQLITE_OK;
00724 }
00725 
00726 bool QgsStyleV2::group( StyleEntity type, QString name, int groupid )
00727 {
00728   char *query;
00729 
00730   switch ( type )
00731   {
00732     case SymbolEntity:
00733       query = sqlite3_mprintf( "UPDATE symbol SET groupid=%d WHERE name='%q'", groupid, name.toUtf8().constData() );
00734       break;
00735     case ColorrampEntity:
00736       query = sqlite3_mprintf( "UPDATE colorramp SET groupid=%d WHERE name='%q'", groupid, name.toUtf8().constData() );
00737       break;
00738 
00739     default:
00740       QgsDebugMsg( "Wrong entity value. cannot apply group" );
00741       return false;
00742   }
00743 
00744   return runEmptyQuery( query );
00745 }
00746 
00747 QStringList QgsStyleV2::findSymbols( QString qword )
00748 {
00749   if ( !mCurrentDB )
00750   {
00751     QgsDebugMsg( "Sorry! Cannot open database to search" );
00752     return QStringList();
00753   }
00754 
00755   char *query = sqlite3_mprintf( "SELECT name FROM symbol WHERE xml LIKE '%%%q%%'", qword.toUtf8().constData() );
00756 
00757   sqlite3_stmt *ppStmt;
00758   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00759 
00760   QStringList symbols;
00761   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00762   {
00763     symbols << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
00764   }
00765 
00766   sqlite3_finalize( ppStmt );
00767 
00768 
00769   query = sqlite3_mprintf( "SELECT id FROM tag WHERE name LIKE '%%%q%%'", qword.toUtf8().constData() );
00770   nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00771 
00772   QStringList tagids;
00773   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00774   {
00775     tagids << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
00776   }
00777 
00778   sqlite3_finalize( ppStmt );
00779 
00780 
00781   QString dummy = tagids.join( ", " );
00782 
00783   query = sqlite3_mprintf( "SELECT symbol_id FROM tagmap WHERE tag_id IN (%q)", dummy.toUtf8().constData() );
00784   nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00785 
00786   QStringList symbolids;
00787   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00788   {
00789     symbolids << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
00790   }
00791 
00792   sqlite3_finalize( ppStmt );
00793 
00794 
00795   dummy = symbolids.join( ", " );
00796   query = sqlite3_mprintf( "SELECT name FROM symbol WHERE id IN (%q)", dummy.toUtf8().constData() );
00797   nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00798   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00799   {
00800     QString symbolName = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
00801     if ( !symbols.contains( symbolName ) )
00802       symbols << symbolName;
00803   }
00804 
00805   sqlite3_finalize( ppStmt );
00806 
00807   return symbols;
00808 }
00809 
00810 bool QgsStyleV2::tagSymbol( StyleEntity type, QString symbol, QStringList tags )
00811 {
00812   if ( !mCurrentDB )
00813   {
00814     QgsDebugMsg( "Sorry! Cannot open database to tag." );
00815     return false;
00816   }
00817 
00818   int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol );
00819   if ( !symbolid )
00820   {
00821     QgsDebugMsg( "No such symbol for tagging in database: " + symbol );
00822     return false;
00823   }
00824 
00825 
00826   foreach ( const QString &tag, tags )
00827   {
00828     // sql: gets the id of the tag if present or insert the tag and get the id of the tag
00829     char *query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
00830 
00831     sqlite3_stmt *ppStmt;
00832     int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00833 
00834     int tagid;
00835     if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00836     {
00837       tagid = sqlite3_column_int( ppStmt, 0 );
00838     }
00839     else
00840     {
00841       tagid = addTag( tag );
00842     }
00843 
00844     sqlite3_finalize( ppStmt );
00845 
00846     // Now map the tag to the symbol
00847     query = type == SymbolEntity
00848             ? sqlite3_mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
00849             : sqlite3_mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );
00850 
00851     char *zErr = 0;
00852     nErr = sqlite3_exec( mCurrentDB, query, NULL, NULL, &zErr );
00853     if ( nErr )
00854     {
00855       QgsDebugMsg( zErr );
00856     }
00857   }
00858 
00859   return true;
00860 }
00861 
00862 bool QgsStyleV2::detagSymbol( StyleEntity type, QString symbol, QStringList tags )
00863 {
00864   if ( !mCurrentDB )
00865   {
00866     QgsDebugMsg( "Sorry! Cannot open database for detgging." );
00867     return false;
00868   }
00869 
00870   char *query = type == SymbolEntity
00871                 ? sqlite3_mprintf( "SELECT id FROM symbol WHERE name='%q'", symbol.toUtf8().constData() )
00872                 : sqlite3_mprintf( "SELECT id FROM colorramp WHERE name='%q'", symbol.toUtf8().constData() );
00873   sqlite3_stmt *ppStmt;
00874   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00875 
00876   int symbolid = 0;
00877   if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00878   {
00879     symbolid = sqlite3_column_int( ppStmt, 0 );
00880   }
00881 
00882   sqlite3_finalize( ppStmt );
00883 
00884   foreach ( const QString &tag, tags )
00885   {
00886     query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
00887 
00888     sqlite3_stmt *ppStmt2;
00889     nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt2, NULL );
00890 
00891     int tagid = 0;
00892     if ( nErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
00893     {
00894       tagid = sqlite3_column_int( ppStmt2, 0 );
00895     }
00896 
00897     sqlite3_finalize( ppStmt2 );
00898 
00899     if ( tagid )
00900     {
00901       // remove from the tagmap
00902       query = type == SymbolEntity
00903               ? sqlite3_mprintf( "DELETE FROM tagmap WHERE tag_id=%d AND symbol_id=%d", tagid, symbolid )
00904               : sqlite3_mprintf( "DELETE FROM ctagmap WHERE tag_id=%d AND colorramp_id=%d", tagid, symbolid );
00905       runEmptyQuery( query );
00906     }
00907   }
00908 
00909   // TODO Perform tag cleanup
00910   // check the number of entries for a given tag in the tagmap
00911   // if the count is 0, then remove( TagEntity, tagid )
00912   return true;
00913 }
00914 
00915 QStringList QgsStyleV2::tagsOfSymbol( StyleEntity type, QString symbol )
00916 {
00917   if ( !mCurrentDB )
00918   {
00919     QgsDebugMsg( "Sorry! Cannot open database for getting the tags." );
00920     return QStringList();
00921   }
00922 
00923   int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol );
00924   if ( !symbolid )
00925     return QStringList();
00926 
00927   // get the ids of tags for the symbol
00928   char *query = type == SymbolEntity
00929                 ? sqlite3_mprintf( "SELECT tag_id FROM tagmap WHERE symbol_id=%d", symbolid )
00930                 : sqlite3_mprintf( "SELECT tag_id FROM ctagmap WHERE colorramp_id=%d", symbolid );
00931 
00932   sqlite3_stmt *ppStmt;
00933   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00934 
00935   QStringList tagList;
00936   while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00937   {
00938     char *subquery = sqlite3_mprintf( "SELECT name FROM tag WHERE id=%d", sqlite3_column_int( ppStmt, 0 ) );
00939 
00940     sqlite3_stmt *ppStmt2;
00941     int pErr = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt2, NULL );
00942     if ( pErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
00943     {
00944       tagList << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt2, 0 ) );
00945     }
00946     sqlite3_finalize( ppStmt2 );
00947   }
00948 
00949   sqlite3_finalize( ppStmt );
00950 
00951   return tagList;
00952 }
00953 
00954 int QgsStyleV2::getId( QString table, QString name )
00955 {
00956   char *query = sqlite3_mprintf( "SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() );
00957 
00958   sqlite3_stmt *ppStmt;
00959   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
00960 
00961   int id = 0;
00962   if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
00963   {
00964     id = sqlite3_column_int( ppStmt, 0 );
00965   }
00966 
00967   sqlite3_finalize( ppStmt );
00968 
00969   return id;
00970 }
00971 
00972 int QgsStyleV2::symbolId( QString name )
00973 {
00974   return getId( "symbol", name );
00975 }
00976 
00977 int QgsStyleV2::colorrampId( QString name )
00978 {
00979   return getId( "colorramp", name );
00980 }
00981 
00982 int QgsStyleV2::groupId( QString name )
00983 {
00984   return getId( "symgroup", name );
00985 }
00986 
00987 int QgsStyleV2::tagId( QString name )
00988 {
00989   return getId( "tag", name );
00990 }
00991 
00992 int QgsStyleV2::smartgroupId( QString name )
00993 {
00994   return getId( "smartgroup", name );
00995 }
00996 
00997 int QgsStyleV2::addSmartgroup( QString name, QString op, QgsSmartConditionMap conditions )
00998 {
00999   QDomDocument doc( "dummy" );
01000   QDomElement smartEl = doc.createElement( "smartgroup" );
01001   smartEl.setAttribute( "name", name );
01002   smartEl.setAttribute( "operator", op );
01003 
01004   QStringList constraints;
01005   constraints << "tag" << "group" << "name" << "!tag" << "!group" << "!name";
01006 
01007   foreach ( const QString &constraint, constraints )
01008   {
01009     QStringList parameters = conditions.values( constraint );
01010     foreach ( const QString &param, parameters )
01011     {
01012       QDomElement condEl = doc.createElement( "condition" );
01013       condEl.setAttribute( "constraint", constraint );
01014       condEl.setAttribute( "param", param );
01015       smartEl.appendChild( condEl );
01016     }
01017   }
01018 
01019   QByteArray xmlArray;
01020   QTextStream stream( &xmlArray );
01021   smartEl.save( stream, 4 );
01022   char *query = sqlite3_mprintf( "INSERT INTO smartgroup VALUES (NULL, '%q', '%q')",
01023                                  name.toUtf8().constData(), xmlArray.constData() );
01024 
01025   if ( runEmptyQuery( query ) )
01026   {
01027     return ( int )sqlite3_last_insert_rowid( mCurrentDB );
01028   }
01029   else
01030   {
01031     QgsDebugMsg( "Couldn't insert symbol into the database!" );
01032     return 0;
01033   }
01034 }
01035 
01036 QgsSymbolGroupMap QgsStyleV2::smartgroupsListMap()
01037 {
01038   if ( !mCurrentDB )
01039   {
01040     QgsDebugMsg( "Cannot open database for listing groups" );
01041     return QgsSymbolGroupMap();
01042   }
01043 
01044   char *query = sqlite3_mprintf( "SELECT * FROM smartgroup" );
01045 
01046   // Now run the query and retrieve the group names
01047   sqlite3_stmt *ppStmt;
01048   int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
01049 
01050   QgsSymbolGroupMap groupNames;
01051   while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
01052   {
01053     QString group = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SmartgroupName ) );
01054     groupNames.insert( sqlite3_column_int( ppStmt, SmartgroupId ), group );
01055   }
01056 
01057   sqlite3_finalize( ppStmt );
01058 
01059   return groupNames;
01060 }
01061 
01062 QStringList QgsStyleV2::smartgroupNames()
01063 {
01064   if ( !mCurrentDB )
01065   {
01066     QgsDebugMsg( "Cannot open database for listing groups" );
01067     return QStringList();
01068   }
01069 
01070   char *query = sqlite3_mprintf( "SELECT name FROM smartgroup" );
01071 
01072   // Now run the query and retrieve the group names
01073   sqlite3_stmt *ppStmt;
01074   int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
01075 
01076   QStringList groups;
01077   while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
01078   {
01079     groups << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
01080   }
01081 
01082   sqlite3_finalize( ppStmt );
01083 
01084   return groups;
01085 }
01086 
01087 QStringList QgsStyleV2::symbolsOfSmartgroup( StyleEntity type, int id )
01088 {
01089   QStringList symbols;
01090 
01091   char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
01092 
01093   sqlite3_stmt *ppStmt;
01094   int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
01095   if ( !( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) )
01096   {
01097     sqlite3_finalize( ppStmt );
01098     return QStringList();
01099   }
01100   else
01101   {
01102     QDomDocument doc;
01103     QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
01104     if ( !doc.setContent( xmlstr ) )
01105     {
01106       QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
01107     }
01108     QDomElement smartEl = doc.documentElement();
01109     QString op = smartEl.attribute( "operator" );
01110     QDomNodeList conditionNodes = smartEl.childNodes();
01111 
01112     bool firstSet = true;
01113     for ( int i = 0; i < conditionNodes.count(); i++ )
01114     {
01115       QDomElement condEl = conditionNodes.at( i ).toElement();
01116       QString constraint = condEl.attribute( "constraint" );
01117       QString param = condEl.attribute( "param" );
01118 
01119       QStringList resultNames;
01120       // perform suitable action for the given constraint
01121       if ( constraint == "tag" )
01122       {
01123         resultNames = symbolsWithTag( type, tagId( param ) );
01124       }
01125       else if ( constraint == "group" )
01126       {
01127         // XXX Validating group id might be a good idea here
01128         resultNames = symbolsOfGroup( type, groupId( param ) );
01129 
01130       }
01131       else if ( constraint == "name" )
01132       {
01133         if ( type == SymbolEntity )
01134         {
01135           resultNames = symbolNames().filter( param, Qt::CaseInsensitive );
01136         }
01137         else
01138         {
01139           resultNames = colorRampNames().filter( param, Qt::CaseInsensitive );
01140         }
01141       }
01142       else if ( constraint == "!tag" )
01143       {
01144         resultNames = type == SymbolEntity ? symbolNames() : colorRampNames();
01145         QStringList unwanted = symbolsWithTag( type, tagId( param ) );
01146         foreach ( QString name, unwanted )
01147         {
01148           resultNames.removeAll( name );
01149         }
01150       }
01151       else if ( constraint == "!group" )
01152       {
01153         resultNames = type == SymbolEntity ? symbolNames() : colorRampNames();
01154         QStringList unwanted = symbolsOfGroup( type, groupId( param ) );
01155         foreach ( QString name, unwanted )
01156         {
01157           resultNames.removeAll( name );
01158         }
01159       }
01160       else if ( constraint == "!name" )
01161       {
01162         QStringList all = type == SymbolEntity ? symbolNames() : colorRampNames() ;
01163         foreach ( const QString &str, all )
01164         {
01165           if ( !str.contains( param, Qt::CaseInsensitive ) )
01166             resultNames << str;
01167         }
01168       }
01169 
01170       // not apply the operator
01171       if ( firstSet )
01172       {
01173         symbols = resultNames;
01174         firstSet = false;
01175       }
01176       else
01177       {
01178         if ( op == "OR" )
01179         {
01180           symbols << resultNames;
01181         }
01182         else if ( op == "AND" )
01183         {
01184           QStringList dummy = symbols;
01185           symbols.clear();
01186           foreach ( const QString &result, resultNames )
01187           {
01188             if ( dummy.contains( result ) )
01189               symbols << result;
01190           }
01191         }
01192       }
01193     } // DOM loop ends here
01194   }
01195 
01196   sqlite3_finalize( ppStmt );
01197 
01198   return symbols;
01199 }
01200 
01201 QgsSmartConditionMap QgsStyleV2::smartgroup( int id )
01202 {
01203   if ( !mCurrentDB )
01204   {
01205     QgsDebugMsg( "Cannot open database for listing groups" );
01206     return QgsSmartConditionMap();
01207   }
01208 
01209   QgsSmartConditionMap condition;
01210 
01211   char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
01212 
01213   sqlite3_stmt *ppStmt;
01214   int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
01215   if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
01216   {
01217     QDomDocument doc;
01218     QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
01219     if ( !doc.setContent( xmlstr ) )
01220     {
01221       QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
01222     }
01223 
01224     QDomElement smartEl = doc.documentElement();
01225     QString op = smartEl.attribute( "operator" );
01226     QDomNodeList conditionNodes = smartEl.childNodes();
01227 
01228     for ( int i = 0; i < conditionNodes.count(); i++ )
01229     {
01230       QDomElement condEl = conditionNodes.at( i ).toElement();
01231       QString constraint = condEl.attribute( "constraint" );
01232       QString param = condEl.attribute( "param" );
01233 
01234       condition.insert( constraint, param );
01235     }
01236   }
01237 
01238   sqlite3_finalize( ppStmt );
01239 
01240   return condition;
01241 }
01242 
01243 QString QgsStyleV2::smartgroupOperator( int id )
01244 {
01245   if ( !mCurrentDB )
01246   {
01247     QgsDebugMsg( "Cannot open database for listing groups" );
01248     return QString();
01249   }
01250 
01251   QString op;
01252 
01253   char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
01254 
01255   sqlite3_stmt *ppStmt;
01256   int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
01257   if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
01258   {
01259     QDomDocument doc;
01260     QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
01261     if ( !doc.setContent( xmlstr ) )
01262     {
01263       QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
01264     }
01265     QDomElement smartEl = doc.documentElement();
01266     op = smartEl.attribute( "operator" );
01267   }
01268 
01269   sqlite3_finalize( ppStmt );
01270 
01271   return op;
01272 }
01273 
01274 bool QgsStyleV2::exportXML( QString filename )
01275 {
01276   if ( filename.isEmpty() )
01277   {
01278     QgsDebugMsg( "Invalid filename for style export." );
01279     return false;
01280   }
01281 
01282   QDomDocument doc( "qgis_style" );
01283   QDomElement root = doc.createElement( "qgis_style" );
01284   root.setAttribute( "version", STYLE_CURRENT_VERSION );
01285   doc.appendChild( root );
01286 
01287   // TODO work on the groups and tags
01288   QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( mSymbols, "symbols", doc );
01289   QDomElement rampsElem = doc.createElement( "colorramps" );
01290 
01291   // save color ramps
01292   for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
01293   {
01294     QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( itr.key(), itr.value(), doc );
01295     rampsElem.appendChild( rampEl );
01296   }
01297 
01298   root.appendChild( symbolsElem );
01299   root.appendChild( rampsElem );
01300 
01301   // save
01302   QFile f( filename );
01303   if ( !f.open( QFile::WriteOnly ) )
01304   {
01305     mErrorString = "Couldn't open file for writing: " + filename;
01306     return false;
01307   }
01308 
01309   QTextStream ts( &f );
01310   doc.save( ts, 2 );
01311   f.close();
01312 
01313   mFileName = filename;
01314   return true;
01315 }
01316 
01317 bool QgsStyleV2::importXML( QString filename )
01318 {
01319   mErrorString = QString();
01320   QDomDocument doc( "style" );
01321   QFile f( filename );
01322   if ( !f.open( QFile::ReadOnly ) )
01323   {
01324     mErrorString = "Unable to open the specified file";
01325     QgsDebugMsg( "Error opening the style XML file." );
01326     return false;
01327   }
01328 
01329   if ( !doc.setContent( &f ) )
01330   {
01331     mErrorString = QString( "Unable to understand the style file: %1" ).arg( filename );
01332     QgsDebugMsg( "XML Parsing error" );
01333     f.close();
01334     return false;
01335   }
01336   f.close();
01337 
01338   QDomElement docEl = doc.documentElement();
01339   if ( docEl.tagName() != "qgis_style" )
01340   {
01341     mErrorString = "Incorrect root tag in style: " + docEl.tagName();
01342     return false;
01343   }
01344 
01345   QString version = docEl.attribute( "version" );
01346   if ( version != STYLE_CURRENT_VERSION && version != "0" )
01347   {
01348     mErrorString = "Unknown style file version: " + version;
01349     return false;
01350   }
01351 
01352   QgsSymbolV2Map symbols;
01353 
01354   QDomElement symbolsElement = docEl.firstChildElement( "symbols" );
01355   QDomElement e = symbolsElement.firstChildElement();
01356 
01357   if ( version == STYLE_CURRENT_VERSION )
01358   {
01359     // For the new style, load symbols individualy
01360     while ( !e.isNull() )
01361     {
01362       if ( e.tagName() == "symbol" )
01363       {
01364         QgsSymbolV2* symbol = QgsSymbolLayerV2Utils::loadSymbol( e );
01365         if ( symbol )
01366         {
01367           symbols.insert( e.attribute( "name" ), symbol );
01368         }
01369       }
01370       else
01371       {
01372         QgsDebugMsg( "unknown tag: " + e.tagName() );
01373       }
01374       e = e.nextSiblingElement();
01375     }
01376   }
01377   else
01378   {
01379     // for the old version, use the utility function to solve @symbol@layer subsymbols
01380     symbols = QgsSymbolLayerV2Utils::loadSymbols( symbolsElement );
01381   }
01382 
01383   // save the symbols with proper name
01384   for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); it++ )
01385   {
01386     addSymbol( it.key(), it.value() );
01387   }
01388 
01389   // load color ramps
01390   QDomElement rampsElement = docEl.firstChildElement( "colorramps" );
01391   e = rampsElement.firstChildElement();
01392   while ( !e.isNull() )
01393   {
01394     if ( e.tagName() == "colorramp" )
01395     {
01396       QgsVectorColorRampV2* ramp = QgsSymbolLayerV2Utils::loadColorRamp( e );
01397       if ( ramp )
01398       {
01399         addColorRamp( e.attribute( "name" ), ramp );
01400       }
01401     }
01402     else
01403     {
01404       QgsDebugMsg( "unknown tag: " + e.tagName() );
01405     }
01406     e = e.nextSiblingElement();
01407   }
01408 
01409   mFileName = filename;
01410   return true;
01411 }
01412 
01413 bool QgsStyleV2::updateSymbol( StyleEntity type, QString name )
01414 {
01415   QDomDocument doc( "dummy" );
01416   QDomElement symEl;
01417   QByteArray xmlArray;
01418   QTextStream stream( &xmlArray );
01419 
01420   char *query;
01421 
01422   if ( type == SymbolEntity )
01423   {
01424     // check if it is an existing symbol
01425     if ( !symbolNames().contains( name ) )
01426     {
01427       QgsDebugMsg( "Update request received for unavailable symbol" );
01428       return false;
01429     }
01430 
01431     symEl = QgsSymbolLayerV2Utils::saveSymbol( name, symbol( name ), doc );
01432     if ( symEl.isNull() )
01433     {
01434       QgsDebugMsg( "Couldn't convert symbol to valid XML!" );
01435       return false;
01436     }
01437     symEl.save( stream, 4 );
01438     query = sqlite3_mprintf( "UPDATE symbol SET xml='%q' WHERE name='%q';",
01439                              xmlArray.constData(), name.toUtf8().constData() );
01440   }
01441   else if ( type == ColorrampEntity )
01442   {
01443     if ( !colorRampNames().contains( name ) )
01444     {
01445       QgsDebugMsg( "Update requested for unavailable color ramp." );
01446       return false;
01447     }
01448 
01449     symEl = QgsSymbolLayerV2Utils::saveColorRamp( name, colorRamp( name ), doc );
01450     if ( symEl.isNull() )
01451     {
01452       QgsDebugMsg( "Couldn't convert color ramp to valid XML!" );
01453       return false;
01454     }
01455     symEl.save( stream, 4 );
01456     query = sqlite3_mprintf( "UPDATE colorramp SET xml='%q' WHERE name='%q';",
01457                              xmlArray.constData(), name.toUtf8().constData() );
01458   }
01459   else
01460   {
01461     QgsDebugMsg( "Updating the unsupported StyleEntity" );
01462     return false;
01463   }
01464 
01465 
01466   if ( !runEmptyQuery( query ) )
01467   {
01468     QgsDebugMsg( "Couldn't insert symbol into the database!" );
01469     return false;
01470   }
01471   return true;
01472 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines