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