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