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