QGIS API Documentation  2.8.2-Wien
 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 xml 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  query = sqlite3_mprintf( "SELECT id FROM tag WHERE name LIKE '%%%q%%'", qword.toUtf8().constData() );
788  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
789 
790  QStringList tagids;
791  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
792  {
793  tagids << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
794  }
795 
796  sqlite3_finalize( ppStmt );
797 
798 
799  QString dummy = tagids.join( ", " );
800 
801  if ( type == SymbolEntity )
802  {
803  query = sqlite3_mprintf( "SELECT symbol_id FROM tagmap WHERE tag_id IN (%q)",
804  dummy.toUtf8().constData() );
805  }
806  else
807  {
808  query = sqlite3_mprintf( "SELECT colorramp_id FROM ctagmap WHERE tag_id IN (%q)",
809  dummy.toUtf8().constData() );
810  }
811  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
812 
813  QStringList symbolids;
814  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
815  {
816  symbolids << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
817  }
818 
819  sqlite3_finalize( ppStmt );
820 
821 
822  dummy = symbolids.join( ", " );
823  query = sqlite3_mprintf( "SELECT name FROM %q WHERE id IN (%q)",
824  item.toUtf8().constData(), dummy.toUtf8().constData() );
825  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
826  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
827  {
828  QString symbolName = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
829  if ( !symbols.contains( symbolName ) )
830  symbols << symbolName;
831  }
832 
833  sqlite3_finalize( ppStmt );
834 
835  return symbols;
836 }
837 
838 bool QgsStyleV2::tagSymbol( StyleEntity type, QString symbol, QStringList tags )
839 {
840  if ( !mCurrentDB )
841  {
842  QgsDebugMsg( "Sorry! Cannot open database to tag." );
843  return false;
844  }
845 
846  int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol );
847  if ( !symbolid )
848  {
849  QgsDebugMsg( "No such symbol for tagging in database: " + symbol );
850  return false;
851  }
852 
853 
854  foreach ( const QString &tag, tags )
855  {
856  // sql: gets the id of the tag if present or insert the tag and get the id of the tag
857  char *query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
858 
859  sqlite3_stmt *ppStmt;
860  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
861 
862  int tagid;
863  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
864  {
865  tagid = sqlite3_column_int( ppStmt, 0 );
866  }
867  else
868  {
869  tagid = addTag( tag );
870  }
871 
872  sqlite3_finalize( ppStmt );
873 
874  // Now map the tag to the symbol
875  query = type == SymbolEntity
876  ? sqlite3_mprintf( "INSERT INTO tagmap VALUES (%d,%d)", tagid, symbolid )
877  : sqlite3_mprintf( "INSERT INTO ctagmap VALUES (%d,%d)", tagid, symbolid );
878 
879  char *zErr = 0;
880  nErr = sqlite3_exec( mCurrentDB, query, NULL, NULL, &zErr );
881  if ( nErr )
882  {
883  QgsDebugMsg( zErr );
884  }
885  }
886 
887  return true;
888 }
889 
890 bool QgsStyleV2::detagSymbol( StyleEntity type, QString symbol, QStringList tags )
891 {
892  if ( !mCurrentDB )
893  {
894  QgsDebugMsg( "Sorry! Cannot open database for detgging." );
895  return false;
896  }
897 
898  char *query = type == SymbolEntity
899  ? sqlite3_mprintf( "SELECT id FROM symbol WHERE name='%q'", symbol.toUtf8().constData() )
900  : sqlite3_mprintf( "SELECT id FROM colorramp WHERE name='%q'", symbol.toUtf8().constData() );
901  sqlite3_stmt *ppStmt;
902  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
903 
904  int symbolid = 0;
905  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
906  {
907  symbolid = sqlite3_column_int( ppStmt, 0 );
908  }
909 
910  sqlite3_finalize( ppStmt );
911 
912  foreach ( const QString &tag, tags )
913  {
914  query = sqlite3_mprintf( "SELECT id FROM tag WHERE name='%q'", tag.toUtf8().constData() );
915 
916  sqlite3_stmt *ppStmt2;
917  nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt2, NULL );
918 
919  int tagid = 0;
920  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
921  {
922  tagid = sqlite3_column_int( ppStmt2, 0 );
923  }
924 
925  sqlite3_finalize( ppStmt2 );
926 
927  if ( tagid )
928  {
929  // remove from the tagmap
930  query = type == SymbolEntity
931  ? sqlite3_mprintf( "DELETE FROM tagmap WHERE tag_id=%d AND symbol_id=%d", tagid, symbolid )
932  : sqlite3_mprintf( "DELETE FROM ctagmap WHERE tag_id=%d AND colorramp_id=%d", tagid, symbolid );
933  runEmptyQuery( query );
934  }
935  }
936 
937  // TODO Perform tag cleanup
938  // check the number of entries for a given tag in the tagmap
939  // if the count is 0, then remove( TagEntity, tagid )
940  return true;
941 }
942 
943 QStringList QgsStyleV2::tagsOfSymbol( StyleEntity type, QString symbol )
944 {
945  if ( !mCurrentDB )
946  {
947  QgsDebugMsg( "Sorry! Cannot open database for getting the tags." );
948  return QStringList();
949  }
950 
951  int symbolid = type == SymbolEntity ? symbolId( symbol ) : colorrampId( symbol );
952  if ( !symbolid )
953  return QStringList();
954 
955  // get the ids of tags for the symbol
956  char *query = type == SymbolEntity
957  ? sqlite3_mprintf( "SELECT tag_id FROM tagmap WHERE symbol_id=%d", symbolid )
958  : sqlite3_mprintf( "SELECT tag_id FROM ctagmap WHERE colorramp_id=%d", symbolid );
959 
960  sqlite3_stmt *ppStmt;
961  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
962 
963  QStringList tagList;
964  while ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
965  {
966  char *subquery = sqlite3_mprintf( "SELECT name FROM tag WHERE id=%d", sqlite3_column_int( ppStmt, 0 ) );
967 
968  sqlite3_stmt *ppStmt2;
969  int pErr = sqlite3_prepare_v2( mCurrentDB, subquery, -1, &ppStmt2, NULL );
970  if ( pErr == SQLITE_OK && sqlite3_step( ppStmt2 ) == SQLITE_ROW )
971  {
972  tagList << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt2, 0 ) );
973  }
974  sqlite3_finalize( ppStmt2 );
975  }
976 
977  sqlite3_finalize( ppStmt );
978 
979  return tagList;
980 }
981 
982 int QgsStyleV2::getId( QString table, QString name )
983 {
984  char *query = sqlite3_mprintf( "SELECT id FROM %q WHERE name='%q'", table.toUtf8().constData(), name.toUtf8().constData() );
985 
986  sqlite3_stmt *ppStmt;
987  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
988 
989  int id = 0;
990  if ( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
991  {
992  id = sqlite3_column_int( ppStmt, 0 );
993  }
994 
995  sqlite3_finalize( ppStmt );
996 
997  return id;
998 }
999 
1000 int QgsStyleV2::symbolId( QString name )
1001 {
1002  return getId( "symbol", name );
1003 }
1004 
1005 int QgsStyleV2::colorrampId( QString name )
1006 {
1007  return getId( "colorramp", name );
1008 }
1009 
1010 int QgsStyleV2::groupId( QString name )
1011 {
1012  return getId( "symgroup", name );
1013 }
1014 
1015 int QgsStyleV2::tagId( QString name )
1016 {
1017  return getId( "tag", name );
1018 }
1019 
1020 int QgsStyleV2::smartgroupId( QString name )
1021 {
1022  return getId( "smartgroup", name );
1023 }
1024 
1025 int QgsStyleV2::addSmartgroup( QString name, QString op, QgsSmartConditionMap conditions )
1026 {
1027  QDomDocument doc( "dummy" );
1028  QDomElement smartEl = doc.createElement( "smartgroup" );
1029  smartEl.setAttribute( "name", name );
1030  smartEl.setAttribute( "operator", op );
1031 
1032  QStringList constraints;
1033  constraints << "tag" << "group" << "name" << "!tag" << "!group" << "!name";
1034 
1035  foreach ( const QString &constraint, constraints )
1036  {
1037  QStringList parameters = conditions.values( constraint );
1038  foreach ( const QString &param, parameters )
1039  {
1040  QDomElement condEl = doc.createElement( "condition" );
1041  condEl.setAttribute( "constraint", constraint );
1042  condEl.setAttribute( "param", param );
1043  smartEl.appendChild( condEl );
1044  }
1045  }
1046 
1047  QByteArray xmlArray;
1048  QTextStream stream( &xmlArray );
1049  stream.setCodec( "UTF-8" );
1050  smartEl.save( stream, 4 );
1051  char *query = sqlite3_mprintf( "INSERT INTO smartgroup VALUES (NULL, '%q', '%q')",
1052  name.toUtf8().constData(), xmlArray.constData() );
1053 
1054  if ( runEmptyQuery( query ) )
1055  {
1056  return ( int )sqlite3_last_insert_rowid( mCurrentDB );
1057  }
1058  else
1059  {
1060  QgsDebugMsg( "Couldn't insert symbol into the database!" );
1061  return 0;
1062  }
1063 }
1064 
1066 {
1067  if ( !mCurrentDB )
1068  {
1069  QgsDebugMsg( "Cannot open database for listing groups" );
1070  return QgsSymbolGroupMap();
1071  }
1072 
1073  char *query = sqlite3_mprintf( "SELECT * FROM smartgroup" );
1074 
1075  // Now run the query and retrieve the group names
1076  sqlite3_stmt *ppStmt;
1077  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1078 
1080  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1081  {
1082  QString group = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, SmartgroupName ) );
1083  groupNames.insert( sqlite3_column_int( ppStmt, SmartgroupId ), group );
1084  }
1085 
1086  sqlite3_finalize( ppStmt );
1087 
1088  return groupNames;
1089 }
1090 
1092 {
1093  if ( !mCurrentDB )
1094  {
1095  QgsDebugMsg( "Cannot open database for listing groups" );
1096  return QStringList();
1097  }
1098 
1099  char *query = sqlite3_mprintf( "SELECT name FROM smartgroup" );
1100 
1101  // Now run the query and retrieve the group names
1102  sqlite3_stmt *ppStmt;
1103  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1104 
1105  QStringList groups;
1106  while ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1107  {
1108  groups << QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1109  }
1110 
1111  sqlite3_finalize( ppStmt );
1112 
1113  return groups;
1114 }
1115 
1117 {
1118  QStringList symbols;
1119 
1120  char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
1121 
1122  sqlite3_stmt *ppStmt;
1123  int nErr = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1124  if ( !( nErr == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW ) )
1125  {
1126  sqlite3_finalize( ppStmt );
1127  return QStringList();
1128  }
1129  else
1130  {
1131  QDomDocument doc;
1132  QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1133  if ( !doc.setContent( xmlstr ) )
1134  {
1135  QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
1136  }
1137  QDomElement smartEl = doc.documentElement();
1138  QString op = smartEl.attribute( "operator" );
1139  QDomNodeList conditionNodes = smartEl.childNodes();
1140 
1141  bool firstSet = true;
1142  for ( int i = 0; i < conditionNodes.count(); i++ )
1143  {
1144  QDomElement condEl = conditionNodes.at( i ).toElement();
1145  QString constraint = condEl.attribute( "constraint" );
1146  QString param = condEl.attribute( "param" );
1147 
1148  QStringList resultNames;
1149  // perform suitable action for the given constraint
1150  if ( constraint == "tag" )
1151  {
1152  resultNames = symbolsWithTag( type, tagId( param ) );
1153  }
1154  else if ( constraint == "group" )
1155  {
1156  // XXX Validating group id might be a good idea here
1157  resultNames = symbolsOfGroup( type, groupId( param ) );
1158 
1159  }
1160  else if ( constraint == "name" )
1161  {
1162  if ( type == SymbolEntity )
1163  {
1164  resultNames = symbolNames().filter( param, Qt::CaseInsensitive );
1165  }
1166  else
1167  {
1168  resultNames = colorRampNames().filter( param, Qt::CaseInsensitive );
1169  }
1170  }
1171  else if ( constraint == "!tag" )
1172  {
1173  resultNames = type == SymbolEntity ? symbolNames() : colorRampNames();
1174  QStringList unwanted = symbolsWithTag( type, tagId( param ) );
1175  foreach ( QString name, unwanted )
1176  {
1177  resultNames.removeAll( name );
1178  }
1179  }
1180  else if ( constraint == "!group" )
1181  {
1182  resultNames = type == SymbolEntity ? symbolNames() : colorRampNames();
1183  QStringList unwanted = symbolsOfGroup( type, groupId( param ) );
1184  foreach ( QString name, unwanted )
1185  {
1186  resultNames.removeAll( name );
1187  }
1188  }
1189  else if ( constraint == "!name" )
1190  {
1191  QStringList all = type == SymbolEntity ? symbolNames() : colorRampNames();
1192  foreach ( const QString &str, all )
1193  {
1194  if ( !str.contains( param, Qt::CaseInsensitive ) )
1195  resultNames << str;
1196  }
1197  }
1198 
1199  // not apply the operator
1200  if ( firstSet )
1201  {
1202  symbols = resultNames;
1203  firstSet = false;
1204  }
1205  else
1206  {
1207  if ( op == "OR" )
1208  {
1209  symbols << resultNames;
1210  }
1211  else if ( op == "AND" )
1212  {
1213  QStringList dummy = symbols;
1214  symbols.clear();
1215  foreach ( const QString &result, resultNames )
1216  {
1217  if ( dummy.contains( result ) )
1218  symbols << result;
1219  }
1220  }
1221  }
1222  } // DOM loop ends here
1223  }
1224 
1225  sqlite3_finalize( ppStmt );
1226 
1227  return symbols;
1228 }
1229 
1231 {
1232  if ( !mCurrentDB )
1233  {
1234  QgsDebugMsg( "Cannot open database for listing groups" );
1235  return QgsSmartConditionMap();
1236  }
1237 
1238  QgsSmartConditionMap condition;
1239 
1240  char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
1241 
1242  sqlite3_stmt *ppStmt;
1243  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1244  if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1245  {
1246  QDomDocument doc;
1247  QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1248  if ( !doc.setContent( xmlstr ) )
1249  {
1250  QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
1251  }
1252 
1253  QDomElement smartEl = doc.documentElement();
1254  QString op = smartEl.attribute( "operator" );
1255  QDomNodeList conditionNodes = smartEl.childNodes();
1256 
1257  for ( int i = 0; i < conditionNodes.count(); i++ )
1258  {
1259  QDomElement condEl = conditionNodes.at( i ).toElement();
1260  QString constraint = condEl.attribute( "constraint" );
1261  QString param = condEl.attribute( "param" );
1262 
1263  condition.insert( constraint, param );
1264  }
1265  }
1266 
1267  sqlite3_finalize( ppStmt );
1268 
1269  return condition;
1270 }
1271 
1273 {
1274  if ( !mCurrentDB )
1275  {
1276  QgsDebugMsg( "Cannot open database for listing groups" );
1277  return QString();
1278  }
1279 
1280  QString op;
1281 
1282  char *query = sqlite3_mprintf( "SELECT xml FROM smartgroup WHERE id=%d", id );
1283 
1284  sqlite3_stmt *ppStmt;
1285  int nError = sqlite3_prepare_v2( mCurrentDB, query, -1, &ppStmt, NULL );
1286  if ( nError == SQLITE_OK && sqlite3_step( ppStmt ) == SQLITE_ROW )
1287  {
1288  QDomDocument doc;
1289  QString xmlstr = QString::fromUtf8(( const char * ) sqlite3_column_text( ppStmt, 0 ) );
1290  if ( !doc.setContent( xmlstr ) )
1291  {
1292  QgsDebugMsg( QString( "Cannot open smartgroup id: %1" ).arg( id ) );
1293  }
1294  QDomElement smartEl = doc.documentElement();
1295  op = smartEl.attribute( "operator" );
1296  }
1297 
1298  sqlite3_finalize( ppStmt );
1299 
1300  return op;
1301 }
1302 
1303 bool QgsStyleV2::exportXML( QString filename )
1304 {
1305  if ( filename.isEmpty() )
1306  {
1307  QgsDebugMsg( "Invalid filename for style export." );
1308  return false;
1309  }
1310 
1311  QDomDocument doc( "qgis_style" );
1312  QDomElement root = doc.createElement( "qgis_style" );
1313  root.setAttribute( "version", STYLE_CURRENT_VERSION );
1314  doc.appendChild( root );
1315 
1316  // TODO work on the groups and tags
1317  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( mSymbols, "symbols", doc );
1318  QDomElement rampsElem = doc.createElement( "colorramps" );
1319 
1320  // save color ramps
1321  for ( QMap<QString, QgsVectorColorRampV2*>::iterator itr = mColorRamps.begin(); itr != mColorRamps.end(); ++itr )
1322  {
1323  QDomElement rampEl = QgsSymbolLayerV2Utils::saveColorRamp( itr.key(), itr.value(), doc );
1324  rampsElem.appendChild( rampEl );
1325  }
1326 
1327  root.appendChild( symbolsElem );
1328  root.appendChild( rampsElem );
1329 
1330  // save
1331  QFile f( filename );
1332  if ( !f.open( QFile::WriteOnly ) )
1333  {
1334  mErrorString = "Couldn't open file for writing: " + filename;
1335  return false;
1336  }
1337 
1338  QTextStream ts( &f );
1339  ts.setCodec( "UTF-8" );
1340  doc.save( ts, 2 );
1341  f.close();
1342 
1343  mFileName = filename;
1344  return true;
1345 }
1346 
1347 bool QgsStyleV2::importXML( QString filename )
1348 {
1349  mErrorString = QString();
1350  QDomDocument doc( "style" );
1351  QFile f( filename );
1352  if ( !f.open( QFile::ReadOnly ) )
1353  {
1354  mErrorString = "Unable to open the specified file";
1355  QgsDebugMsg( "Error opening the style XML file." );
1356  return false;
1357  }
1358 
1359  if ( !doc.setContent( &f ) )
1360  {
1361  mErrorString = QString( "Unable to understand the style file: %1" ).arg( filename );
1362  QgsDebugMsg( "XML Parsing error" );
1363  f.close();
1364  return false;
1365  }
1366  f.close();
1367 
1368  QDomElement docEl = doc.documentElement();
1369  if ( docEl.tagName() != "qgis_style" )
1370  {
1371  mErrorString = "Incorrect root tag in style: " + docEl.tagName();
1372  return false;
1373  }
1374 
1375  QString version = docEl.attribute( "version" );
1376  if ( version != STYLE_CURRENT_VERSION && version != "0" )
1377  {
1378  mErrorString = "Unknown style file version: " + version;
1379  return false;
1380  }
1381 
1382  QgsSymbolV2Map symbols;
1383 
1384  QDomElement symbolsElement = docEl.firstChildElement( "symbols" );
1385  QDomElement e = symbolsElement.firstChildElement();
1386 
1387  if ( version == STYLE_CURRENT_VERSION )
1388  {
1389  // For the new style, load symbols individualy
1390  while ( !e.isNull() )
1391  {
1392  if ( e.tagName() == "symbol" )
1393  {
1395  if ( symbol )
1396  {
1397  symbols.insert( e.attribute( "name" ), symbol );
1398  }
1399  }
1400  else
1401  {
1402  QgsDebugMsg( "unknown tag: " + e.tagName() );
1403  }
1404  e = e.nextSiblingElement();
1405  }
1406  }
1407  else
1408  {
1409  // for the old version, use the utility function to solve @symbol@layer subsymbols
1410  symbols = QgsSymbolLayerV2Utils::loadSymbols( symbolsElement );
1411  }
1412 
1413  // save the symbols with proper name
1414  for ( QMap<QString, QgsSymbolV2*>::iterator it = symbols.begin(); it != symbols.end(); ++it )
1415  {
1416  addSymbol( it.key(), it.value() );
1417  }
1418 
1419  // load color ramps
1420  QDomElement rampsElement = docEl.firstChildElement( "colorramps" );
1421  e = rampsElement.firstChildElement();
1422  while ( !e.isNull() )
1423  {
1424  if ( e.tagName() == "colorramp" )
1425  {
1427  if ( ramp )
1428  {
1429  addColorRamp( e.attribute( "name" ), ramp );
1430  }
1431  }
1432  else
1433  {
1434  QgsDebugMsg( "unknown tag: " + e.tagName() );
1435  }
1436  e = e.nextSiblingElement();
1437  }
1438 
1439  mFileName = filename;
1440  return true;
1441 }
1442 
1443 bool QgsStyleV2::updateSymbol( StyleEntity type, QString name )
1444 {
1445  QDomDocument doc( "dummy" );
1446  QDomElement symEl;
1447  QByteArray xmlArray;
1448  QTextStream stream( &xmlArray );
1449  stream.setCodec( "UTF-8" );
1450 
1451  char *query;
1452 
1453  if ( type == SymbolEntity )
1454  {
1455  // check if it is an existing symbol
1456  if ( !symbolNames().contains( name ) )
1457  {
1458  QgsDebugMsg( "Update request received for unavailable symbol" );
1459  return false;
1460  }
1461 
1462  symEl = QgsSymbolLayerV2Utils::saveSymbol( name, symbol( name ), doc );
1463  if ( symEl.isNull() )
1464  {
1465  QgsDebugMsg( "Couldn't convert symbol to valid XML!" );
1466  return false;
1467  }
1468  symEl.save( stream, 4 );
1469  query = sqlite3_mprintf( "UPDATE symbol SET xml='%q' WHERE name='%q';",
1470  xmlArray.constData(), name.toUtf8().constData() );
1471  }
1472  else if ( type == ColorrampEntity )
1473  {
1474  if ( !colorRampNames().contains( name ) )
1475  {
1476  QgsDebugMsg( "Update requested for unavailable color ramp." );
1477  return false;
1478  }
1479 
1480  symEl = QgsSymbolLayerV2Utils::saveColorRamp( name, colorRamp( name ), doc );
1481  if ( symEl.isNull() )
1482  {
1483  QgsDebugMsg( "Couldn't convert color ramp to valid XML!" );
1484  return false;
1485  }
1486  symEl.save( stream, 4 );
1487  query = sqlite3_mprintf( "UPDATE colorramp SET xml='%q' WHERE name='%q';",
1488  xmlArray.constData(), name.toUtf8().constData() );
1489  }
1490  else
1491  {
1492  QgsDebugMsg( "Updating the unsupported StyleEntity" );
1493  return false;
1494  }
1495 
1496 
1497  if ( !runEmptyQuery( query ) )
1498  {
1499  QgsDebugMsg( "Couldn't insert symbol into the database!" );
1500  return false;
1501  }
1502  return true;
1503 }