Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsproject.cpp - description 00003 ------------------- 00004 begin : February 24, 2005 00005 copyright : (C) 2005 by Mark Coletti 00006 email : mcoletti at gmail.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 00018 #include "qgsprojectproperty.h" 00019 #include "qgslogger.h" 00020 00021 #include <QDomDocument> 00022 #include <QStringList> 00023 00024 void QgsPropertyValue::dump( size_t tabs ) const 00025 { 00026 QString tabString; 00027 tabString.fill( '\t', tabs ); 00028 00029 if ( QVariant::StringList == value_.type() ) 00030 { 00031 QStringList sl = value_.toStringList(); 00032 00033 for ( QStringList::const_iterator i = sl.begin(); i != sl.end(); ++i ) 00034 { 00035 QgsDebugMsg( QString( "%1[%2] " ).arg( tabString ).arg( *i ) ); 00036 } 00037 } 00038 else 00039 { 00040 QgsDebugMsg( QString( "%1%2" ).arg( tabString ).arg( value_.toString() ) ); 00041 } 00042 } // QgsPropertyValue::dump() 00043 00044 00045 00046 bool QgsPropertyValue::readXML( QDomNode & keyNode ) 00047 { 00048 // this *should* be a Dom element node 00049 QDomElement subkeyElement = keyNode.toElement(); 00050 00051 // get the type so that we can properly parse the key value 00052 QString typeString = subkeyElement.attribute( "type" ); 00053 00054 if ( QString::null == typeString ) 00055 { 00056 QgsDebugMsg( QString( "null ``type'' attribute for %1" ).arg( keyNode.nodeName() ) ); 00057 00058 return false; 00059 } 00060 00061 // the values come in as strings; we need to restore them to their 00062 // original values *and* types 00063 value_.clear(); 00064 00065 // get the type associated with the value first 00066 QVariant::Type type = QVariant::nameToType( typeString.toLocal8Bit().constData() ); 00067 00068 // This huge switch is left-over from an earlier incarnation of 00069 // QgsProject where there was a fine level of granularity for value 00070 // types. The current interface, borrowed from QSettings, supports a 00071 // very small sub-set of these types. However, I've left all the 00072 // other types just in case the interface is expanded to include these 00073 // other types. 00074 00075 switch ( type ) 00076 { 00077 case QVariant::Invalid: 00078 QgsDebugMsg( QString( "invalid value type %1 .. " ).arg( typeString ) ); 00079 return false; 00080 00081 case QVariant::Map: 00082 QgsDebugMsg( "no support for QVariant::Map" ); 00083 return false; 00084 00085 case QVariant::List: 00086 QgsDebugMsg( "no support for QVariant::List" ); 00087 return false; 00088 00089 case QVariant::String: 00090 value_ = subkeyElement.text(); // no translating necessary 00091 break; 00092 00093 case QVariant::StringList: 00094 { 00095 int i = 0; 00096 QDomNodeList values = keyNode.childNodes(); 00097 00098 // all the QStringList values will be inside <value> elements 00099 QStringList valueStringList; 00100 00101 while ( i < values.count() ) 00102 { 00103 if ( "value" == values.item( i ).nodeName() ) 00104 { // <value>s have only one element, which contains actual string value 00105 valueStringList.append( values.item( i ).firstChild().nodeValue() ); 00106 } 00107 else 00108 { 00109 QgsDebugMsg( QString( "non <value> element ``%1'' in string list" ).arg( values.item( i ).nodeName() ) ); 00110 } 00111 00112 ++i; 00113 } 00114 00115 value_ = valueStringList; 00116 break; 00117 } 00118 00119 case QVariant::Font: 00120 QgsDebugMsg( "no support for QVariant::Font" ); 00121 return false; 00122 00123 case QVariant::Pixmap: 00124 QgsDebugMsg( "no support for QVariant::Pixmap" ); 00125 return false; 00126 00127 case QVariant::Brush: 00128 QgsDebugMsg( "no support for QVariant::Brush" ); 00129 return false; 00130 00131 case QVariant::Rect: 00132 QgsDebugMsg( "no support for QVariant::Rect" ); 00133 return false; 00134 00135 case QVariant::Size: 00136 QgsDebugMsg( "no support for QVariant::Size" ); 00137 return false; 00138 00139 case QVariant::Color: 00140 QgsDebugMsg( "no support for QVariant::Color" ); 00141 return false; 00142 00143 case QVariant::Palette: 00144 QgsDebugMsg( "no support for QVariant::Palette" ); 00145 return false; 00146 00147 case QVariant::Point: 00148 QgsDebugMsg( "no support for QVariant::Point" ); 00149 return false; 00150 00151 case QVariant::Image: 00152 QgsDebugMsg( "no support for QVariant::Image" ); 00153 return false; 00154 00155 case QVariant::Int: 00156 value_ = QVariant( subkeyElement.text() ).toInt(); 00157 break; 00158 00159 case QVariant::UInt: 00160 value_ = QVariant( subkeyElement.text() ).toUInt(); 00161 break; 00162 00163 case QVariant::Bool: 00164 value_ = QVariant( subkeyElement.text() ).toBool(); 00165 break; 00166 00167 case QVariant::Double: 00168 value_ = QVariant( subkeyElement.text() ).toDouble(); 00169 break; 00170 00171 case QVariant::ByteArray: 00172 value_ = QVariant( subkeyElement.text() ).toByteArray(); 00173 break; 00174 00175 case QVariant::Polygon: 00176 QgsDebugMsg( "no support for QVariant::Polygon" ); 00177 return false; 00178 00179 case QVariant::Region: 00180 QgsDebugMsg( "no support for QVariant::Region" ); 00181 return false; 00182 00183 case QVariant::Bitmap: 00184 QgsDebugMsg( "no support for QVariant::Bitmap" ); 00185 return false; 00186 00187 case QVariant::Cursor: 00188 QgsDebugMsg( "no support for QVariant::Cursor" ); 00189 return false; 00190 00191 case QVariant::BitArray : 00192 QgsDebugMsg( "no support for QVariant::BitArray" ); 00193 return false; 00194 00195 case QVariant::KeySequence : 00196 QgsDebugMsg( "no support for QVariant::KeySequence" ); 00197 return false; 00198 00199 case QVariant::Pen : 00200 QgsDebugMsg( "no support for QVariant::Pen" ); 00201 return false; 00202 00203 // 00204 // QGIS DIES NOT SUPPORT THESE VARIANT TYPES IN VERSION 3.1 DISABLING FOR NOW 00205 // 00206 /* 00207 case QVariant::LongLong : 00208 value_ = QVariant(subkeyElement.text()).toLongLong(); 00209 break; 00210 00211 case QVariant::ULongLong : 00212 value_ = QVariant(subkeyElement.text()).toULongLong(); 00213 break; 00214 */ 00215 default : 00216 QgsDebugMsg( QString( "unsupported value type %1 .. not propertly translated to QVariant" ).arg( typeString ) ); 00217 } 00218 00219 return true; 00220 00221 } // QgsPropertyValue::readXML 00222 00223 00227 bool QgsPropertyValue::writeXML( QString const & nodeName, 00228 QDomElement & keyElement, 00229 QDomDocument & document ) 00230 { 00231 QDomElement valueElement = document.createElement( nodeName ); 00232 00233 // remember the type so that we can rebuild it when the project is read in 00234 valueElement.setAttribute( "type", value_.typeName() ); 00235 00236 00237 // we handle string lists differently from other types in that we 00238 // create a sequence of repeated elements to cover all the string list 00239 // members; each value will be in a <value></value> tag. 00240 // XXX Not the most elegant way to handle string lists? 00241 if ( QVariant::StringList == value_.type() ) 00242 { 00243 QStringList sl = value_.toStringList(); 00244 00245 for ( QStringList::iterator i = sl.begin(); 00246 i != sl.end(); 00247 ++i ) 00248 { 00249 QDomElement stringListElement = document.createElement( "value" ); 00250 QDomText valueText = document.createTextNode( *i ); 00251 stringListElement.appendChild( valueText ); 00252 00253 valueElement.appendChild( stringListElement ); 00254 } 00255 } 00256 else // we just plop the value in as plain ole text 00257 { 00258 QDomText valueText = document.createTextNode( value_.toString() ); 00259 valueElement.appendChild( valueText ); 00260 } 00261 00262 keyElement.appendChild( valueElement ); 00263 00264 return true; 00265 } // QgsPropertyValue::writeXML 00266 00267 00268 00269 00270 QgsPropertyKey::QgsPropertyKey( QString const name ) 00271 : mName( name ) 00272 {} 00273 00274 QgsPropertyKey::~QgsPropertyKey() 00275 { 00276 clearKeys(); 00277 } 00278 00279 QVariant QgsPropertyKey::value() const 00280 { 00281 QgsProperty *foundQgsProperty = mProperties.value( name() ); 00282 00283 if ( !foundQgsProperty ) 00284 { 00285 QgsDebugMsg( "key has null child" ); 00286 return QVariant(); // just return an QVariant::Invalid 00287 } 00288 00289 return foundQgsProperty->value(); 00290 } // QVariant QgsPropertyKey::value() 00291 00292 00293 void QgsPropertyKey::dump( size_t tabs ) const 00294 { 00295 QString tabString; 00296 00297 tabString.fill( '\t', tabs ); 00298 00299 QgsDebugMsg( QString( "%1name: %2" ).arg( tabString ).arg( name() ) ); 00300 00301 tabs++; 00302 tabString.fill( '\t', tabs ); 00303 00304 if ( ! mProperties.isEmpty() ) 00305 { 00306 QHashIterator < QString, QgsProperty* > i( mProperties ); 00307 while ( i.hasNext() ) 00308 { 00309 if ( i.next().value()->isValue() ) 00310 { 00311 QgsPropertyValue * propertyValue = 00312 dynamic_cast<QgsPropertyValue*>( i.value() ); 00313 00314 if ( QVariant::StringList == propertyValue->value().type() ) 00315 { 00316 QgsDebugMsg( QString( "%1key: <%2> value:" ).arg( tabString ).arg( i.key() ) ); 00317 propertyValue->dump( tabs + 1 ); 00318 } 00319 else 00320 { 00321 QgsDebugMsg( QString( "%1key: <%2> value: %3" ).arg( tabString ).arg( i.key() ).arg( propertyValue->value().toString() ) ); 00322 } 00323 } 00324 else 00325 { 00326 QgsDebugMsg( QString( "%1key: <%2> subkey: <%3>" ) 00327 .arg( tabString ) 00328 .arg( i.key() ) 00329 .arg( dynamic_cast<QgsPropertyKey*>( i.value() )->name() ) ); 00330 i.value()->dump( tabs + 1 ); 00331 } 00332 00333 // qDebug("<%s>", name().toUtf8().constData()); 00334 // if ( i.value()->isValue() ) 00335 // { 00336 // qDebug(" <%s>", i.key().toUtf8().constData() ); 00337 // } 00338 // i.value()->dump(); 00339 // if ( i.value()->isValue() ) 00340 // { 00341 // qDebug(" </%s>", i.key().toUtf8().constData() ); 00342 // } 00343 // qDebug("</%s>", name().toUtf8().constData()); 00344 } 00345 } 00346 00347 } // QgsPropertyKey::dump 00348 00349 00350 00351 bool QgsPropertyKey::readXML( QDomNode & keyNode ) 00352 { 00353 int i = 0; 00354 QDomNodeList subkeys = keyNode.childNodes(); 00355 00356 while ( i < subkeys.count() ) 00357 { 00358 // if the current node is an element that has a "type" attribute, 00359 // then we know it's a leaf node; i.e., a subkey _value_, and not 00360 // a subkey 00361 if ( subkeys.item( i ).hasAttributes() && // if we have attributes 00362 subkeys.item( i ).isElement() && // and we're an element 00363 subkeys.item( i ).toElement().hasAttribute( "type" ) ) // and we have a "type" attribute 00364 { // then we're a key value 00365 delete mProperties.take( subkeys.item( i ).nodeName() ); 00366 mProperties.insert( subkeys.item( i ).nodeName(), new QgsPropertyValue ); 00367 00368 QDomNode subkey = subkeys.item( i ); 00369 00370 if ( !mProperties[subkeys.item( i ).nodeName()]->readXML( subkey ) ) 00371 { 00372 QgsDebugMsg( QString( "unable to parse key value %1" ).arg( subkeys.item( i ).nodeName() ) ); 00373 } 00374 } 00375 else // otherwise it's a subkey, so just 00376 // recurse on down the remaining keys 00377 { 00378 addKey( subkeys.item( i ).nodeName() ); 00379 00380 QDomNode subkey = subkeys.item( i ); 00381 00382 if ( !mProperties[subkeys.item( i ).nodeName()]->readXML( subkey ) ) 00383 { 00384 QgsDebugMsg( QString( "unable to parse subkey %1" ).arg( subkeys.item( i ).nodeName() ) ); 00385 } 00386 } 00387 00388 ++i; 00389 } 00390 00391 return true; 00392 } // QgsPropertyKey::readXML(QDomNode & keyNode) 00393 00394 00399 bool QgsPropertyKey::writeXML( QString const &nodeName, QDomElement & element, QDomDocument & document ) 00400 { 00401 // If it's an _empty_ node (i.e., one with no properties) we need to emit 00402 // an empty place holder; else create new Dom elements as necessary. 00403 00404 QDomElement keyElement = document.createElement( nodeName ); // Dom element for this property key 00405 00406 if ( ! mProperties.isEmpty() ) 00407 { 00408 QHashIterator < QString, QgsProperty* > i( mProperties ); 00409 while ( i.hasNext() ) 00410 { 00411 i.next(); 00412 if ( !i.value()->writeXML( i.key(), keyElement, document ) ) 00413 { 00414 return false; 00415 } 00416 } 00417 } 00418 00419 element.appendChild( keyElement ); 00420 00421 return true; 00422 } // QgsPropertyKey::writeXML 00423 00424 00425 00428 void QgsPropertyKey::entryList( QStringList & entries ) const 00429 { 00430 // now add any leaf nodes to the entries list 00431 QHashIterator < QString, QgsProperty* > i( mProperties ); 00432 while ( i.hasNext() ) 00433 { 00434 // add any of the nodes that have just a single value 00435 if ( i.next().value()->isLeaf() ) 00436 { 00437 entries.append( i.key() ); 00438 } 00439 } 00440 } // QgsPropertyKey::entryList 00441 00442 00443 00444 void QgsPropertyKey::subkeyList( QStringList & entries ) const 00445 { 00446 // now add any leaf nodes to the entries list 00447 QHashIterator < QString, QgsProperty* > i( mProperties ); 00448 while ( i.hasNext() ) 00449 { 00450 // add any of the nodes that have just a single value 00451 if ( !i.next().value()->isLeaf() ) 00452 { 00453 entries.append( i.key() ); 00454 } 00455 } 00456 } // QgsPropertyKey::subkeyList 00457 00458 00459 bool QgsPropertyKey::isLeaf() const 00460 { 00461 if ( 0 == count() ) 00462 { 00463 return true; 00464 } 00465 else if ( 1 == count() ) 00466 { 00467 QHashIterator < QString, QgsProperty* > i( mProperties ); 00468 00469 if ( i.hasNext() && i.next().value()->isValue() ) 00470 { 00471 return true; 00472 } 00473 } 00474 00475 return false; 00476 } // QgsPropertyKey::isLeaf