QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsstylev2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsstylev2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsstylev2.h"
17 
18 #include "qgssymbolv2.h"
19 #include "qgsvectorcolorrampv2.h"
20 
22 
23 #include "qgsapplication.h"
24 #include "qgslogger.h"
25 
26 #include <QDomDocument>
27 #include <QDomElement>
28 #include <QDomNode>
29 #include <QDomNodeList>
30 #include <QFile>
31 #include <QTextStream>
32 #include <QByteArray>
33 
34 #include <sqlite3.h>
35 
36 #define STYLE_CURRENT_VERSION "1"
37 
39 
40 
42 {
43  mCurrentDB = 0;
44 }
45 
47 {
48  clear();
49 }
50 
52 {
53  if ( !mDefaultStyle )
54  {
55  QString styleFilename = QgsApplication::userStyleV2Path();
56 
57  // copy default style if user style doesn't exist
58  if ( !QFile::exists( styleFilename ) )
59  {
60  QFile::copy( QgsApplication::defaultStyleV2Path(), styleFilename );
61  }
62 
64  mDefaultStyle->load( styleFilename );
65  }
66  return mDefaultStyle;
67 }
68 
69 
71 {
72  for ( QMap<QString, QgsSymbolV2*>::iterator its = mSymbols.begin(); its != mSymbols.end(); ++its )
73  delete its.value();
74  for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
75  delete itr.value();
76 
77  mSymbols.clear();
78  mColorRamps.clear();
79  if ( mCurrentDB )
80  sqlite3_close( mCurrentDB );
81 }
82 
83 bool QgsStyleV2::addSymbol( QString name, QgsSymbolV2* symbol, bool update )
84 {
85  if ( !symbol || name.isEmpty() )
86  return false;
87 
88  // delete previous symbol (if any)
89  if ( mSymbols.contains( name ) )
90  {
91  // TODO remove groups and tags?
92  delete mSymbols.value( name );
93  mSymbols.insert( name, symbol );
94  if ( update )
95  updateSymbol( SymbolEntity, name );
96  }
97  else
98  {
99  mSymbols.insert( name, symbol );
100  if ( update )
101  saveSymbol( name, symbol, 0, QStringList() );
102  }
103 
104  return true;
105 }
106 
107 bool QgsStyleV2::saveSymbol( QString name, QgsSymbolV2* symbol, int groupid, QStringList tags )
108 {
109  // TODO add support for tags and groups
110  Q_UNUSED( tags );
111 
112  QDomDocument doc( "dummy" );
113  QDomElement symEl = QgsSymbolLayerV2Utils::saveSymbol( name, symbol, doc );
114  if ( symEl.isNull() )
115  {
116  QgsDebugMsg( "Couldn't convert symbol to valid XML!" );
117  return false;
118  }
119 
120  QByteArray xmlArray;
121  QTextStream stream( &xmlArray );
122  symEl.save( stream, 4 );
123  char *query = sqlite3_mprintf( "INSERT INTO symbol VALUES (NULL, '%q', '%q', %d);",
124  name.toUtf8().constData(), xmlArray.constData(), groupid );
125 
126  if ( !runEmptyQuery( query ) )
127  {
128  QgsDebugMsg( "Couldn't insert symbol into the database!" );
129  return false;
130  }
131 
132  return true;
133 }
134 
135 bool QgsStyleV2::removeSymbol( QString name )
136 {
137  QgsSymbolV2 *symbol = mSymbols.take( name );
138  if ( !symbol )
139  return false;
140 
141  // remove from map and delete
142  delete symbol;
143 
144  // TODO
145  // Simplify this work here, its STUPID to run two DB queries for the sake of remove()
146  if ( !mCurrentDB )
147  {
148  QgsDebugMsg( "Sorry! Cannot open database to tag." );
149  return false;
150  }
151 
152  int symbolid = symbolId( name );
153  if ( !symbolid )
154  {
155  QgsDebugMsg( "No such symbol for deleting in database: " + name + ". Cheers." );
156  }
157 
158  remove( SymbolEntity, symbolid );
159 
160  return true;
161 }
162 
164 {
165  const QgsSymbolV2 *symbol = symbolRef( name );
166  return symbol ? symbol->clone() : 0;
167 }
168 
169 const QgsSymbolV2 *QgsStyleV2::symbolRef( QString name ) const
170 {
171  return mSymbols.value( name );
172 }
173 
175 {
176  return mSymbols.count();
177 }
178 
180 {
181  return mSymbols.keys();
182 }
183 
184 
185 bool QgsStyleV2::addColorRamp( QString name, QgsVectorColorRampV2* colorRamp, bool update )
186 {
187  if ( !colorRamp || name.isEmpty() )
188  return false;
189 
190  // delete previous color ramps (if any)
191  if ( mColorRamps.contains( name ) )
192  {
193  // TODO remove groups and tags?
194  delete mColorRamps.value( name );
195  mColorRamps.insert( name, colorRamp );
196  if ( update )
197  updateSymbol( ColorrampEntity, name );
198  }
199  else
200  {
201  mColorRamps.insert( name, colorRamp );
202  if ( update )
203  saveColorRamp( name, colorRamp, 0, QStringList() );
204  }
205 
206  return true;
207 }
208 
209 bool QgsStyleV2::saveColorRamp( QString name, QgsVectorColorRampV2* ramp, int groupid, QStringList tags )
210 {
211  // TODO add support for groups and tags
212  Q_UNUSED( tags );
213 
214  // insert it into the database
215  QDomDocument doc( "dummy" );
216  QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( name, ramp, doc );
217  if ( rampEl.isNull() )
218  {
219  QgsDebugMsg( "Couldn't convert color ramp to valid XML!" );
220  return false;
221  }
222 
223  QByteArray xmlArray;
224  QTextStream stream( &xmlArray );
225  rampEl.save( stream, 4 );
226  char *query = sqlite3_mprintf( "INSERT INTO colorramp VALUES (NULL, '%q', '%q', %d);",
227  name.toUtf8().constData(), xmlArray.constData(), groupid );
228 
229  if ( !runEmptyQuery( query ) )
230  {
231  QgsDebugMsg( "Couldn't insert colorramp into the database!" );
232  return false;
233  }
234 
235  return true;
236 }
237 
238 bool QgsStyleV2::removeColorRamp( QString name )
239 {
240  QgsVectorColorRampV2 *ramp = mColorRamps.take( name );
241  if ( !ramp )
242  return false;
243 
244  char *query = sqlite3_mprintf( "DELETE FROM colorramp WHERE name='%q'", name.toUtf8().constData() );
245  if ( !runEmptyQuery( query ) )
246  {
247  QgsDebugMsg( "Couldn't remove color ramp from the database." );
248  return false;
249  }
250 
251  delete ramp;
252 
253  return true;
254 }
255 
257 {
258  const QgsVectorColorRampV2 *ramp = colorRampRef( name );
259  return ramp ? ramp->clone() : 0;
260 }
261 
262 const QgsVectorColorRampV2* QgsStyleV2::colorRampRef( QString name ) const
263 {
264  return mColorRamps.value( name );
265 }
266 
268 {
269  return mColorRamps.count();
270 }
271 
273 {
274  return mColorRamps.keys();
275 }
276 
277 bool QgsStyleV2::openDB( QString filename )
278 {
279  int rc = sqlite3_open( filename.toUtf8(), &mCurrentDB );
280  if ( rc )
281  {
282  mErrorString = "Couldn't open the style database: " + QString( sqlite3_errmsg( mCurrentDB ) );
283  sqlite3_close( mCurrentDB );
284  return false;
285  }
286 
287  return true;
288 }
289 
290 bool QgsStyleV2::load( QString filename )
291 {
292  mErrorString.clear();
293 
294  // Open the sqlite database
295  if ( !openDB( filename ) )
296  {
297  mErrorString = "Unable to open database file specified";
299  return false;
300  }
301 
302  // Make sure there are no Null fields in parenting symbols ang groups
303  char *query = sqlite3_mprintf( "UPDATE symbol SET groupid=0 WHERE groupid IS NULL;"
304  "UPDATE colorramp SET groupid=0 WHERE groupid IS NULL;"
305  "UPDATE symgroup SET parent=0 WHERE parent IS NULL;" );
306  runEmptyQuery( query );
307 
308  // First create all the main symbols
309  query = sqlite3_mprintf( "SELECT * FROM symbol" );
310 
311  sqlite3_stmt *ppStmt;
312  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
313  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
314  {
315  QDomDocument doc;
316  QString symbol_name = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymbolName ) );
317  QString xmlstring = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymbolXML ) );
318  if ( !doc.setContent( xmlstring ) )
319  {
320  QgsDebugMsg( "Cannot open symbol " + symbol_name );
321  continue;
322  }
323 
324  QDomElement symElement = doc.documentElement();
326  if ( symbol != NULL )
327  mSymbols.insert( symbol_name, symbol );
328  }
329 
330  sqlite3_finalize( ppStmt );
331 
332  query = sqlite3_mprintf( "SELECT * FROM colorramp" );
333  nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
334  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
335  {
336  QDomDocument doc;
337  QString ramp_name = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, ColorrampName ) );
338  QString xmlstring = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, ColorrampXML ) );
339  if ( !doc.setContent( xmlstring ) )
340  {
341  QgsDebugMsg( "Cannot open symbol " + ramp_name );
342  continue;
343  }
344  QDomElement rampElement = doc.documentElement();
346  if ( ramp )
347  mColorRamps.insert( ramp_name, ramp );
348  }
349 
350  mFileName = filename;
351  return true;
352 }
353 
354 
355 
356 bool QgsStyleV2::save( QString filename )
357 {
358  mErrorString.clear();
359 
360  if ( filename.isEmpty() )
361  filename = mFileName;
362 
363  // TODO evaluate the requirement of this function and change implementation accordingly
364  // TODO remove QEXPECT_FAIL from TestStyleV2::testSaveLoad() when done
365 #if 0
366  QDomDocument doc( "qgis_style" );
367  QDomElement root = doc.createElement( "qgis_style" );
368  root.setAttribute( "version", STYLE_CURRENT_VERSION );
369  doc.appendChild( root );
370 
371  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( mSymbols, "symbols", doc );
372 
373  QDomElement rampsElem = doc.createElement( "colorramps" );
374 
375  // save color ramps
376  for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
377  {
378  QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( itr.key(), itr.value(), doc );
379  rampsElem.appendChild( rampEl );
380  }
381 
382  root.appendChild( symbolsElem );
383  root.appendChild( rampsElem );
384 
385  // save
386  QFile f( filename );
387  if ( !f.open( QFile::WriteOnly ) )
388  {
389  mErrorString = "Couldn't open file for writing: " + filename;
390  return false;
391  }
392  QTextStream ts( &f );
393  doc.save( ts, 2 );
394  f.close();
395 #endif
396 
397  mFileName = filename;
398  return true;
399 }
400 
401 bool QgsStyleV2::renameSymbol( QString oldName, QString newName )
402 {
403  QgsSymbolV2 *symbol = mSymbols.take( oldName );
404  if ( !symbol )
405  return false;
406 
407  mSymbols.insert( newName, symbol );
408 
409  if ( !mCurrentDB )
410  {
411  QgsDebugMsg( "Sorry! Cannot open database to tag." );
412  return false;
413  }
414 
415  int symbolid = symbolId( oldName );
416  if ( !symbolid )
417  {
418  QgsDebugMsg( "No such symbol for tagging in database: " + oldName );
419  return false;
420  }
421 
422  rename( SymbolEntity, symbolid, newName );
423 
424  return true;
425 }
426 
427 bool QgsStyleV2::renameColorRamp( QString oldName, QString newName )
428 {
429  QgsVectorColorRampV2 *ramp = mColorRamps.take( oldName );
430  if ( !ramp )
431  return false;
432 
433  mColorRamps.insert( newName, ramp );
434 
435  int rampid = 0;
436  sqlite3_stmt *ppStmt;
437  char *query = sqlite3_mprintf( "SELECT id FROM colorramp WHERE name='%q'", oldName.toUtf8().constData() );
438  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
439  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
440  {
441  rampid = sqlite3_column_int( ppStmt, 0 );
442  }
443  sqlite3_finalize( ppStmt );
444  rename( ColorrampEntity, rampid, newName );
445 
446  return true;
447 }
448 
450 {
451  QStringList groupNames;
452  sqlite3_stmt *ppStmt;
453  const char *query = "SELECT * FROM symgroup";
454  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
455  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
456  {
457  groupNames << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymgroupName ) );
458  }
459  sqlite3_finalize( ppStmt );
460  return groupNames;
461 }
462 
464 {
465  // get the name list from the sqlite database and return as a QStringList
466  if ( !mCurrentDB )
467  {
468  QgsDebugMsg( "Cannot open database for listing groups" );
469  return QgsSymbolGroupMap();
470  }
471 
472  char *query = 0;
473  int nError;
474  sqlite3_stmt *ppStmt;
475 
476  // decide the query to be run based on parent group
477  if ( parent == "" || parent == QString() )
478  {
479  query = sqlite3_mprintf( "SELECT * FROM symgroup WHERE parent=0" );
480  }
481  else
482  {
483  char *subquery = sqlite3_mprintf( "SELECT * FROM symgroup WHERE name='%q'", parent.toUtf8().constData() );
484  nError = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt, NULL );
485  if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
486  {
487  query = sqlite3_mprintf( "SELECT * FROM symgroup WHERE parent=%d", sqlite3_column_int( ppStmt, SymgroupId ) );
488  }
489  sqlite3_finalize( ppStmt );
490  }
491 
492  if ( !query )
493  return QgsSymbolGroupMap();
494 
496 
497  // Now run the query and retrieve the group names
498  nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
499  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
500  {
501  QString group = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SymgroupName ) );
502  groupNames.insert( sqlite3_column_int( ppStmt, SymgroupId ), group );
503  }
504 
505  sqlite3_finalize( ppStmt );
506 
507  return groupNames;
508 }
509 
510 QStringList QgsStyleV2::symbolsOfGroup( StyleEntity type, int groupid )
511 {
512  if ( !mCurrentDB )
513  {
514  QgsDebugMsg( QString( "Cannot Open database for getting group symbols of groupid: %1" ).arg( groupid ) );
515  return QStringList();
516  }
517 
518  char *query;
519  if ( type == SymbolEntity )
520  {
521  query = sqlite3_mprintf( "SELECT name FROM symbol WHERE groupid=%d", groupid );
522  }
523  else if ( type == ColorrampEntity )
524  {
525  query = sqlite3_mprintf( "SELECT name FROM colorramp WHERE groupid=%d", groupid );
526  }
527  else
528  {
529  QgsDebugMsg( "No such style entity" );
530  return QStringList();
531  }
532 
533  sqlite3_stmt *ppStmt;
534  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
535 
536  QStringList symbols;
537  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
538  {
539  symbols << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
540  }
541 
542  sqlite3_finalize( ppStmt );
543 
544  return symbols;
545 }
546 
547 QStringList QgsStyleV2::symbolsWithTag( StyleEntity type, int tagid )
548 {
549  if ( !mCurrentDB )
550  {
551  QgsDebugMsg( QString( "Cannot open database to get symbols of tagid %1" ).arg( tagid ) );
552  return QStringList();
553  }
554 
555  char *subquery;
556  if ( type == SymbolEntity )
557  {
558  subquery = sqlite3_mprintf( "SELECT symbol_id FROM tagmap WHERE tag_id=%d", tagid );
559  }
560  else if ( type == ColorrampEntity )
561  {
562  subquery = sqlite3_mprintf( "SELECT symbol_id FROM ctagmap WHERE tag_id=%d", tagid );
563  }
564  else
565  {
566  QgsDebugMsg( "Unknown Entity" );
567  return QStringList();
568  }
569 
570  sqlite3_stmt *ppStmt;
571  int nErr = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt, NULL );
572 
573  // get the symbol <-> tag connection from table 'tagmap'
574  QStringList symbols;
575  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
576  {
577  int symbolId = sqlite3_column_int( ppStmt, 0 );
578 
579  char *query = type == SymbolEntity
580  ? sqlite3_mprintf( "SELECT name FROM symbol WHERE id=%d", symbolId )
581  : sqlite3_mprintf( "SELECT name FROM colorramp WHERE id=%d", symbolId );
582 
583  sqlite3_stmt *ppStmt2;
584  int sErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt2, NULL );
585  while ( sErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
586  {
587  symbols << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt2, 0 ) );
588  }
589  sqlite3_finalize( ppStmt2 );
590  }
591  sqlite3_finalize( ppStmt );
592 
593  return symbols;
594 }
595 
596 int QgsStyleV2::addGroup( QString groupName, int parentid )
597 {
598  if ( !mCurrentDB )
599  return 0;
600 
601  char *query = sqlite3_mprintf( "INSERT INTO symgroup VALUES (NULL, '%q', %d)", groupName.toUtf8().constData(), parentid );
602 
603  sqlite3_stmt *ppStmt;
604  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
605  if ( nErr == SQLITE_OK )
606  sqlite3_step( ppStmt );
607 
608  sqlite3_finalize( ppStmt );
609 
610  return ( int )sqlite3_last_insert_rowid( mCurrentDB );
611 }
612 
613 int QgsStyleV2::addTag( QString tagname )
614 {
615  if ( !mCurrentDB )
616  return 0;
617  sqlite3_stmt *ppStmt;
618 
619  char *query = sqlite3_mprintf( "INSERT INTO tag VALUES (NULL, '%q')", tagname.toUtf8().constData() );
620  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
621  if ( nErr == SQLITE_OK )
622  sqlite3_step( ppStmt );
623  sqlite3_finalize( ppStmt );
624 
625  return ( int )sqlite3_last_insert_rowid( mCurrentDB );
626 }
627 
628 void QgsStyleV2::rename( StyleEntity type, int id, QString newName )
629 {
630  char *query;
631  switch ( type )
632  {
633  case SymbolEntity:
634  query = sqlite3_mprintf( "UPDATE symbol SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
635  break;
636  case GroupEntity:
637  query = sqlite3_mprintf( "UPDATE symgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
638  break;
639  case TagEntity:
640  query = sqlite3_mprintf( "UPDATE tag SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
641  break;
642  case ColorrampEntity:
643  query = sqlite3_mprintf( "UPDATE colorramp SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
644  break;
645  case SmartgroupEntity:
646  query = sqlite3_mprintf( "UPDATE smartgroup SET name='%q' WHERE id=%d", newName.toUtf8().constData(), id );
647  break;
648  default:
649  QgsDebugMsg( "Invalid Style Entity indicated" );
650  return;
651  }
652  if ( !runEmptyQuery( query ) )
653  mErrorString = "Could not rename!";
654 }
655 
657 {
658  char *query = sqlite3_mprintf( "SELECT parent FROM symgroup WHERE id=%d", id );
659 
660  sqlite3_stmt *ppStmt;
661  int err = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
662 
663  int parentid = 0;
664  if ( err == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
665  parentid = sqlite3_column_int( ppStmt, 0 );
666 
667  sqlite3_finalize( ppStmt );
668 
669  return sqlite3_mprintf( "UPDATE symbol SET groupid=%d WHERE groupid=%d;"
670  "UPDATE symgroup SET parent=%d WHERE parent=%d;"
671  "DELETE FROM symgroup WHERE id=%d", parentid, id, parentid, id, id );
672 }
673 
674 void QgsStyleV2::remove( StyleEntity type, int id )
675 {
676  char *query;
677  switch ( type )
678  {
679  case SymbolEntity:
680  query = sqlite3_mprintf( "DELETE FROM symbol WHERE id=%d; DELETE FROM tagmap WHERE symbol_id=%d", id, id );
681  break;
682  case GroupEntity:
683  query = getGroupRemoveQuery( id );
684  break;
685  case TagEntity:
686  query = sqlite3_mprintf( "DELETE FROM tag WHERE id=%d; DELETE FROM tagmap WHERE tag_id=%d", id, id );
687  break;
688  case ColorrampEntity:
689  query = sqlite3_mprintf( "DELETE FROM colorramp WHERE id=%d", id );
690  break;
691  case SmartgroupEntity:
692  query = sqlite3_mprintf( "DELETE FROM smartgroup WHERE id=%d", id );
693  break;
694  default:
695  QgsDebugMsg( "Invalid Style Entity indicated" );
696  return;
697  }
698 
699  if ( !runEmptyQuery( query ) )
700  {
701  QgsDebugMsg( "Could not delete entity!" );
702  }
703 }
704 
705 bool QgsStyleV2::runEmptyQuery( char *query, bool freeQuery )
706 {
707  if ( !mCurrentDB )
708  return false;
709 
710  char *zErr = 0;
711  int nErr = sqlite3_exec( mCurrentDB, query, NULL, NULL, &zErr );
712 
713  if ( freeQuery )
714  {
715  sqlite3_free( query );
716  }
717 
718  if ( nErr != SQLITE_OK )
719  {
720  QgsDebugMsg( zErr );
721  }
722 
723  return zErr == SQLITE_OK;
724 }
725 
726 bool QgsStyleV2::group( StyleEntity type, QString name, int groupid )
727 {
728  char *query;
729 
730  switch ( type )
731  {
732  case SymbolEntity:
733  query = sqlite3_mprintf( "UPDATE symbol SET groupid=%d WHERE name='%q'", groupid, name.toUtf8().constData() );
734  break;
735  case ColorrampEntity:
736  query = sqlite3_mprintf( "UPDATE colorramp SET groupid=%d WHERE name='%q'", groupid, name.toUtf8().constData() );
737  break;
738 
739  default:
740  QgsDebugMsg( "Wrong entity value. cannot apply group" );
741  return false;
742  }
743 
744  return runEmptyQuery( query );
745 }
746 
747 QStringList QgsStyleV2::findSymbols( StyleEntity type, QString qword )
748 {
749  if ( !mCurrentDB )
750  {
751  QgsDebugMsg( "Sorry! Cannot open database to search" );
752  return QStringList();
753  }
754 
755  QString item = ( type == SymbolEntity ) ? "symbol" : "colorramp";
756  char *query = sqlite3_mprintf( "SELECT name FROM %q WHERE xml LIKE '%%%q%%'",
757  item.toUtf8().constData(), qword.toUtf8().constData() );
758 
759  sqlite3_stmt *ppStmt;
760  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
761 
762  QStringList symbols;
763  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
764  {
765  symbols << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
766  }
767 
768  sqlite3_finalize( ppStmt );
769 
770  query = sqlite3_mprintf( "SELECT id FROM tag WHERE name LIKE '%%%q%%'", qword.toUtf8().constData() );
771  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
772 
773  QStringList tagids;
774  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
775  {
776  tagids << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
777  }
778 
779  sqlite3_finalize( ppStmt );
780 
781 
782  QString dummy = tagids.join( ", " );
783 
784  if ( type == SymbolEntity )
785  {
786  query = sqlite3_mprintf( "SELECT symbol_id FROM tagmap WHERE tag_id IN (%q)",
787  dummy.toUtf8().constData() );
788  }
789  else
790  {
791  query = sqlite3_mprintf( "SELECT colorramp_id FROM ctagmap WHERE tag_id IN (%q)",
792  dummy.toUtf8().constData() );
793  }
794  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
795 
796  QStringList symbolids;
797  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
798  {
799  symbolids << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
800  }
801 
802  sqlite3_finalize( ppStmt );
803 
804 
805  dummy = symbolids.join( ", " );
806  query = sqlite3_mprintf( "SELECT name FROM %q WHERE id IN (%q)",
807  item.toUtf8().constData(), dummy.toUtf8().constData() );
808  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
809  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
810  {
811  QString symbolName = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
812  if ( !symbols.contains( symbolName ) )
813  symbols << symbolName;
814  }
815 
816  sqlite3_finalize( ppStmt );
817 
818  return symbols;
819 }
820 
821 bool QgsStyleV2::tagSymbol( StyleEntity type, QString symbol, QStringList tags )
822 {
823  if ( !mCurrentDB )
824  {
825  QgsDebugMsg( "Sorry! Cannot open database to tag." );
826  return false;
827  }
828 
829  int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol );
830  if ( !symbolid )
831  {
832  QgsDebugMsg( "No such symbol for tagging in database: " + symbol );
833  return false;
834  }
835 
836 
837  foreach ( const QString &tag, tags )
838  {
839  // sql: gets the id of the tag if present or insert the tag and get the id of the tag
840  char *query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
841 
842  sqlite3_stmt *ppStmt;
843  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
844 
845  int tagid;
846  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
847  {
848  tagid = sqlite3_column_int( ppStmt, 0 );
849  }
850  else
851  {
852  tagid = addTag( tag );
853  }
854 
855  sqlite3_finalize( ppStmt );
856 
857  // Now map the tag to the symbol
858  query = type == SymbolEntity
859  ? sqlite3_mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
860  : sqlite3_mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );
861 
862  char *zErr = 0;
863  nErr = sqlite3_exec( mCurrentDB, query, NULL, NULL, &zErr );
864  if ( nErr )
865  {
866  QgsDebugMsg( zErr );
867  }
868  }
869 
870  return true;
871 }
872 
873 bool QgsStyleV2::detagSymbol( StyleEntity type, QString symbol, QStringList tags )
874 {
875  if ( !mCurrentDB )
876  {
877  QgsDebugMsg( "Sorry! Cannot open database for detgging." );
878  return false;
879  }
880 
881  char *query = type == SymbolEntity
882  ? sqlite3_mprintf( "SELECT id FROM symbol WHERE name='%q'", symbol.toUtf8().constData() )
883  : sqlite3_mprintf( "SELECT id FROM colorramp WHERE name='%q'", symbol.toUtf8().constData() );
884  sqlite3_stmt *ppStmt;
885  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
886 
887  int symbolid = 0;
888  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
889  {
890  symbolid = sqlite3_column_int( ppStmt, 0 );
891  }
892 
893  sqlite3_finalize( ppStmt );
894 
895  foreach ( const QString &tag, tags )
896  {
897  query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
898 
899  sqlite3_stmt *ppStmt2;
900  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt2, NULL );
901 
902  int tagid = 0;
903  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
904  {
905  tagid = sqlite3_column_int( ppStmt2, 0 );
906  }
907 
908  sqlite3_finalize( ppStmt2 );
909 
910  if ( tagid )
911  {
912  // remove from the tagmap
913  query = type == SymbolEntity
914  ? sqlite3_mprintf( "DELETE FROM tagmap WHERE tag_id=%d AND symbol_id=%d", tagid, symbolid )
915  : sqlite3_mprintf( "DELETE FROM ctagmap WHERE tag_id=%d AND colorramp_id=%d", tagid, symbolid );
916  runEmptyQuery( query );
917  }
918  }
919 
920  // TODO Perform tag cleanup
921  // check the number of entries for a given tag in the tagmap
922  // if the count is 0, then remove( TagEntity, tagid )
923  return true;
924 }
925 
926 QStringList QgsStyleV2::tagsOfSymbol( StyleEntity type, QString symbol )
927 {
928  if ( !mCurrentDB )
929  {
930  QgsDebugMsg( "Sorry! Cannot open database for getting the tags." );
931  return QStringList();
932  }
933 
934  int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol );
935  if ( !symbolid )
936  return QStringList();
937 
938  // get the ids of tags for the symbol
939  char *query = type == SymbolEntity
940  ? sqlite3_mprintf( "SELECT tag_id FROM tagmap WHERE symbol_id=%d", symbolid )
941  : sqlite3_mprintf( "SELECT tag_id FROM ctagmap WHERE colorramp_id=%d", symbolid );
942 
943  sqlite3_stmt *ppStmt;
944  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
945 
946  QStringList tagList;
947  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
948  {
949  char *subquery = sqlite3_mprintf( "SELECT name FROM tag WHERE id=%d", sqlite3_column_int( ppStmt, 0 ) );
950 
951  sqlite3_stmt *ppStmt2;
952  int pErr = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt2, NULL );
953  if ( pErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
954  {
955  tagList << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt2, 0 ) );
956  }
957  sqlite3_finalize( ppStmt2 );
958  }
959 
960  sqlite3_finalize( ppStmt );
961 
962  return tagList;
963 }
964 
965 int QgsStyleV2::getId( QString table, QString name )
966 {
967  char *query = sqlite3_mprintf( "SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() );
968 
969  sqlite3_stmt *ppStmt;
970  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
971 
972  int id = 0;
973  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
974  {
975  id = sqlite3_column_int( ppStmt, 0 );
976  }
977 
978  sqlite3_finalize( ppStmt );
979 
980  return id;
981 }
982 
983 int QgsStyleV2::symbolId( QString name )
984 {
985  return getId( "symbol", name );
986 }
987 
988 int QgsStyleV2::colorrampId( QString name )
989 {
990  return getId( "colorramp", name );
991 }
992 
993 int QgsStyleV2::groupId( QString name )
994 {
995  return getId( "symgroup", name );
996 }
997 
998 int QgsStyleV2::tagId( QString name )
999 {
1000  return getId( "tag", name );
1001 }
1002 
1003 int QgsStyleV2::smartgroupId( QString name )
1004 {
1005  return getId( "smartgroup", name );
1006 }
1007 
1008 int QgsStyleV2::addSmartgroup( QString name, QString op, QgsSmartConditionMap conditions )
1009 {
1010  QDomDocument doc( "dummy" );
1011  QDomElement smartEl = doc.createElement( "smartgroup" );
1012  smartEl.setAttribute( "name", name );
1013  smartEl.setAttribute( "operator", op );
1014 
1015  QStringList constraints;
1016  constraints << "tag" << "group" << "name" << "!tag" << "!group" << "!name";
1017 
1018  foreach ( const QString &constraint, constraints )
1019  {
1020  QStringList parameters = conditions.values( constraint );
1021  foreach ( const QString &param, parameters )
1022  {
1023  QDomElement condEl = doc.createElement( "condition" );
1024  condEl.setAttribute( "constraint", constraint );
1025  condEl.setAttribute( "param", param );
1026  smartEl.appendChild( condEl );
1027  }
1028  }
1029 
1030  QByteArray xmlArray;
1031  QTextStream stream( &xmlArray );
1032  smartEl.save( stream, 4 );
1033  char *query = sqlite3_mprintf( "INSERT INTO smartgroup VALUES (NULL, '%q', '%q')",
1034  name.toUtf8().constData(), xmlArray.constData() );
1035 
1036  if ( runEmptyQuery( query ) )
1037  {
1038  return ( int )sqlite3_last_insert_rowid( mCurrentDB );
1039  }
1040  else
1041  {
1042  QgsDebugMsg( "Couldn't insert symbol into the database!" );
1043  return 0;
1044  }
1045 }
1046 
1048 {
1049  if ( !mCurrentDB )
1050  {
1051  QgsDebugMsg( "Cannot open database for listing groups" );
1052  return QgsSymbolGroupMap();
1053  }
1054 
1055  char *query = sqlite3_mprintf( "SELECT * FROM smartgroup" );
1056 
1057  // Now run the query and retrieve the group names
1058  sqlite3_stmt *ppStmt;
1059  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1060 
1062  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1063  {
1064  QString group = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SmartgroupName ) );
1065  groupNames.insert( sqlite3_column_int( ppStmt, SmartgroupId ), group );
1066  }
1067 
1068  sqlite3_finalize( ppStmt );
1069 
1070  return groupNames;
1071 }
1072 
1074 {
1075  if ( !mCurrentDB )
1076  {
1077  QgsDebugMsg( "Cannot open database for listing groups" );
1078  return QStringList();
1079  }
1080 
1081  char *query = sqlite3_mprintf( "SELECT name FROM smartgroup" );
1082 
1083  // Now run the query and retrieve the group names
1084  sqlite3_stmt *ppStmt;
1085  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1086 
1087  QStringList groups;
1088  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1089  {
1090  groups << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1091  }
1092 
1093  sqlite3_finalize( ppStmt );
1094 
1095  return groups;
1096 }
1097 
1099 {
1100  QStringList symbols;
1101 
1102  char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
1103 
1104  sqlite3_stmt *ppStmt;
1105  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1106  if ( !( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) )
1107  {
1108  sqlite3_finalize( ppStmt );
1109  return QStringList();
1110  }
1111  else
1112  {
1113  QDomDocument doc;
1114  QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1115  if ( !doc.setContent( xmlstr ) )
1116  {
1117  QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
1118  }
1119  QDomElement smartEl = doc.documentElement();
1120  QString op = smartEl.attribute( "operator" );
1121  QDomNodeList conditionNodes = smartEl.childNodes();
1122 
1123  bool firstSet = true;
1124  for ( int i = 0; i < conditionNodes.count(); i++ )
1125  {
1126  QDomElement condEl = conditionNodes.at( i ).toElement();
1127  QString constraint = condEl.attribute( "constraint" );
1128  QString param = condEl.attribute( "param" );
1129 
1130  QStringList resultNames;
1131  // perform suitable action for the given constraint
1132  if ( constraint == "tag" )
1133  {
1134  resultNames = symbolsWithTag( type, tagId( param ) );
1135  }
1136  else if ( constraint == "group" )
1137  {
1138  // XXX Validating group id might be a good idea here
1139  resultNames = symbolsOfGroup( type, groupId( param ) );
1140 
1141  }
1142  else if ( constraint == "name" )
1143  {
1144  if ( type == SymbolEntity )
1145  {
1146  resultNames = symbolNames().filter( param, Qt::CaseInsensitive );
1147  }
1148  else
1149  {
1150  resultNames = colorRampNames().filter( param, Qt::CaseInsensitive );
1151  }
1152  }
1153  else if ( constraint == "!tag" )
1154  {
1155  resultNames = type == SymbolEntity ? symbolNames() : colorRampNames();
1156  QStringList unwanted = symbolsWithTag( type, tagId( param ) );
1157  foreach ( QString name, unwanted )
1158  {
1159  resultNames.removeAll( name );
1160  }
1161  }
1162  else if ( constraint == "!group" )
1163  {
1164  resultNames = type == SymbolEntity ? symbolNames() : colorRampNames();
1165  QStringList unwanted = symbolsOfGroup( type, groupId( param ) );
1166  foreach ( QString name, unwanted )
1167  {
1168  resultNames.removeAll( name );
1169  }
1170  }
1171  else if ( constraint == "!name" )
1172  {
1173  QStringList all = type == SymbolEntity ? symbolNames() : colorRampNames() ;
1174  foreach ( const QString &str, all )
1175  {
1176  if ( !str.contains( param, Qt::CaseInsensitive ) )
1177  resultNames << str;
1178  }
1179  }
1180 
1181  // not apply the operator
1182  if ( firstSet )
1183  {
1184  symbols = resultNames;
1185  firstSet = false;
1186  }
1187  else
1188  {
1189  if ( op == "OR" )
1190  {
1191  symbols << resultNames;
1192  }
1193  else if ( op == "AND" )
1194  {
1195  QStringList dummy = symbols;
1196  symbols.clear();
1197  foreach ( const QString &result, resultNames )
1198  {
1199  if ( dummy.contains( result ) )
1200  symbols << result;
1201  }
1202  }
1203  }
1204  } // DOM loop ends here
1205  }
1206 
1207  sqlite3_finalize( ppStmt );
1208 
1209  return symbols;
1210 }
1211 
1213 {
1214  if ( !mCurrentDB )
1215  {
1216  QgsDebugMsg( "Cannot open database for listing groups" );
1217  return QgsSmartConditionMap();
1218  }
1219 
1220  QgsSmartConditionMap condition;
1221 
1222  char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
1223 
1224  sqlite3_stmt *ppStmt;
1225  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1226  if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1227  {
1228  QDomDocument doc;
1229  QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1230  if ( !doc.setContent( xmlstr ) )
1231  {
1232  QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
1233  }
1234 
1235  QDomElement smartEl = doc.documentElement();
1236  QString op = smartEl.attribute( "operator" );
1237  QDomNodeList conditionNodes = smartEl.childNodes();
1238 
1239  for ( int i = 0; i < conditionNodes.count(); i++ )
1240  {
1241  QDomElement condEl = conditionNodes.at( i ).toElement();
1242  QString constraint = condEl.attribute( "constraint" );
1243  QString param = condEl.attribute( "param" );
1244 
1245  condition.insert( constraint, param );
1246  }
1247  }
1248 
1249  sqlite3_finalize( ppStmt );
1250 
1251  return condition;
1252 }
1253 
1255 {
1256  if ( !mCurrentDB )
1257  {
1258  QgsDebugMsg( "Cannot open database for listing groups" );
1259  return QString();
1260  }
1261 
1262  QString op;
1263 
1264  char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
1265 
1266  sqlite3_stmt *ppStmt;
1267  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1268  if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1269  {
1270  QDomDocument doc;
1271  QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1272  if ( !doc.setContent( xmlstr ) )
1273  {
1274  QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
1275  }
1276  QDomElement smartEl = doc.documentElement();
1277  op = smartEl.attribute( "operator" );
1278  }
1279 
1280  sqlite3_finalize( ppStmt );
1281 
1282  return op;
1283 }
1284 
1285 bool QgsStyleV2::exportXML( QString filename )
1286 {
1287  if ( filename.isEmpty() )
1288  {
1289  QgsDebugMsg( "Invalid filename for style export." );
1290  return false;
1291  }
1292 
1293  QDomDocument doc( "qgis_style" );
1294  QDomElement root = doc.createElement( "qgis_style" );
1295  root.setAttribute( "version", STYLE_CURRENT_VERSION );
1296  doc.appendChild( root );
1297 
1298  // TODO work on the groups and tags
1299  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( mSymbols, "symbols", doc );
1300  QDomElement rampsElem = doc.createElement( "colorramps" );
1301 
1302  // save color ramps
1303  for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
1304  {
1305  QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( itr.key(), itr.value(), doc );
1306  rampsElem.appendChild( rampEl );
1307  }
1308 
1309  root.appendChild( symbolsElem );
1310  root.appendChild( rampsElem );
1311 
1312  // save
1313  QFile f( filename );
1314  if ( !f.open( QFile::WriteOnly ) )
1315  {
1316  mErrorString = "Couldn't open file for writing: " + filename;
1317  return false;
1318  }
1319 
1320  QTextStream ts( &f );
1321  doc.save( ts, 2 );
1322  f.close();
1323 
1324  mFileName = filename;
1325  return true;
1326 }
1327 
1328 bool QgsStyleV2::importXML( QString filename )
1329 {
1330  mErrorString = QString();
1331  QDomDocument doc( "style" );
1332  QFile f( filename );
1333  if ( !f.open( QFile::ReadOnly ) )
1334  {
1335  mErrorString = "Unable to open the specified file";
1336  QgsDebugMsg( "Error opening the style XML file." );
1337  return false;
1338  }
1339 
1340  if ( !doc.setContent( &f ) )
1341  {
1342  mErrorString = QString( "Unable to understand the style file: %1" ).arg( filename );
1343  QgsDebugMsg( "XML Parsing error" );
1344  f.close();
1345  return false;
1346  }
1347  f.close();
1348 
1349  QDomElement docEl = doc.documentElement();
1350  if ( docEl.tagName() != "qgis_style" )
1351  {
1352  mErrorString = "Incorrect root tag in style: " + docEl.tagName();
1353  return false;
1354  }
1355 
1356  QString version = docEl.attribute( "version" );
1357  if ( version != STYLE_CURRENT_VERSION && version != "0" )
1358  {
1359  mErrorString = "Unknown style file version: " + version;
1360  return false;
1361  }
1362 
1363  QgsSymbolV2Map symbols;
1364 
1365  QDomElement symbolsElement = docEl.firstChildElement( "symbols" );
1366  QDomElement e = symbolsElement.firstChildElement();
1367 
1368  if ( version == STYLE_CURRENT_VERSION )
1369  {
1370  // For the new style, load symbols individualy
1371  while ( !e.isNull() )
1372  {
1373  if ( e.tagName() == "symbol" )
1374  {
1376  if ( symbol )
1377  {
1378  symbols.insert( e.attribute( "name" ), symbol );
1379  }
1380  }
1381  else
1382  {
1383  QgsDebugMsg( "unknown tag: " + e.tagName() );
1384  }
1385  e = e.nextSiblingElement();
1386  }
1387  }
1388  else
1389  {
1390  // for the old version, use the utility function to solve @symbol@layer subsymbols
1391  symbols = QgsSymbolLayerV2Utils::loadSymbols( symbolsElement );
1392  }
1393 
1394  // save the symbols with proper name
1395  for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); it++ )
1396  {
1397  addSymbol( it.key(), it.value() );
1398  }
1399 
1400  // load color ramps
1401  QDomElement rampsElement = docEl.firstChildElement( "colorramps" );
1402  e = rampsElement.firstChildElement();
1403  while ( !e.isNull() )
1404  {
1405  if ( e.tagName() == "colorramp" )
1406  {
1408  if ( ramp )
1409  {
1410  addColorRamp( e.attribute( "name" ), ramp );
1411  }
1412  }
1413  else
1414  {
1415  QgsDebugMsg( "unknown tag: " + e.tagName() );
1416  }
1417  e = e.nextSiblingElement();
1418  }
1419 
1420  mFileName = filename;
1421  return true;
1422 }
1423 
1424 bool QgsStyleV2::updateSymbol( StyleEntity type, QString name )
1425 {
1426  QDomDocument doc( "dummy" );
1427  QDomElement symEl;
1428  QByteArray xmlArray;
1429  QTextStream stream( &xmlArray );
1430 
1431  char *query;
1432 
1433  if ( type == SymbolEntity )
1434  {
1435  // check if it is an existing symbol
1436  if ( !symbolNames().contains( name ) )
1437  {
1438  QgsDebugMsg( "Update request received for unavailable symbol" );
1439  return false;
1440  }
1441 
1442  symEl = QgsSymbolLayerV2Utils::saveSymbol( name, symbol( name ), doc );
1443  if ( symEl.isNull() )
1444  {
1445  QgsDebugMsg( "Couldn't convert symbol to valid XML!" );
1446  return false;
1447  }
1448  symEl.save( stream, 4 );
1449  query = sqlite3_mprintf( "UPDATE symbol SET xml='%q' WHERE name='%q';",
1450  xmlArray.constData(), name.toUtf8().constData() );
1451  }
1452  else if ( type == ColorrampEntity )
1453  {
1454  if ( !colorRampNames().contains( name ) )
1455  {
1456  QgsDebugMsg( "Update requested for unavailable color ramp." );
1457  return false;
1458  }
1459 
1460  symEl = QgsSymbolLayerV2Utils::saveColorRamp( name, colorRamp( name ), doc );
1461  if ( symEl.isNull() )
1462  {
1463  QgsDebugMsg( "Couldn't convert color ramp to valid XML!" );
1464  return false;
1465  }
1466  symEl.save( stream, 4 );
1467  query = sqlite3_mprintf( "UPDATE colorramp SET xml='%q' WHERE name='%q';",
1468  xmlArray.constData(), name.toUtf8().constData() );
1469  }
1470  else
1471  {
1472  QgsDebugMsg( "Updating the unsupported StyleEntity" );
1473  return false;
1474  }
1475 
1476 
1477  if ( !runEmptyQuery( query ) )
1478  {
1479  QgsDebugMsg( "Couldn't insert symbol into the database!" );
1480  return false;
1481  }
1482  return true;
1483 }