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