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