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