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