16
16
***************************************************************************/
18
18
#include "qgsprojectproperty.h"
24
// Qt4-only includes to go here
19
#include "qgslogger.h"
21
#include <QDomDocument>
25
22
#include <QStringList>
28
static const char * const ident_ = "$Id: qgsprojectproperty.cpp 5681 2006-08-10 10:51:04Z g_j_m $";
24
static const char * const ident_ = "$Id$";
33
27
void QgsPropertyValue::dump( size_t tabs ) const
36
tabString.fill( '\t', tabs );
38
if (QVariant::StringList == value_.type())
40
QStringList sl = value_.toStringList();
42
for (QStringList::const_iterator i = sl.begin(); i != sl.end(); ++i)
44
qDebug("%s[%s] ", tabString.toLocal8Bit().data(), (const char *) (*i).toLocal8Bit().data());
49
qDebug("%s%s", tabString.toLocal8Bit().data(), (const char *) value_.toString().toLocal8Bit().data());
30
tabString.fill( '\t', tabs );
32
if ( QVariant::StringList == value_.type() )
34
QStringList sl = value_.toStringList();
36
for ( QStringList::const_iterator i = sl.begin(); i != sl.end(); ++i )
38
QgsDebugMsg( QString( "%1[%2] " ).arg( tabString ).arg( *i ) );
43
QgsDebugMsg( QString( "%1%2" ).arg( tabString ).arg( value_.toString() ) );
51
45
} // QgsPropertyValue::dump()
55
bool QgsPropertyValue::readXML(QDomNode & keyNode)
49
bool QgsPropertyValue::readXML( QDomNode & keyNode )
57
// this *should* be a DOM element node
58
QDomElement subkeyElement = keyNode.toElement();
60
// get the type so that we can properly parse the key value
61
QString typeString = subkeyElement.attribute("type");
63
if (QString::null == typeString)
65
qDebug("%s:%d null ``type'' attribute for %s", __FILE__, __LINE__,
66
(const char *) keyNode.nodeName().utf8());
71
// the values come in as strings; we need to restore them to their
72
// original values *and* types
75
// get the type associated with the value first
76
QVariant::Type type = QVariant::nameToType(typeString.toLocal8Bit().data());
78
// This huge switch is left-over from an earlier incarnation of
79
// QgsProject where there was a fine level of granularity for value
80
// types. The current interface, borrowed from QSettings, supports a
81
// very small sub-set of these types. However, I've left all the
82
// other types just in case the interface is expanded to include these
87
case QVariant::Invalid:
88
qDebug("%s:%d invalid value type %s .. ", __FILE__, __LINE__,
89
(const char *) typeString.utf8());
96
qDebug("qgsproject.cpp:%d add support for QVariant::Map", __LINE__);
103
qDebug("qgsproject.cpp:%d add support for QVariant::List", __LINE__);
109
case QVariant::String:
110
value_ = subkeyElement.text(); // no translating necessary
113
case QVariant::StringList:
51
// this *should* be a Dom element node
52
QDomElement subkeyElement = keyNode.toElement();
54
// get the type so that we can properly parse the key value
55
QString typeString = subkeyElement.attribute( "type" );
57
if ( QString::null == typeString )
59
QgsDebugMsg( QString( "null ``type'' attribute for %1" ).arg( keyNode.nodeName() ) );
64
// the values come in as strings; we need to restore them to their
65
// original values *and* types
68
// get the type associated with the value first
69
QVariant::Type type = QVariant::nameToType( typeString.toLocal8Bit().constData() );
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
80
case QVariant::Invalid:
81
QgsDebugMsg( QString( "invalid value type %1 .. " ).arg( typeString ) );
85
QgsDebugMsg( "no support for QVariant::Map" );
89
QgsDebugMsg( "no support for QVariant::List" );
92
case QVariant::String:
93
value_ = subkeyElement.text(); // no translating necessary
96
case QVariant::StringList:
99
QDomNodeList values = keyNode.childNodes();
101
// all the QStringList values will be inside <value> elements
102
QStringList valueStringList;
104
while ( i < values.count() )
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() );
116
QDomNodeList values = keyNode.childNodes();
118
// all the QStringList values will be inside <value> elements
119
QStringList valueStringList;
121
while (i < values.count())
123
if ("value" == values.item(i).nodeName())
124
{ // <value>s have only one element, which contains actual string value
125
valueStringList.append(values.item(i).firstChild().nodeValue());
129
("qgsproject.cpp:%d non <value> element ``%s'' in string list",
130
__LINE__, (const char *) values.item(i).nodeName().utf8());
136
value_ = valueStringList;
112
QgsDebugMsg( QString( "non <value> element ``%1'' in string list" ).arg( values.item( i ).nodeName() ) );
141
qDebug("qgsproject.cpp:%d add support for QVariant::Font", __LINE__);
147
case QVariant::Pixmap:
148
qDebug("qgsproject.cpp:%d add support for QVariant::Pixmap", __LINE__);
154
case QVariant::Brush:
155
qDebug("qgsproject.cpp:%d add support for QVariant::Brush", __LINE__);
162
qDebug("qgsproject.cpp:%d add support for QVariant::Rect", __LINE__);
169
qDebug("qgsproject.cpp:%d add support for QVariant::Size", __LINE__);
175
case QVariant::Color:
176
qDebug("qgsproject.cpp:%d add support for QVariant::Color", __LINE__);
182
case QVariant::Palette:
183
qDebug("qgsproject.cpp:%d add support for QVariant::Palette", __LINE__);
189
case QVariant::ColorGroup:
190
qDebug("qgsproject.cpp:%d add support for QVariant::ColorGroup",
197
case QVariant::Point:
198
qDebug("qgsproject.cpp:%d add support for QVariant::Point", __LINE__);
204
case QVariant::Image:
205
qDebug("qgsproject.cpp:%d add support for QVariant::Image", __LINE__);
212
value_ = QVariant(subkeyElement.text()).asInt();
217
value_ = QVariant(subkeyElement.text()).asUInt();
222
value_ = QVariant(subkeyElement.text()).asBool();
226
case QVariant::Double:
227
value_ = QVariant(subkeyElement.text()).asDouble();
231
// in Qt4 this is equivalent to case QVariant::ByteArray
232
case QVariant::CString:
233
value_ = QVariant(subkeyElement.text()).asCString();
237
case QVariant::PointArray:
238
qDebug("qgsproject.cpp:%d add support for QVariant::PointArray",
245
case QVariant::Region:
246
qDebug("qgsproject.cpp:%d add support for QVariant::Region", __LINE__);
252
case QVariant::Bitmap:
253
qDebug("qgsproject.cpp:%d add support for QVariant::Bitmap", __LINE__);
260
case QVariant::Cursor:
261
qDebug("qgsproject.cpp:%d add support for QVariant::Cursor", __LINE__);
266
case QVariant::BitArray :
267
qDebug( "qgsproject.cpp:%d add support for QVariant::BitArray", __LINE__ );
273
case QVariant::KeySequence :
274
qDebug( "qgsproject.cpp:%d add support for QVariant::KeySequence", __LINE__ );
281
qDebug( "qgsproject.cpp:%d add support for QVariant::Pen", __LINE__ );
287
// QGIS DIES NOT SUPPORT THESE VARIANT TYPES IN VERSION 3.1 DISABLING FOR NOW
290
case QVariant::LongLong :
291
value_ = QVariant(subkeyElement.text()).asLongLong();
294
case QVariant::ULongLong :
295
value_ = QVariant(subkeyElement.text()).asULongLong();
299
qDebug( "%s:%d unsupported value type %s .. not propertly translated to QVariant in qgsproject.cpp:",
300
__FILE__, __LINE__, (const char*)typeString.utf8() );
118
value_ = valueStringList;
123
QgsDebugMsg( "no support for QVariant::Font" );
126
case QVariant::Pixmap:
127
QgsDebugMsg( "no support for QVariant::Pixmap" );
130
case QVariant::Brush:
131
QgsDebugMsg( "no support for QVariant::Brush" );
135
QgsDebugMsg( "no support for QVariant::Rect" );
139
QgsDebugMsg( "no support for QVariant::Size" );
142
case QVariant::Color:
143
QgsDebugMsg( "no support for QVariant::Color" );
146
case QVariant::Palette:
147
QgsDebugMsg( "no support for QVariant::Palette" );
150
case QVariant::Point:
151
QgsDebugMsg( "no support for QVariant::Point" );
154
case QVariant::Image:
155
QgsDebugMsg( "no support for QVariant::Image" );
159
value_ = QVariant( subkeyElement.text() ).toInt();
163
value_ = QVariant( subkeyElement.text() ).toUInt();
167
value_ = QVariant( subkeyElement.text() ).toBool();
170
case QVariant::Double:
171
value_ = QVariant( subkeyElement.text() ).toDouble();
174
case QVariant::ByteArray:
175
value_ = QVariant( subkeyElement.text() ).toByteArray();
178
case QVariant::Polygon:
179
QgsDebugMsg( "no support for QVariant::Polygon" );
182
case QVariant::Region:
183
QgsDebugMsg( "no support for QVariant::Region" );
186
case QVariant::Bitmap:
187
QgsDebugMsg( "no support for QVariant::Bitmap" );
190
case QVariant::Cursor:
191
QgsDebugMsg( "no support for QVariant::Cursor" );
194
case QVariant::BitArray :
195
QgsDebugMsg( "no support for QVariant::BitArray" );
198
case QVariant::KeySequence :
199
QgsDebugMsg( "no support for QVariant::KeySequence" );
203
QgsDebugMsg( "no support for QVariant::Pen" );
207
// QGIS DIES NOT SUPPORT THESE VARIANT TYPES IN VERSION 3.1 DISABLING FOR NOW
210
case QVariant::LongLong :
211
value_ = QVariant(subkeyElement.text()).toLongLong();
214
case QVariant::ULongLong :
215
value_ = QVariant(subkeyElement.text()).toULongLong();
219
QgsDebugMsg( QString( "unsupported value type %1 .. not propertly translated to QVariant" ).arg( typeString ) );
305
224
} // QgsPropertyValue::readXML
309
228
@param element created by parent QgsPropertyKey
311
bool QgsPropertyValue::writeXML( QString const & nodeName,
312
QDomElement & keyElement,
230
bool QgsPropertyValue::writeXML( QString const & nodeName,
231
QDomElement & keyElement,
313
232
QDomDocument & document )
315
QDomElement valueElement = document.createElement( nodeName );
317
// remember the type so that we can rebuild it when the project is read in
318
valueElement.setAttribute( "type", value_.typeName() );
321
// we handle string lists differently from other types in that we
322
// create a sequence of repeated elements to cover all the string list
323
// members; each value will be in a <value></value> tag.
324
// XXX Not the most elegant way to handle string lists?
325
if ( QVariant::StringList == value_.type() )
327
QStringList sl = value_.asStringList();
329
for ( QStringList::iterator i = sl.begin();
333
QDomElement stringListElement = document.createElement( "value" );
334
QDomText valueText = document.createTextNode( *i );
335
stringListElement.appendChild( valueText );
337
valueElement.appendChild( stringListElement );
340
else // we just plop the value in as plain ole text
342
QDomText valueText = document.createTextNode( value_.toString() );
343
valueElement.appendChild( valueText );
346
keyElement.appendChild( valueElement );
234
QDomElement valueElement = document.createElement( nodeName );
236
// remember the type so that we can rebuild it when the project is read in
237
valueElement.setAttribute( "type", value_.typeName() );
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() )
246
QStringList sl = value_.toStringList();
248
for ( QStringList::iterator i = sl.begin();
252
QDomElement stringListElement = document.createElement( "value" );
253
QDomText valueText = document.createTextNode( *i );
254
stringListElement.appendChild( valueText );
256
valueElement.appendChild( stringListElement );
259
else // we just plop the value in as plain ole text
261
QDomText valueText = document.createTextNode( value_.toString() );
262
valueElement.appendChild( valueText );
265
keyElement.appendChild( valueElement );
349
268
} // QgsPropertyValue::writeXML
354
273
QgsPropertyKey::QgsPropertyKey( QString const name )
277
QgsPropertyKey::~QgsPropertyKey()
357
// since we own our properties, we are responsible for deleting the
359
properties_.setAutoDelete(true);
362
282
QVariant QgsPropertyKey::value() const
364
QgsProperty * foundQgsProperty;
366
if ( 0 == ( foundQgsProperty = properties_.find( name()) ) )
367
{ // recurse down to next key
368
return foundQgsProperty->value();
371
qDebug("%s:%d QgsPropertyKey has null child", __FILE__, __LINE__);
373
return QVariant(); // just return an QVariant::Invalid
375
} // QVariant QgsPropertyKey::value()
284
QgsProperty * foundQgsProperty;
286
if ( 0 == ( foundQgsProperty = mProperties.value( name() ) ) )
287
{ // recurse down to next key
288
return foundQgsProperty->value();
292
QgsDebugMsg( "key has null child" );
294
return QVariant(); // just return an QVariant::Invalid
296
} // QVariant QgsPropertyKey::value()
378
299
void QgsPropertyKey::dump( size_t tabs ) const
382
tabString.fill( '\t', tabs );
384
qDebug( "%sname: %s", tabString.toLocal8Bit().data(), name().toLocal8Bit().data() );
387
tabString.fill( '\t', tabs );
389
if ( ! properties_.isEmpty() )
303
tabString.fill( '\t', tabs );
305
QgsDebugMsg( QString( "%1name: %2" ).arg( tabString ).arg( name() ) );
308
tabString.fill( '\t', tabs );
310
if ( ! mProperties.isEmpty() )
312
QHashIterator < QString, QgsProperty* > i( mProperties );
313
while ( i.hasNext() )
391
for (Q3DictIterator < QgsProperty > i(properties_); i.current(); ++i)
393
if ( i.current()->isValue() )
395
QgsPropertyValue * propertyValue =
396
dynamic_cast<QgsPropertyValue*>( i.current() );
398
if ( QVariant::StringList == propertyValue->value().type() )
400
qDebug("%skey: <%s> value:",
401
tabString.toLocal8Bit().data(),
402
i.currentKey().toLocal8Bit().data() );
404
propertyValue->dump( tabs + 1 );
408
qDebug("%skey: <%s> value: %s",
409
tabString.toLocal8Bit().data(),
410
i.currentKey().toLocal8Bit().data(),
411
propertyValue->value().toString().toLocal8Bit().data() );
416
qDebug("%skey: <%s> subkey: <%s>",
417
tabString.toLocal8Bit().data(),
418
i.currentKey().toLocal8Bit().data(),
419
dynamic_cast<QgsPropertyKey*>(i.current())->name().toLocal8Bit().data() );
421
i.current()->dump( tabs + 1 );
424
// qDebug("<%s>", (const char *) name().utf8());
425
// if ( i.current()->isValue() )
427
// qDebug(" <%s>", (const char*) i.currentKey().utf8() );
429
// i.current()->dump();
430
// if ( i.current()->isValue() )
432
// qDebug(" </%s>", (const char*) i.currentKey().utf8() );
434
// qDebug("</%s>", (const char *) name().utf8());
315
if ( i.next().value()->isValue() )
317
QgsPropertyValue * propertyValue =
318
dynamic_cast<QgsPropertyValue*>( i.value() );
320
if ( QVariant::StringList == propertyValue->value().type() )
322
QgsDebugMsg( QString( "%1key: <%2> value:" ).arg( tabString ).arg( i.key() ) );
323
propertyValue->dump( tabs + 1 );
327
QgsDebugMsg( QString( "%1key: <%2> value: %3" ).arg( tabString ).arg( i.key() ).arg( propertyValue->value().toString() ) );
332
QgsDebugMsg( QString( "%1key: <%2> subkey: <%3>" )
335
.arg( dynamic_cast<QgsPropertyKey*>( i.value() )->name() ) );
336
i.value()->dump( tabs + 1 );
339
// qDebug("<%s>", name().toUtf8().constData());
340
// if ( i.value()->isValue() )
342
// qDebug(" <%s>", i.key().toUtf8().constData() );
344
// i.value()->dump();
345
// if ( i.value()->isValue() )
347
// qDebug(" </%s>", i.key().toUtf8().constData() );
349
// qDebug("</%s>", name().toUtf8().constData());
438
353
} // QgsPropertyKey::dump
442
bool QgsPropertyKey::readXML(QDomNode & keyNode)
357
bool QgsPropertyKey::readXML( QDomNode & keyNode )
445
QDomNodeList subkeys = keyNode.childNodes();
447
while (i < subkeys.count())
360
QDomNodeList subkeys = keyNode.childNodes();
362
while ( i < subkeys.count() )
364
// if the current node is an element that has a "type" attribute,
365
// then we know it's a leaf node; i.e., a subkey _value_, and not
367
if ( subkeys.item( i ).hasAttributes() && // if we have attributes
368
subkeys.item( i ).isElement() && // and we're an element
369
subkeys.item( i ).toElement().hasAttribute( "type" ) ) // and we have a "type" attribute
370
{ // then we're a key value
371
delete mProperties.take( subkeys.item( i ).nodeName() );
372
mProperties.insert( subkeys.item( i ).nodeName(), new QgsPropertyValue );
374
QDomNode subkey = subkeys.item( i );
376
if ( !mProperties[subkeys.item( i ).nodeName()]->readXML( subkey ) )
378
QgsDebugMsg( QString( "unable to parse key value %1" ).arg( subkeys.item( i ).nodeName() ) );
381
else // otherwise it's a subkey, so just
382
// recurse on down the remaining keys
449
// if the current node is an element that has a "type" attribute,
450
// then we know it's a leaf node; i.e., a subkey _value_, and not
452
if (subkeys.item(i).hasAttributes() && // if we have attributes
453
subkeys.item(i).isElement() && // and we're an element
454
subkeys.item(i).toElement().hasAttribute("type")) // and we have a "type" attribute
455
{ // then we're a key value
456
properties_.replace(subkeys.item(i).nodeName(), new QgsPropertyValue);
458
QDomNode subkey = subkeys.item(i);
460
if (!properties_[subkeys.item(i).nodeName()]->readXML(subkey))
462
qDebug("%s:%d unable to parse key value %s", __FILE__, __LINE__,
463
(const char *) subkeys.item(i).nodeName().utf8());
465
} else // otherwise it's a subkey, so just
466
// recurse on down the remaining keys
468
addKey( subkeys.item(i).nodeName() );
470
QDomNode subkey = subkeys.item(i);
472
if (!properties_[subkeys.item(i).nodeName()]->readXML(subkey))
474
qDebug("%s:%d unable to parse subkey %s", __FILE__, __LINE__,
475
(const char *) subkeys.item(i).nodeName().utf8());
384
addKey( subkeys.item( i ).nodeName() );
386
QDomNode subkey = subkeys.item( i );
388
if ( !mProperties[subkeys.item( i ).nodeName()]->readXML( subkey ) )
390
QgsDebugMsg( QString( "unable to parse subkey %1" ).arg( subkeys.item( i ).nodeName() ) );
483
398
} // QgsPropertyKey::readXML(QDomNode & keyNode)
487
Property keys will always create a DOM element for itself and then
402
Property keys will always create a Dom element for itself and then
488
403
recursively call writeXML for any constituent properties.
490
bool QgsPropertyKey::writeXML(QString const &nodeName, QDomElement & element, QDomDocument & document)
405
bool QgsPropertyKey::writeXML( QString const &nodeName, QDomElement & element, QDomDocument & document )
492
// If it's an _empty_ node (i.e., one with no properties) we need to emit
493
// an empty place holder; else create new DOM elements as necessary.
495
QDomElement keyElement = document.createElement(nodeName); // DOM element for this property key
497
if ( ! properties_.isEmpty() )
407
// If it's an _empty_ node (i.e., one with no properties) we need to emit
408
// an empty place holder; else create new Dom elements as necessary.
410
QDomElement keyElement = document.createElement( nodeName ); // Dom element for this property key
412
if ( ! mProperties.isEmpty() )
414
QHashIterator < QString, QgsProperty* > i( mProperties );
415
while ( i.hasNext() )
499
for (Q3DictIterator < QgsProperty > i(properties_); i.current(); ++i)
501
if (!i.current()->writeXML(i.currentKey(), keyElement, document))
418
if ( !i.value()->writeXML( i.key(), keyElement, document ) )
508
element.appendChild(keyElement);
425
element.appendChild( keyElement );
511
428
} // QgsPropertyKey::writeXML
515
432
/** return keys that do not contain other keys
517
434
void QgsPropertyKey::entryList( QStringList & entries ) const
519
// now add any leaf nodes to the entries list
520
for (Q3DictIterator<QgsProperty> i(properties_); i.current(); ++i)
436
// now add any leaf nodes to the entries list
437
QHashIterator < QString, QgsProperty* > i( mProperties );
438
while ( i.hasNext() )
440
// add any of the nodes that have just a single value
441
if ( i.next().value()->isLeaf() )
522
// add any of the nodes that have just a single value
523
if (i.current()->isLeaf())
525
entries.append(i.currentKey());
443
entries.append( i.key() );
528
446
} // QgsPropertyKey::entryList
532
void QgsPropertyKey::subkeyList(QStringList & entries) const
450
void QgsPropertyKey::subkeyList( QStringList & entries ) const
534
// now add any leaf nodes to the entries list
535
for (Q3DictIterator < QgsProperty > i(properties_); i.current(); ++i)
452
// now add any leaf nodes to the entries list
453
QHashIterator < QString, QgsProperty* > i( mProperties );
454
while ( i.hasNext() )
456
// add any of the nodes that have just a single value
457
if ( !i.next().value()->isLeaf() )
537
// add any of the nodes that have just a single value
538
if (!i.current()->isLeaf())
540
entries.append(i.currentKey());
459
entries.append( i.key() );
543
462
} // QgsPropertyKey::subkeyList
546
465
bool QgsPropertyKey::isLeaf() const
552
else if (1 == count())
554
Q3DictIterator < QgsProperty > i(properties_);
556
if (i.current() && i.current()->isValue())
471
else if ( 1 == count() )
473
QHashIterator < QString, QgsProperty* > i( mProperties );
475
if ( i.hasNext() && i.next().value()->isValue() )
563
482
} // QgsPropertyKey::isLeaf