QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsprojectproperty.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsproject.cpp - description
3  -------------------
4  begin : February 24, 2005
5  copyright : (C) 2005 by Mark Coletti
6  email : mcoletti at gmail.com
7 ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsprojectproperty.h"
19 #include "qgslogger.h"
20 
21 #include <QDomDocument>
22 #include <QStringList>
23 
24 void QgsPropertyValue::dump( int tabs ) const
25 {
26  QString tabString;
27  tabString.fill( '\t', tabs );
28 
29  if ( QVariant::StringList == value_.type() )
30  {
31  QStringList sl = value_.toStringList();
32 
33  for ( QStringList::const_iterator i = sl.begin(); i != sl.end(); ++i )
34  {
35  QgsDebugMsg( QString( "%1[%2] " ).arg( tabString ).arg( *i ) );
36  }
37  }
38  else
39  {
40  QgsDebugMsg( QString( "%1%2" ).arg( tabString ).arg( value_.toString() ) );
41  }
42 } // QgsPropertyValue::dump()
43 
44 
45 bool QgsPropertyValue::readXML( QDomNode & keyNode )
46 {
47  // this *should* be a Dom element node
48  QDomElement subkeyElement = keyNode.toElement();
49 
50  // get the type so that we can properly parse the key value
51  QString typeString = subkeyElement.attribute( "type" );
52 
53  if ( QString::null == typeString )
54  {
55  QgsDebugMsg( QString( "null ``type'' attribute for %1" ).arg( keyNode.nodeName() ) );
56 
57  return false;
58  }
59 
60  // the values come in as strings; we need to restore them to their
61  // original values *and* types
62  value_.clear();
63 
64  // get the type associated with the value first
65  QVariant::Type type = QVariant::nameToType( typeString.toLocal8Bit().constData() );
66 
67  // This huge switch is left-over from an earlier incarnation of
68  // QgsProject where there was a fine level of granularity for value
69  // types. The current interface, borrowed from QSettings, supports a
70  // very small sub-set of these types. However, I've left all the
71  // other types just in case the interface is expanded to include these
72  // other types.
73 
74  switch ( type )
75  {
76  case QVariant::Invalid:
77  QgsDebugMsg( QString( "invalid value type %1 .. " ).arg( typeString ) );
78  return false;
79 
80  case QVariant::Map:
81  QgsDebugMsg( "no support for QVariant::Map" );
82  return false;
83 
84  case QVariant::List:
85  QgsDebugMsg( "no support for QVariant::List" );
86  return false;
87 
88  case QVariant::String:
89  value_ = subkeyElement.text(); // no translating necessary
90  break;
91 
92  case QVariant::StringList:
93  {
94  int i = 0;
95  QDomNodeList values = keyNode.childNodes();
96 
97  // all the QStringList values will be inside <value> elements
98  QStringList valueStringList;
99 
100  while ( i < values.count() )
101  {
102  if ( "value" == values.item( i ).nodeName() )
103  { // <value>s have only one element, which contains actual string value
104  valueStringList.append( values.item( i ).firstChild().nodeValue() );
105  }
106  else
107  {
108  QgsDebugMsg( QString( "non <value> element ``%1'' in string list" ).arg( values.item( i ).nodeName() ) );
109  }
110 
111  ++i;
112  }
113 
114  value_ = valueStringList;
115  break;
116  }
117 
118  case QVariant::Font:
119  QgsDebugMsg( "no support for QVariant::Font" );
120  return false;
121 
122  case QVariant::Pixmap:
123  QgsDebugMsg( "no support for QVariant::Pixmap" );
124  return false;
125 
126  case QVariant::Brush:
127  QgsDebugMsg( "no support for QVariant::Brush" );
128  return false;
129 
130  case QVariant::Rect:
131  QgsDebugMsg( "no support for QVariant::Rect" );
132  return false;
133 
134  case QVariant::Size:
135  QgsDebugMsg( "no support for QVariant::Size" );
136  return false;
137 
138  case QVariant::Color:
139  QgsDebugMsg( "no support for QVariant::Color" );
140  return false;
141 
142  case QVariant::Palette:
143  QgsDebugMsg( "no support for QVariant::Palette" );
144  return false;
145 
146  case QVariant::Point:
147  QgsDebugMsg( "no support for QVariant::Point" );
148  return false;
149 
150  case QVariant::Image:
151  QgsDebugMsg( "no support for QVariant::Image" );
152  return false;
153 
154  case QVariant::Int:
155  value_ = QVariant( subkeyElement.text() ).toInt();
156  break;
157 
158  case QVariant::UInt:
159  value_ = QVariant( subkeyElement.text() ).toUInt();
160  break;
161 
162  case QVariant::Bool:
163  value_ = QVariant( subkeyElement.text() ).toBool();
164  break;
165 
166  case QVariant::Double:
167  value_ = QVariant( subkeyElement.text() ).toDouble();
168  break;
169 
170  case QVariant::ByteArray:
171  value_ = QVariant( subkeyElement.text() ).toByteArray();
172  break;
173 
174  case QVariant::Polygon:
175  QgsDebugMsg( "no support for QVariant::Polygon" );
176  return false;
177 
178  case QVariant::Region:
179  QgsDebugMsg( "no support for QVariant::Region" );
180  return false;
181 
182  case QVariant::Bitmap:
183  QgsDebugMsg( "no support for QVariant::Bitmap" );
184  return false;
185 
186  case QVariant::Cursor:
187  QgsDebugMsg( "no support for QVariant::Cursor" );
188  return false;
189 
190  case QVariant::BitArray :
191  QgsDebugMsg( "no support for QVariant::BitArray" );
192  return false;
193 
194  case QVariant::KeySequence :
195  QgsDebugMsg( "no support for QVariant::KeySequence" );
196  return false;
197 
198  case QVariant::Pen :
199  QgsDebugMsg( "no support for QVariant::Pen" );
200  return false;
201 
202  //
203  // QGIS DIES NOT SUPPORT THESE VARIANT TYPES IN VERSION 3.1 DISABLING FOR NOW
204  //
205  /*
206  case QVariant::LongLong :
207  value_ = QVariant(subkeyElement.text()).toLongLong();
208  break;
209 
210  case QVariant::ULongLong :
211  value_ = QVariant(subkeyElement.text()).toULongLong();
212  break;
213  */
214  default :
215  QgsDebugMsg( QString( "unsupported value type %1 .. not propertly translated to QVariant" ).arg( typeString ) );
216  }
217 
218  return true;
219 
220 } // QgsPropertyValue::readXML
221 
222 
226 bool QgsPropertyValue::writeXML( QString const & nodeName,
227  QDomElement & keyElement,
228  QDomDocument & document )
229 {
230  QDomElement valueElement = document.createElement( nodeName );
231 
232  // remember the type so that we can rebuild it when the project is read in
233  valueElement.setAttribute( "type", value_.typeName() );
234 
235 
236  // we handle string lists differently from other types in that we
237  // create a sequence of repeated elements to cover all the string list
238  // members; each value will be in a <value></value> tag.
239  // XXX Not the most elegant way to handle string lists?
240  if ( QVariant::StringList == value_.type() )
241  {
242  QStringList sl = value_.toStringList();
243 
244  for ( QStringList::iterator i = sl.begin();
245  i != sl.end();
246  ++i )
247  {
248  QDomElement stringListElement = document.createElement( "value" );
249  QDomText valueText = document.createTextNode( *i );
250  stringListElement.appendChild( valueText );
251 
252  valueElement.appendChild( stringListElement );
253  }
254  }
255  else // we just plop the value in as plain ole text
256  {
257  QDomText valueText = document.createTextNode( value_.toString() );
258  valueElement.appendChild( valueText );
259  }
260 
261  keyElement.appendChild( valueElement );
262 
263  return true;
264 } // QgsPropertyValue::writeXML
265 
266 
267 QgsPropertyKey::QgsPropertyKey( const QString &name )
268  : mName( name )
269 {}
270 
272 {
273  clearKeys();
274 }
275 
276 QVariant QgsPropertyKey::value() const
277 {
278  QgsProperty *foundQgsProperty = mProperties.value( name() );
279 
280  if ( !foundQgsProperty )
281  {
282  QgsDebugMsg( "key has null child" );
283  return QVariant(); // just return an QVariant::Invalid
284  }
285 
286  return foundQgsProperty->value();
287 } // QVariant QgsPropertyKey::value()
288 
289 
290 void QgsPropertyKey::dump( int tabs ) const
291 {
292  QString tabString;
293 
294  tabString.fill( '\t', tabs );
295 
296  QgsDebugMsg( QString( "%1name: %2" ).arg( tabString ).arg( name() ) );
297 
298  tabs++;
299  tabString.fill( '\t', tabs );
300 
301  if ( ! mProperties.isEmpty() )
302  {
303  QHashIterator < QString, QgsProperty* > i( mProperties );
304  while ( i.hasNext() )
305  {
306  if ( i.next().value()->isValue() )
307  {
308  QgsPropertyValue * propertyValue =
309  dynamic_cast<QgsPropertyValue*>( i.value() );
310 
311  if ( QVariant::StringList == propertyValue->value().type() )
312  {
313  QgsDebugMsg( QString( "%1key: <%2> value:" ).arg( tabString ).arg( i.key() ) );
314  propertyValue->dump( tabs + 1 );
315  }
316  else
317  {
318  QgsDebugMsg( QString( "%1key: <%2> value: %3" ).arg( tabString ).arg( i.key() ).arg( propertyValue->value().toString() ) );
319  }
320  }
321  else
322  {
323  QgsDebugMsg( QString( "%1key: <%2> subkey: <%3>" )
324  .arg( tabString )
325  .arg( i.key() )
326  .arg( dynamic_cast<QgsPropertyKey*>( i.value() )->name() ) );
327  i.value()->dump( tabs + 1 );
328  }
329 
330 #if 0
331  qDebug( "<%s>", name().toUtf8().constData() );
332  if ( i.value()->isValue() )
333  {
334  qDebug( " <%s>", i.key().toUtf8().constData() );
335  }
336  i.value()->dump();
337  if ( i.value()->isValue() )
338  {
339  qDebug( " </%s>", i.key().toUtf8().constData() );
340  }
341  qDebug( "</%s>", name().toUtf8().constData() );
342 #endif
343  }
344  }
345 
346 } // QgsPropertyKey::dump
347 
348 
349 
350 bool QgsPropertyKey::readXML( QDomNode & keyNode )
351 {
352  int i = 0;
353  QDomNodeList subkeys = keyNode.childNodes();
354 
355  while ( i < subkeys.count() )
356  {
357  // if the current node is an element that has a "type" attribute,
358  // then we know it's a leaf node; i.e., a subkey _value_, and not
359  // a subkey
360  if ( subkeys.item( i ).hasAttributes() && // if we have attributes
361  subkeys.item( i ).isElement() && // and we're an element
362  subkeys.item( i ).toElement().hasAttribute( "type" ) ) // and we have a "type" attribute
363  { // then we're a key value
364  delete mProperties.take( subkeys.item( i ).nodeName() );
365  mProperties.insert( subkeys.item( i ).nodeName(), new QgsPropertyValue );
366 
367  QDomNode subkey = subkeys.item( i );
368 
369  if ( !mProperties[subkeys.item( i ).nodeName()]->readXML( subkey ) )
370  {
371  QgsDebugMsg( QString( "unable to parse key value %1" ).arg( subkeys.item( i ).nodeName() ) );
372  }
373  }
374  else // otherwise it's a subkey, so just
375  // recurse on down the remaining keys
376  {
377  addKey( subkeys.item( i ).nodeName() );
378 
379  QDomNode subkey = subkeys.item( i );
380 
381  if ( !mProperties[subkeys.item( i ).nodeName()]->readXML( subkey ) )
382  {
383  QgsDebugMsg( QString( "unable to parse subkey %1" ).arg( subkeys.item( i ).nodeName() ) );
384  }
385  }
386 
387  ++i;
388  }
389 
390  return true;
391 } // QgsPropertyKey::readXML(QDomNode & keyNode)
392 
393 
398 bool QgsPropertyKey::writeXML( QString const &nodeName, QDomElement & element, QDomDocument & document )
399 {
400  // If it's an _empty_ node (i.e., one with no properties) we need to emit
401  // an empty place holder; else create new Dom elements as necessary.
402 
403  QDomElement keyElement = document.createElement( nodeName ); // Dom element for this property key
404 
405  if ( ! mProperties.isEmpty() )
406  {
407  QHashIterator < QString, QgsProperty* > i( mProperties );
408  while ( i.hasNext() )
409  {
410  i.next();
411  if ( !i.value()->writeXML( i.key(), keyElement, document ) )
412  {
413  return false;
414  }
415  }
416  }
417 
418  element.appendChild( keyElement );
419 
420  return true;
421 } // QgsPropertyKey::writeXML
422 
423 
424 
427 void QgsPropertyKey::entryList( QStringList & entries ) const
428 {
429  // now add any leaf nodes to the entries list
430  QHashIterator < QString, QgsProperty* > i( mProperties );
431  while ( i.hasNext() )
432  {
433  // add any of the nodes that have just a single value
434  if ( i.next().value()->isLeaf() )
435  {
436  entries.append( i.key() );
437  }
438  }
439 } // QgsPropertyKey::entryList
440 
441 
442 
443 void QgsPropertyKey::subkeyList( QStringList & entries ) const
444 {
445  // now add any leaf nodes to the entries list
446  QHashIterator < QString, QgsProperty* > i( mProperties );
447  while ( i.hasNext() )
448  {
449  // add any of the nodes that have just a single value
450  if ( !i.next().value()->isLeaf() )
451  {
452  entries.append( i.key() );
453  }
454  }
455 } // QgsPropertyKey::subkeyList
456 
457 
459 {
460  if ( 0 == count() )
461  {
462  return true;
463  }
464  else if ( 1 == count() )
465  {
466  QHashIterator < QString, QgsProperty* > i( mProperties );
467 
468  if ( i.hasNext() && i.next().value()->isValue() )
469  {
470  return true;
471  }
472  }
473 
474  return false;
475 } // QgsPropertyKey::isLeaf
QgsPropertyKey * addKey(const QString &keyName)
add the given property key
bool writeXML(const QString &nodeName, QDomElement &element, QDomDocument &document)
Property keys will always create a Dom element for itself and then recursively call writeXML for any ...
void entryList(QStringList &entries) const
return keys that do not contain other keys
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QVariant value() const
return the node's value
QHash< QString, QgsProperty * > mProperties
sub-keys
QgsPropertyValue node.
void dump(int tabs=0) const
dumps out the keys and values
void dump(int tabs=0) const
dumps out the keys and values
virtual void clearKeys()
delete any sub-nodes
virtual QVariant value() const =0
return the node's value
bool readXML(QDomNode &keyNode)
restores property hierarchy to given Dom node
An Abstract Base Class for QGIS project property hierarchies.
bool writeXML(const QString &nodeName, QDomElement &element, QDomDocument &document)
keyElement created by parent QgsPropertyKey
void subkeyList(QStringList &entries) const
return keys that contain other keys
QVariant value_
We use QVariant as it's very handy to keep multiple types and provides type conversions.
QgsPropertyKey(const QString &name="")
bool isLeaf() const
returns true if a leaf node
bool readXML(QDomNode &keyNode)
restores property hierarchy to given Dom node
const QString & name() const
every key has a name
QVariant value() const
if this key has a value, it will be stored by its name in its properties
int count() const
how many elements are contained within this one?