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