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