QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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  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  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 }
QString mErrorString
Definition: qgsstylev2.h:325
QString smartgroupOperator(int id)
returns the operator for the smartgroup
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:39
static QgsSymbolV2Map loadSymbols(QDomElement &element)
QString mFileName
Definition: qgsstylev2.h:326
void remove(StyleEntity type, int id)
remove the specified entity from the db
Definition: qgsstylev2.cpp:691
QStringList tagsOfSymbol(StyleEntity type, QString symbol)
return the tags associated with the symbol
Definition: qgsstylev2.cpp:943
bool saveSymbol(QString name, QgsSymbolV2 *symbol, int groupid, QStringList tags)
add the symbol to the DB with the tags
Definition: qgsstylev2.cpp:107
int addSmartgroup(QString name, QString op, QgsSmartConditionMap conditions)
adds new smartgroup to the database and returns the id
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
bool updateSymbol(StyleEntity type, QString name)
updates the properties of an existing symbol/colorramp
int colorrampId(QString name)
return the id in the style database for the given colorramp name returns 0 if not found ...
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
bool group(StyleEntity type, QString name, int groupid)
applies the specified group to the symbol or colorramp specified by StyleEntity
Definition: qgsstylev2.cpp:743
virtual QgsSymbolV2 * clone() const =0
QMultiMap< QString, QString > QgsSmartConditionMap
Definition: qgsstylev2.h:56
QStringList symbolsOfGroup(StyleEntity type, int groupid)
returns the symbolnames of a given groupid
Definition: qgsstylev2.cpp:527
bool importXML(QString filename)
Imports the symbols and colorramps into the default style database from the given XML file...
int getId(QString table, QString name)
gets the id from the table for the given name from the database, 0 if not found
Definition: qgsstylev2.cpp:982
QgsSymbolV2 * symbol(QString name)
return a NEW copy of symbol
Definition: qgsstylev2.cpp:166
void rename(StyleEntity type, int id, QString newName)
rename the given entity with the specified id
Definition: qgsstylev2.cpp:645
QStringList colorRampNames()
return a list of names of color ramps
Definition: qgsstylev2.cpp:276
int addTag(QString tagName)
adds a new tag and returns the tag's id
Definition: qgsstylev2.cpp:630
bool renameSymbol(QString oldName, QString newName)
change symbol's name
Definition: qgsstylev2.cpp:406
char * getGroupRemoveQuery(int id)
prepares the complex query for removing a group, so that the children are not abandoned ...
Definition: qgsstylev2.cpp:673
QgsSymbolGroupMap childGroupNames(QString parent="")
return a map of groupid and names for the given parent group
Definition: qgsstylev2.cpp:480
bool addSymbol(QString name, QgsSymbolV2 *symbol, bool update=false)
add symbol to style. takes symbol's ownership
Definition: qgsstylev2.cpp:83
bool save(QString filename=QString())
save style into a file (will use current filename if empty string is passed)
Definition: qgsstylev2.cpp:360
void symbolSaved(QString name, QgsSymbolV2 *symbol)
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
const QgsSymbolV2 * symbolRef(QString name) const
return a const pointer to a symbol (doesn't create new instance)
Definition: qgsstylev2.cpp:172
const QgsVectorColorRampV2 * colorRampRef(QString name) const
return a const pointer to a symbol (doesn't create new instance)
Definition: qgsstylev2.cpp:266
int colorRampCount()
return count of color ramps
Definition: qgsstylev2.cpp:271
static QgsStyleV2 * mDefaultStyle
Definition: qgsstylev2.h:330
virtual QgsVectorColorRampV2 * clone() const =0
bool openDB(QString filename)
convenience function to open the DB and return a sqlite3 object
Definition: qgsstylev2.cpp:281
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
static QgsStyleV2 * defaultStyle()
return default application-wide style
Definition: qgsstylev2.cpp:51
sqlite3 * mCurrentDB
Definition: qgsstylev2.h:328
bool renameColorRamp(QString oldName, QString newName)
change ramp's name
Definition: qgsstylev2.cpp:438
bool load(QString filename)
load a file into the style
Definition: qgsstylev2.cpp:294
QStringList symbolsOfSmartgroup(StyleEntity type, int id)
returns the symbols for the smartgroup
bool runEmptyQuery(char *query, bool freeQuery=true)
convenience function that would run queries which don't generate return values
Definition: qgsstylev2.cpp:722
bool saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, int groupid, QStringList tags)
add the colorramp to the DB
Definition: qgsstylev2.cpp:212
QStringList symbolNames()
return a list of names of symbols
Definition: qgsstylev2.cpp:182
QMap< int, QString > QgsSymbolGroupMap
Definition: qgsstylev2.h:35
static const QString defaultStyleV2Path()
Returns the path to default style (works as a starting point).
QgsSymbolGroupMap smartgroupsListMap()
returns the smart groups map with id as key and name as value
bool exportXML(QString filename)
Exports the style as a XML file.
QgsSymbolV2Map mSymbols
Definition: qgsstylev2.h:322
QgsVectorColorRampV2Map mColorRamps
Definition: qgsstylev2.h:323
QStringList smartgroupNames()
returns the smart groups list
QStringList symbolsWithTag(StyleEntity type, int tagid)
returns the symbol names with which have the given tag
Definition: qgsstylev2.cpp:564
void clear()
remove all contents of the style
Definition: qgsstylev2.cpp:70
bool detagSymbol(StyleEntity type, QString symbol, QStringList tags)
detags the symbol with the given list
Definition: qgsstylev2.cpp:890
bool removeSymbol(QString name)
remove symbol from style (and delete it)
Definition: qgsstylev2.cpp:138
bool addColorRamp(QString name, QgsVectorColorRampV2 *colorRamp, bool update=false)
add color ramp to style. takes ramp's ownership
Definition: qgsstylev2.cpp:188
int symbolCount()
return count of symbols in style
Definition: qgsstylev2.cpp:177
bool tagSymbol(StyleEntity type, QString symbol, QStringList tags)
tags the symbol with the tags in the list
Definition: qgsstylev2.cpp:838
bool removeColorRamp(QString name)
remove color ramp from style (and delete it)
Definition: qgsstylev2.cpp:242
int addGroup(QString groupName, int parent=0)
adds a new group and returns the group's id
Definition: qgsstylev2.cpp:613
static QgsSymbolV2 * loadSymbol(QDomElement &element)
int tagId(QString tag)
return the DB id for the given tag name
QgsVectorColorRampV2 * colorRamp(QString name)
return a NEW copy of color ramp
Definition: qgsstylev2.cpp:260
StyleEntity
Enum for Entities involved in a style.
Definition: qgsstylev2.h:80
QStringList findSymbols(StyleEntity type, QString qword)
return the names of the symbols which have a matching 'substring' in its defintion ...
Definition: qgsstylev2.cpp:764
static const QString userStyleV2Path()
Returns the path to user's style.
int smartgroupId(QString smartgroup)
return the DB id for the given smartgroup name
int symbolId(QString name)
return the id in the style database for the given symbol name returns 0 if not found ...
QStringList groupNames()
return the all the groups in the style
Definition: qgsstylev2.cpp:466
#define STYLE_CURRENT_VERSION
Definition: qgsstylev2.cpp:36
QgsSmartConditionMap smartgroup(int id)
returns the QgsSmartConditionMap for the given id
int groupId(QString group)
return the DB id for the given group name