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