00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "qgsproject.h"
00019
00020 #include <deque>
00021 #include <memory>
00022
00023 #include "qgslogger.h"
00024 #include "qgsrectangle.h"
00025 #include "qgsvectorlayer.h"
00026 #include "qgsrasterlayer.h"
00027 #include "qgsmaplayerregistry.h"
00028 #include "qgsexception.h"
00029 #include "qgsprojectproperty.h"
00030 #include "qgslogger.h"
00031 #include "qgsprojectfiletransform.h"
00032 #include "qgsprojectversion.h"
00033 #include "qgspluginlayer.h"
00034 #include "qgspluginlayerregistry.h"
00035
00036 #include <QApplication>
00037 #include <QFileInfo>
00038 #include <QDomNode>
00039 #include <QObject>
00040 #include <QTextStream>
00041
00042
00043 static const char *const ident_ = "$Id$";
00044
00045
00046 QgsProject * QgsProject::theProject_;
00047
00056 static
00057 QStringList makeKeyTokens_( QString const &scope, QString const &key )
00058 {
00059
00060
00061
00062
00063 QStringList keyTokens = QStringList( scope );
00064 keyTokens += key.split( '/', QString::SkipEmptyParts );
00065
00066
00067 keyTokens.push_front( "properties" );
00068
00069 return keyTokens;
00070 }
00071
00072
00073
00074
00084 static
00085 QgsProperty * findKey_( QString const & scope,
00086 QString const & key,
00087 QgsPropertyKey & rootProperty )
00088 {
00089 QgsPropertyKey * currentProperty = &rootProperty;
00090 QgsProperty * nextProperty;
00091
00092 QStringList keySequence = makeKeyTokens_( scope, key );
00093
00094 while ( ! keySequence.isEmpty() )
00095 {
00096
00097
00098 if ( keySequence.first() == currentProperty->name() )
00099 {
00100
00101 keySequence.pop_front();
00102
00103
00104 if ( 1 == keySequence.count() )
00105 {
00106 return currentProperty->find( keySequence.front() );
00107
00108 }
00109
00110
00111
00112 else if ( keySequence.isEmpty() )
00113 {
00114 return currentProperty;
00115 }
00116 else if (( nextProperty = currentProperty->find( keySequence.first() ) ) )
00117 {
00118 if ( nextProperty->isKey() )
00119 {
00120 currentProperty = dynamic_cast<QgsPropertyKey*>( nextProperty );
00121 }
00122
00123
00124
00125
00126 else if ( nextProperty->isValue() && ( 1 == keySequence.count() ) )
00127 {
00128 return currentProperty;
00129 }
00130 else
00131 {
00132 return 0x0;
00133 }
00134 }
00135 else
00136 {
00137 return 0x0;
00138 }
00139 }
00140 else
00141 {
00142 return 0x0;
00143 }
00144 }
00145
00146 return 0x0;
00147 }
00148
00149
00150
00158 static
00159 QgsProperty * addKey_( QString const & scope,
00160 QString const & key,
00161 QgsPropertyKey * rootProperty,
00162 QVariant value )
00163 {
00164 QStringList keySequence = makeKeyTokens_( scope, key );
00165
00166
00167 QgsPropertyKey * currentProperty = rootProperty;
00168
00169 QgsProperty * newProperty;
00170
00171 while ( ! keySequence.isEmpty() )
00172 {
00173
00174
00175 if ( keySequence.first() == currentProperty->name() )
00176 {
00177
00178 keySequence.pop_front();
00179
00180
00181
00182 if ( 1 == keySequence.count() )
00183 {
00184 currentProperty->setValue( keySequence.front(), value );
00185 return currentProperty;
00186 }
00187
00188
00189 else if ( keySequence.isEmpty() )
00190 {
00191 currentProperty->setValue( value );
00192
00193 return currentProperty;
00194 }
00195 else if (( newProperty = currentProperty->find( keySequence.first() ) ) )
00196 {
00197 currentProperty = dynamic_cast<QgsPropertyKey*>( newProperty );
00198
00199 if ( currentProperty )
00200 {
00201 continue;
00202 }
00203 else
00204 {
00205 return 0x0;
00206 }
00207 }
00208 else
00209 {
00210 newProperty = currentProperty->addKey( keySequence.first() );
00211
00212 if ( newProperty )
00213 {
00214 currentProperty = dynamic_cast<QgsPropertyKey*>( newProperty );
00215 }
00216 continue;
00217 }
00218 }
00219 else
00220 {
00221 return 0x0;
00222 }
00223 }
00224
00225 return 0x0;
00226
00227 }
00228
00229
00230
00231 static
00232 void removeKey_( QString const & scope,
00233 QString const & key,
00234 QgsPropertyKey & rootProperty )
00235 {
00236 QgsPropertyKey * currentProperty = &rootProperty;
00237
00238 QgsProperty * nextProperty = NULL;
00239 QgsPropertyKey * previousQgsPropertyKey = NULL;
00240
00241 QStringList keySequence = makeKeyTokens_( scope, key );
00242
00243 while ( ! keySequence.isEmpty() )
00244 {
00245
00246
00247 if ( keySequence.first() == currentProperty->name() )
00248 {
00249
00250 keySequence.pop_front();
00251
00252
00253
00254 if ( 1 == keySequence.count() )
00255 {
00256 currentProperty->removeKey( keySequence.front() );
00257 }
00258
00259
00260
00261 else if ( keySequence.isEmpty() )
00262 {
00263 previousQgsPropertyKey->removeKey( currentProperty->name() );
00264 }
00265 else if (( nextProperty = currentProperty->find( keySequence.first() ) ) )
00266 {
00267 previousQgsPropertyKey = currentProperty;
00268 currentProperty = dynamic_cast<QgsPropertyKey*>( nextProperty );
00269
00270 if ( currentProperty )
00271 {
00272 continue;
00273 }
00274 else
00275 {
00276 return;
00277 }
00278 }
00279 else
00280 {
00281 return;
00282 }
00283 }
00284 else
00285 {
00286 return;
00287 }
00288 }
00289
00290 }
00291
00292
00293
00294 struct QgsProject::Imp
00295 {
00297 QFile file;
00298
00300 QgsPropertyKey properties_;
00301
00303 QString title;
00304
00306 bool dirty;
00307
00308 Imp()
00309 : title( "" ),
00310 dirty( false )
00311 {
00312
00313
00314 properties_.name() = "properties";
00315 }
00316
00319 void clear()
00320 {
00321
00322
00323 properties_.clearKeys();
00324 title = "";
00325
00326
00327
00328 QgsProject::instance()->writeEntry( "PositionPrecision", "/Automatic", true );
00329 QgsProject::instance()->writeEntry( "PositionPrecision", "/DecimalPlaces", 2 );
00330 }
00331
00332 };
00333
00334
00335
00336 QgsProject::QgsProject()
00337 : imp_( new QgsProject::Imp ), mBadLayerHandler( new QgsProjectBadLayerDefaultHandler() )
00338 {
00339
00340
00341 writeEntry( "PositionPrecision", "/Automatic", true );
00342 writeEntry( "PositionPrecision", "/DecimalPlaces", 2 );
00343
00344
00345 dirty( false );
00346 }
00347
00348
00349
00350 QgsProject::~QgsProject()
00351 {
00352 delete mBadLayerHandler;
00353
00354
00355 }
00356
00357
00358
00359 QgsProject * QgsProject::instance()
00360 {
00361 if ( !QgsProject::theProject_ )
00362 {
00363 QgsProject::theProject_ = new QgsProject;
00364 }
00365
00366 return QgsProject::theProject_;
00367 }
00368
00369
00370
00371
00372 void QgsProject::title( QString const &title )
00373 {
00374 imp_->title = title;
00375
00376 dirty( true );
00377 }
00378
00379
00380 QString const & QgsProject::title() const
00381 {
00382 return imp_->title;
00383 }
00384
00385
00386 bool QgsProject::isDirty() const
00387 {
00388 return imp_->dirty;
00389 }
00390
00391
00392 void QgsProject::dirty( bool b )
00393 {
00394 imp_->dirty = b;
00395 }
00396
00397
00398
00399 void QgsProject::setFileName( QString const &name )
00400 {
00401 imp_->file.setFileName( name );
00402
00403 dirty( true );
00404 }
00405
00406
00407
00408 QString QgsProject::fileName() const
00409 {
00410 return imp_->file.fileName();
00411 }
00412
00413
00414
00416 static void dump_( QgsPropertyKey const & topQgsPropertyKey )
00417 {
00418 QgsDebugMsg( "current properties:" );
00419
00420 topQgsPropertyKey.dump();
00421 }
00422
00423
00424
00425
00456 static
00457 void
00458 _getProperties( QDomDocument const &doc, QgsPropertyKey & project_properties )
00459 {
00460 QDomNodeList properties = doc.elementsByTagName( "properties" );
00461
00462 if ( properties.count() > 1 )
00463 {
00464 QgsDebugMsg( "there appears to be more than one ``properties'' XML tag ... bailing" );
00465 return;
00466 }
00467 else if ( properties.count() < 1 )
00468 {
00469 return;
00470 }
00471
00472
00473
00474 QDomNodeList scopes = properties.item( 0 ).childNodes();
00475
00476 if ( scopes.count() < 1 )
00477 {
00478 QgsDebugMsg( "empty ``properties'' XML tag ... bailing" );
00479 return;
00480 }
00481
00482 QDomNode propertyNode = properties.item( 0 );
00483
00484 if ( ! project_properties.readXML( propertyNode ) )
00485 {
00486 QgsDebugMsg( "Project_properties.readXML() failed" );
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 }
00527
00528
00529
00530
00542 static void _getTitle( QDomDocument const &doc, QString & title )
00543 {
00544 QDomNodeList nl = doc.elementsByTagName( "title" );
00545
00546 title = "";
00547
00548 if ( !nl.count() )
00549 {
00550 QgsDebugMsg( "unable to find title element" );
00551 return;
00552 }
00553
00554 QDomNode titleNode = nl.item( 0 );
00555
00556 if ( !titleNode.hasChildNodes() )
00557 {
00558 QgsDebugMsg( "unable to find title element" );
00559 return;
00560 }
00561
00562 QDomNode titleTextNode = titleNode.firstChild();
00563
00564 if ( !titleTextNode.isText() )
00565 {
00566 QgsDebugMsg( "unable to find title element" );
00567 return;
00568 }
00569
00570 QDomText titleText = titleTextNode.toText();
00571
00572 title = titleText.data();
00573
00574 }
00575
00576
00581 static QgsProjectVersion _getVersion( QDomDocument const &doc )
00582 {
00583 QDomNodeList nl = doc.elementsByTagName( "qgis" );
00584
00585 if ( !nl.count() )
00586 {
00587 QgsDebugMsg( " unable to find qgis element in project file" );
00588 return QgsProjectVersion( 0, 0, 0, QString( "" ) );
00589 }
00590
00591 QDomNode qgisNode = nl.item( 0 );
00592
00593 QDomElement qgisElement = qgisNode.toElement();
00594 QgsProjectVersion projectVersion( qgisElement.attribute( "version" ) );
00595 return projectVersion;
00596 }
00597
00598
00599
00647 QPair< bool, QList<QDomNode> > QgsProject::_getMapLayers( QDomDocument const &doc )
00648 {
00649
00650
00651
00652 QDomNodeList nl = doc.elementsByTagName( "maplayer" );
00653
00654
00655
00656 QString wk;
00657
00658 QList<QDomNode> brokenNodes;
00659
00660
00661
00662
00663
00664
00665 if ( 0 == nl.count() )
00666 {
00667 return qMakePair( true, brokenNodes );
00668
00669
00670
00671
00672
00673 }
00674
00675 bool returnStatus = true;
00676
00677 emit layerLoaded( 0, nl.count() );
00678
00679 for ( int i = 0; i < nl.count(); i++ )
00680 {
00681 QDomNode node = nl.item( i );
00682 QDomElement element = node.toElement();
00683
00684 QString type = element.attribute( "type" );
00685
00686 QgsDebugMsg( "Layer type is " + type );
00687
00688 QgsMapLayer *mapLayer = NULL;
00689
00690 if ( type == "vector" )
00691 {
00692 mapLayer = new QgsVectorLayer;
00693 }
00694 else if ( type == "raster" )
00695 {
00696 mapLayer = new QgsRasterLayer;
00697 }
00698 else if ( type == "plugin" )
00699 {
00700 QString typeName = element.attribute( "name" );
00701 mapLayer = QgsPluginLayerRegistry::instance()->createLayer( typeName );
00702 }
00703
00704 Q_CHECK_PTR( mapLayer );
00705
00706 if ( !mapLayer )
00707 {
00708 QgsDebugMsg( "Unable to create layer" );
00709
00710 return qMakePair( false, brokenNodes );
00711 }
00712
00713
00714 if ( mapLayer->readXML( node ) )
00715 {
00716 mapLayer = QgsMapLayerRegistry::instance()->addMapLayer( mapLayer );
00717 }
00718 else
00719 {
00720 delete mapLayer;
00721
00722 QgsDebugMsg( "Unable to load " + type + " layer" );
00723
00724 returnStatus = false;
00725
00726 brokenNodes.push_back( node );
00727 }
00728
00729 emit layerLoaded( i + 1, nl.count() );
00730 }
00731
00732 return qMakePair( returnStatus, brokenNodes );
00733
00734 }
00735
00736
00737
00738
00742 bool QgsProject::read( QFileInfo const &file )
00743 {
00744 imp_->file.setFileName( file.filePath() );
00745
00746 return read();
00747 }
00748
00749
00750
00751
00752
00753
00754 bool QgsProject::read()
00755 {
00756 clearError();
00757
00758 std::auto_ptr< QDomDocument > doc =
00759 std::auto_ptr < QDomDocument > ( new QDomDocument( "qgis" ) );
00760
00761 if ( !imp_->file.open( QIODevice::ReadOnly ) )
00762 {
00763 imp_->file.close();
00764
00765 setError( tr( "Unable to open %1" ).arg( imp_->file.fileName() ) );
00766
00767 return false;
00768 }
00769
00770
00771 int line, column;
00772 QString errorMsg;
00773
00774 if ( !doc->setContent( &imp_->file, &errorMsg, &line, &column ) )
00775 {
00776
00777 #if 0
00778 QMessageBox::critical( 0, tr( "Project File Read Error" ),
00779 tr( "%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
00780 #endif
00781
00782 QString errorString = tr( "Project file read error: %1 at line %2 column %3" )
00783 .arg( errorMsg ).arg( line ).arg( column );
00784
00785 QgsDebugMsg( errorString );
00786
00787 imp_->file.close();
00788
00789 setError( tr( "%1 for file %2" ).arg( errorString ).arg( imp_->file.fileName() ) );
00790
00791 return false;
00792 }
00793
00794 imp_->file.close();
00795
00796
00797 QgsDebugMsg( "Opened document " + imp_->file.fileName() );
00798 QgsDebugMsg( "Project title: " + imp_->title );
00799
00800
00801 QgsProjectVersion fileVersion = _getVersion( *doc );
00802 QgsProjectVersion thisVersion( QGis::QGIS_VERSION );
00803
00804 if ( thisVersion > fileVersion )
00805 {
00806 QgsLogger::warning( "Loading a file that was saved with an older "
00807 "version of qgis (saved in " + fileVersion.text() +
00808 ", loaded in " + QGis::QGIS_VERSION +
00809 "). Problems may occur." );
00810
00811 QgsProjectFileTransform projectFile( *doc, fileVersion );
00812
00814 emit oldProjectVersionWarning( fileVersion.text() );
00815 QgsDebugMsg( "Emitting oldProjectVersionWarning(oldVersion)." );
00816
00817 projectFile.dump();
00818
00819 projectFile.updateRevision( thisVersion );
00820
00821 projectFile.dump();
00822
00823 }
00824
00825
00826
00827
00828
00829 imp_->clear();
00830
00831
00832 _getProperties( *doc, imp_->properties_ );
00833
00834 QgsDebugMsg( QString::number( imp_->properties_.count() ) + " properties read" );
00835
00836 dump_( imp_->properties_ );
00837
00838
00839
00840
00841
00842 _getTitle( *doc, imp_->title );
00843
00844
00845
00846 QPair< bool, QList<QDomNode> > getMapLayersResults = _getMapLayers( *doc );
00847
00848
00849
00850 if ( ! getMapLayersResults.first )
00851 {
00852 QgsDebugMsg( "Unable to get map layers from project file." );
00853
00854 if ( ! getMapLayersResults.second.isEmpty() )
00855 {
00856 QgsDebugMsg( "there are " + QString::number( getMapLayersResults.second.size() ) + " broken layers" );
00857 }
00858
00859
00860
00861 mBadLayerHandler->handleBadLayers( getMapLayersResults.second, *doc );
00862 }
00863
00864
00865 emit readProject( *doc );
00866
00867
00868 dirty( false );
00869
00870 return true;
00871
00872 }
00873
00874
00875
00876
00877
00878 bool QgsProject::read( QDomNode & layerNode )
00879 {
00880 QString type = layerNode.toElement().attribute( "type" );
00881
00882 QgsMapLayer *mapLayer = NULL;
00883
00884 if ( type == "vector" )
00885 {
00886 mapLayer = new QgsVectorLayer;
00887 }
00888 else if ( type == "raster" )
00889 {
00890 mapLayer = new QgsRasterLayer;
00891 }
00892 else if ( type == "plugin" )
00893 {
00894 QString typeName = layerNode.toElement().attribute( "name" );
00895 mapLayer = QgsPluginLayerRegistry::instance()->createLayer( typeName );
00896 }
00897 else
00898 {
00899 QgsDebugMsg( "bad layer type" );
00900 return false;
00901 }
00902
00903 if ( !mapLayer )
00904 {
00905 QgsDebugMsg( "unable to create layer" );
00906 return false;
00907 }
00908
00909
00910 if ( mapLayer->readXML( layerNode ) )
00911 {
00912 mapLayer = QgsMapLayerRegistry::instance()->addMapLayer( mapLayer );
00913 }
00914 else
00915 {
00916 delete mapLayer;
00917
00918 QgsDebugMsg( "unable to load " + type + " layer" );
00919
00920 return false;
00921 }
00922
00923 return true;
00924 }
00925
00926
00927
00928 bool QgsProject::write( QFileInfo const &file )
00929 {
00930 imp_->file.setFileName( file.filePath() );
00931
00932 return write();
00933 }
00934
00935
00936 bool QgsProject::write()
00937 {
00938 clearError();
00939
00940
00941
00942
00943 if ( !imp_->file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
00944 {
00945 imp_->file.close();
00946
00947
00948 setError( tr( "Unable to save to file %1" ).arg( imp_->file.fileName() ) );
00949 return false;
00950 }
00951 QFileInfo myFileInfo( imp_->file );
00952 if ( !myFileInfo.isWritable() )
00953 {
00954
00955
00956 imp_->file.close();
00957 setError( tr( "%1 is not writeable. Please adjust permissions (if possible) and try again." )
00958 .arg( imp_->file.fileName() ) );
00959 return false;
00960 }
00961
00962 QDomImplementation DomImplementation;
00963
00964 QDomDocumentType documentType =
00965 DomImplementation.createDocumentType( "qgis", "http://mrcc.com/qgis.dtd",
00966 "SYSTEM" );
00967 std::auto_ptr < QDomDocument > doc =
00968 std::auto_ptr < QDomDocument > ( new QDomDocument( documentType ) );
00969
00970
00971 QDomElement qgisNode = doc->createElement( "qgis" );
00972 qgisNode.setAttribute( "projectname", title() );
00973 qgisNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) );
00974
00975 doc->appendChild( qgisNode );
00976
00977
00978 QDomElement titleNode = doc->createElement( "title" );
00979 qgisNode.appendChild( titleNode );
00980
00981 QDomText titleText = doc->createTextNode( title() );
00982 titleNode.appendChild( titleText );
00983
00984
00985 emit writeProject( *doc );
00986
00987
00988 QMap<QString, QgsMapLayer*> & layers = QgsMapLayerRegistry::instance()->mapLayers();
00989
00990
00991
00992 QDomElement projectLayersNode = doc->createElement( "projectlayers" );
00993 projectLayersNode.setAttribute( "layercount", qulonglong( layers.size() ) );
00994
00995 QMap<QString, QgsMapLayer*>::iterator li = layers.begin();
00996 while ( li != layers.end() )
00997 {
00998
00999 QgsMapLayer* ml = li.value();
01000
01001 if ( ml )
01002 {
01003 ml->writeXML( projectLayersNode, *doc );
01004 }
01005 li++;
01006 }
01007
01008 qgisNode.appendChild( projectLayersNode );
01009
01010
01011
01012 dump_( imp_->properties_ );
01013
01014 QgsDebugMsg( QString( "there are %1 property scopes" ).arg( static_cast<int>( imp_->properties_.count() ) ) );
01015
01016 if ( !imp_->properties_.isEmpty() )
01017
01018 {
01019 imp_->properties_.writeXML( "properties", qgisNode, *doc );
01020 }
01021
01022
01023 doc->normalize();
01024
01025
01026
01027
01028
01029
01030
01031 QTextStream projectFileStream( &imp_->file );
01032
01033
01034 doc->save( projectFileStream, 4 );
01035 imp_->file.close();
01036
01037
01038
01039
01040
01041 if ( projectFileStream.pos() == -1 || imp_->file.error() != QFile::NoError )
01042 {
01043 setError( tr( "Unable to save to file %1. Your project "
01044 "may be corrupted on disk. Try clearing some space on the volume and "
01045 "check file permissions before pressing save again." )
01046 .arg( imp_->file.fileName() ) );
01047 return false;
01048 }
01049
01050 dirty( false );
01051
01052 return true;
01053 }
01054
01055
01056
01057 void QgsProject::clearProperties()
01058 {
01059
01060
01061 imp_->clear();
01062
01063 dirty( true );
01064 }
01065
01066
01067
01068 bool
01069 QgsProject::writeEntry( QString const &scope, const QString & key, bool value )
01070 {
01071 dirty( true );
01072
01073 return addKey_( scope, key, &imp_->properties_, value );
01074 }
01075
01076
01077 bool
01078 QgsProject::writeEntry( QString const &scope, const QString & key,
01079 double value )
01080 {
01081 dirty( true );
01082
01083 return addKey_( scope, key, &imp_->properties_, value );
01084 }
01085
01086
01087 bool
01088 QgsProject::writeEntry( QString const &scope, const QString & key, int value )
01089 {
01090 dirty( true );
01091
01092 return addKey_( scope, key, &imp_->properties_, value );
01093 }
01094
01095
01096 bool
01097 QgsProject::writeEntry( QString const &scope, const QString & key,
01098 const QString & value )
01099 {
01100 dirty( true );
01101
01102 return addKey_( scope, key, &imp_->properties_, value );
01103 }
01104
01105
01106 bool
01107 QgsProject::writeEntry( QString const &scope, const QString & key,
01108 const QStringList & value )
01109 {
01110 dirty( true );
01111
01112 return addKey_( scope, key, &imp_->properties_, value );
01113 }
01114
01115
01116
01117
01118 QStringList
01119 QgsProject::readListEntry( QString const & scope,
01120 const QString & key,
01121 bool * ok ) const
01122 {
01123 QgsProperty * property = findKey_( scope, key, imp_->properties_ );
01124
01125 QVariant value;
01126
01127 if ( property )
01128 {
01129 value = property->value();
01130 }
01131
01132 bool valid = QVariant::StringList == value.type();
01133
01134 if ( ok )
01135 {
01136 *ok = valid;
01137 }
01138
01139 if ( valid )
01140 {
01141 return value.toStringList();
01142 }
01143
01144 return QStringList();
01145 }
01146
01147
01148 QString
01149 QgsProject::readEntry( QString const & scope,
01150 const QString & key,
01151 const QString & def,
01152 bool * ok ) const
01153 {
01154 QgsProperty * property = findKey_( scope, key, imp_->properties_ );
01155
01156 QVariant value;
01157
01158 if ( property )
01159 {
01160 value = property->value();
01161 }
01162
01163 bool valid = value.canConvert( QVariant::String );
01164
01165 if ( ok )
01166 {
01167 *ok = valid;
01168 }
01169
01170 if ( valid )
01171 {
01172 return value.toString();
01173 }
01174
01175 return QString( def );
01176 }
01177
01178
01179 int
01180 QgsProject::readNumEntry( QString const &scope, const QString & key, int def,
01181 bool * ok ) const
01182 {
01183 QgsProperty * property = findKey_( scope, key, imp_->properties_ );
01184
01185 QVariant value;
01186
01187 if ( property )
01188 {
01189 value = property->value();
01190 }
01191
01192 bool valid = value.canConvert( QVariant::String );
01193
01194 if ( ok )
01195 {
01196 *ok = valid;
01197 }
01198
01199 if ( valid )
01200 {
01201 return value.toInt();
01202 }
01203
01204 return def;
01205 }
01206
01207
01208 double
01209 QgsProject::readDoubleEntry( QString const &scope, const QString & key,
01210 double def,
01211 bool * ok ) const
01212 {
01213 QgsProperty * property = findKey_( scope, key, imp_->properties_ );
01214
01215 QVariant value;
01216
01217 if ( property )
01218 {
01219 value = property->value();
01220 }
01221
01222 bool valid = value.canConvert( QVariant::Double );
01223
01224 if ( ok )
01225 {
01226 *ok = valid;
01227 }
01228
01229 if ( valid )
01230 {
01231 return value.toDouble();
01232 }
01233
01234 return def;
01235 }
01236
01237
01238 bool
01239 QgsProject::readBoolEntry( QString const &scope, const QString & key, bool def,
01240 bool * ok ) const
01241 {
01242 QgsProperty * property = findKey_( scope, key, imp_->properties_ );
01243
01244 QVariant value;
01245
01246 if ( property )
01247 {
01248 value = property->value();
01249 }
01250
01251 bool valid = value.canConvert( QVariant::Bool );
01252
01253 if ( ok )
01254 {
01255 *ok = valid;
01256 }
01257
01258 if ( valid )
01259 {
01260 return value.toBool();
01261 }
01262
01263 return def;
01264 }
01265
01266
01267 bool QgsProject::removeEntry( QString const &scope, const QString & key )
01268 {
01269 removeKey_( scope, key, imp_->properties_ );
01270
01271 dirty( true );
01272
01273 return ! findKey_( scope, key, imp_->properties_ );
01274 }
01275
01276
01277
01278 QStringList QgsProject::entryList( QString const &scope, QString const &key ) const
01279 {
01280 QgsProperty * foundProperty = findKey_( scope, key, imp_->properties_ );
01281
01282 QStringList entries;
01283
01284 if ( foundProperty )
01285 {
01286 QgsPropertyKey * propertyKey = dynamic_cast<QgsPropertyKey*>( foundProperty );
01287
01288 if ( propertyKey )
01289 { propertyKey->entryList( entries ); }
01290 }
01291
01292 return entries;
01293 }
01294
01295
01296 QStringList
01297 QgsProject::subkeyList( QString const &scope, QString const &key ) const
01298 {
01299 QgsProperty * foundProperty = findKey_( scope, key, imp_->properties_ );
01300
01301 QStringList entries;
01302
01303 if ( foundProperty )
01304 {
01305 QgsPropertyKey * propertyKey = dynamic_cast<QgsPropertyKey*>( foundProperty );
01306
01307 if ( propertyKey )
01308 { propertyKey->subkeyList( entries ); }
01309 }
01310
01311 return entries;
01312
01313 }
01314
01315
01316
01317 void QgsProject::dumpProperties() const
01318 {
01319 dump_( imp_->properties_ );
01320 }
01321
01322
01323
01324 QString QgsProject::readPath( QString src ) const
01325 {
01326 if ( readBoolEntry( "Paths", "/Absolute", true ) )
01327 {
01328 return src;
01329 }
01330
01331
01332 if ( !src.startsWith( "./" ) && !src.startsWith( "../" ) )
01333 {
01334 #if defined(Q_OS_WIN)
01335 if ( src.startsWith( "\\\\" ) ||
01336 src.startsWith( "//" ) ||
01337 ( src[0].isLetter() && src[1] == ':' ) )
01338 {
01339
01340 return src;
01341 }
01342 #else
01343 if ( src[0] == '/' )
01344 {
01345
01346 return src;
01347 }
01348 #endif
01349
01350
01351
01352
01353
01354 QFileInfo pfi( fileName() );
01355 Q_ASSERT( pfi.exists() );
01356 QFileInfo fi( pfi.canonicalPath() + "/" + src );
01357
01358 if ( !fi.exists() )
01359 {
01360 return src;
01361 }
01362 else
01363 {
01364 return fi.canonicalFilePath();
01365 }
01366 }
01367
01368 QString srcPath = src;
01369 QString projPath = fileName();
01370
01371 #if defined(Q_OS_WIN)
01372 srcPath.replace( "\\", "/" );
01373 projPath.replace( "\\", "/" );
01374
01375 bool uncPath = projPath.startsWith( "//" );
01376 #endif
01377
01378 QStringList srcElems = srcPath.split( "/", QString::SkipEmptyParts );
01379 QStringList projElems = projPath.split( "/", QString::SkipEmptyParts );
01380
01381 #if defined(Q_OS_WIN)
01382 if ( uncPath )
01383 {
01384 projElems.insert( 0, "" );
01385 projElems.insert( 0, "" );
01386 }
01387 #endif
01388
01389
01390 projElems.removeLast();
01391
01392
01393 projElems << srcElems;
01394 projElems.removeAll( "." );
01395
01396
01397 int pos;
01398 while (( pos = projElems.indexOf( ".." ) ) > 0 )
01399 {
01400
01401 projElems.removeAt( pos - 1 );
01402 projElems.removeAt( pos - 1 );
01403 }
01404
01405 #if !defined(Q_OS_WIN)
01406
01407 projElems.prepend( "" );
01408 #endif
01409
01410 return projElems.join( "/" );
01411 }
01412
01413
01414 QString QgsProject::writePath( QString src ) const
01415 {
01416 if ( readBoolEntry( "Paths", "/Absolute", true ) )
01417 {
01418 return src;
01419 }
01420
01421 QString srcPath = src;
01422 QString projPath = fileName();
01423
01424 #if defined( Q_OS_WIN )
01425 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
01426
01427 srcPath.replace( "\\", "/" );
01428
01429 if ( srcPath.startsWith( "//" ) )
01430 {
01431
01432 srcPath = "\\\\" + srcPath.mid( 2 );
01433 }
01434
01435 projPath.replace( "\\", "/" );
01436 if ( projPath.startsWith( "//" ) )
01437 {
01438
01439 projPath = "\\\\" + projPath.mid( 2 );
01440 }
01441 #else
01442 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
01443 #endif
01444
01445 QStringList projElems = projPath.split( "/", QString::SkipEmptyParts );
01446 QStringList srcElems = srcPath.split( "/", QString::SkipEmptyParts );
01447
01448
01449 projElems.removeLast();
01450
01451 projElems.removeAll( "." );
01452 srcElems.removeAll( "." );
01453
01454
01455 int n = 0;
01456 while ( srcElems.size() > 0 &&
01457 projElems.size() > 0 &&
01458 srcElems[0].compare( projElems[0], cs ) == 0 )
01459 {
01460 srcElems.removeFirst();
01461 projElems.removeFirst();
01462 n++;
01463 }
01464
01465 if ( n == 0 )
01466 {
01467
01468 return src;
01469 }
01470
01471 if ( projElems.size() > 0 )
01472 {
01473
01474 for ( int i = 0; i < projElems.size(); i++ )
01475 {
01476 srcElems.insert( 0, ".." );
01477 }
01478 }
01479 else
01480 {
01481
01482
01483 srcElems.insert( 0, "." );
01484 }
01485
01486 return srcElems.join( "/" );
01487 }
01488
01489 void QgsProject::setError( QString errorMessage )
01490 {
01491 mErrorMessage = errorMessage;
01492 }
01493
01494 QString QgsProject::error() const
01495 {
01496 return mErrorMessage;
01497 }
01498
01499 void QgsProject::clearError()
01500 {
01501 setError( QString() );
01502 }
01503
01504 void QgsProject::setBadLayerHandler( QgsProjectBadLayerHandler* handler )
01505 {
01506 delete mBadLayerHandler;
01507 mBadLayerHandler = handler;
01508 }
01509
01510 void QgsProjectBadLayerDefaultHandler::handleBadLayers( QList<QDomNode> , QDomDocument )
01511 {
01512
01513 }