35 #include <QApplication>
39 #include <QTextStream>
42 static const char *
const ident_ =
"$Id$";
62 QStringList keyTokens = QStringList( scope );
63 keyTokens += key.split(
'/', QString::SkipEmptyParts );
66 keyTokens.push_front(
"properties" );
93 while ( ! keySequence.isEmpty() )
97 if ( keySequence.first() == currentProperty->
name() )
100 keySequence.pop_front();
103 if ( 1 == keySequence.count() )
105 return currentProperty->
find( keySequence.front() );
111 else if ( keySequence.isEmpty() )
113 return currentProperty;
115 else if (( nextProperty = currentProperty->
find( keySequence.first() ) ) )
117 if ( nextProperty->
isKey() )
125 else if ( nextProperty->
isValue() && ( 1 == keySequence.count() ) )
127 return currentProperty;
170 while ( ! keySequence.isEmpty() )
174 if ( keySequence.first() == currentProperty->
name() )
177 keySequence.pop_front();
181 if ( 1 == keySequence.count() )
183 currentProperty->
setValue( keySequence.front(), value );
184 return currentProperty;
188 else if ( keySequence.isEmpty() )
192 return currentProperty;
194 else if (( newProperty = currentProperty->
find( keySequence.first() ) ) )
198 if ( currentProperty )
209 newProperty = currentProperty->
addKey( keySequence.first() );
242 while ( ! keySequence.isEmpty() )
246 if ( keySequence.first() == currentProperty->
name() )
249 keySequence.pop_front();
253 if ( 1 == keySequence.count() )
255 currentProperty->
removeKey( keySequence.front() );
260 else if ( keySequence.isEmpty() )
262 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
264 else if (( nextProperty = currentProperty->
find( keySequence.first() ) ) )
266 previousQgsPropertyKey = currentProperty;
269 if ( currentProperty )
341 writeEntry(
"PositionPrecision",
"/Automatic",
true );
342 writeEntry(
"PositionPrecision",
"/DecimalPlaces", 2 );
362 if ( !QgsProject::theProject_ )
402 imp_->file.setFileName( name );
411 return imp_->file.fileName();
421 topQgsPropertyKey.
dump();
461 QDomNodeList properties = doc.elementsByTagName(
"properties" );
463 if ( properties.count() > 1 )
465 QgsDebugMsg(
"there appears to be more than one ``properties'' XML tag ... bailing" );
468 else if ( properties.count() < 1 )
475 QDomNodeList scopes = properties.item( 0 ).childNodes();
477 if ( scopes.count() < 1 )
479 QgsDebugMsg(
"empty ``properties'' XML tag ... bailing" );
483 QDomNode propertyNode = properties.item( 0 );
485 if ( ! project_properties.
readXML( propertyNode ) )
487 QgsDebugMsg(
"Project_properties.readXML() failed" );
493 while ( i < scopes.count() )
495 QDomNode curr_scope_node = scopes.item( i );
497 qDebug(
"found %d property node(s) for scope %s",
498 curr_scope_node.childNodes().count(),
499 curr_scope_node.nodeName().utf8().constData() );
501 QString key( curr_scope_node.nodeName() );
511 currentKey = project_properties.
addKey( key );
515 qDebug(
"%s:%d unable to add key", __FILE__, __LINE__ );
519 if ( ! currentKey->readXML( curr_scope_node ) )
521 qDebug(
"%s:%d unable to read XML for property %s", __FILE__, __LINE__,
522 curr_scope_node.nodeName().utf8().constData() );
544 static void _getTitle( QDomDocument
const &doc, QString & title )
546 QDomNodeList nl = doc.elementsByTagName(
"title" );
556 QDomNode titleNode = nl.item( 0 );
558 if ( !titleNode.hasChildNodes() )
564 QDomNode titleTextNode = titleNode.firstChild();
566 if ( !titleTextNode.isText() )
572 QDomText titleText = titleTextNode.toText();
574 title = titleText.data();
585 QDomNodeList nl = doc.elementsByTagName(
"qgis" );
589 QgsDebugMsg(
" unable to find qgis element in project file" );
593 QDomNode qgisNode = nl.item( 0 );
595 QDomElement qgisElement = qgisNode.toElement();
597 return projectVersion;
654 QDomNodeList nl = doc.elementsByTagName(
"maplayer" );
660 QList<QDomNode> brokenNodes;
667 if ( 0 == nl.count() )
669 return qMakePair(
true, brokenNodes );
677 bool returnStatus =
true;
683 QList< QPair< QgsVectorLayer*, QDomElement > > vLayerList;
685 for (
int i = 0; i < nl.count(); i++ )
687 QDomNode node = nl.item( i );
688 QDomElement element = node.toElement();
690 QString type = element.attribute(
"type" );
696 if ( type ==
"vector" )
700 else if ( type ==
"raster" )
704 else if ( type ==
"plugin" )
706 QString typeName = element.attribute(
"name" );
710 Q_CHECK_PTR( mapLayer );
716 return qMakePair(
false, brokenNodes );
726 vLayerList.push_back( qMakePair( vLayer, element ) );
733 QgsDebugMsg(
"Unable to load " + type +
" layer" );
735 returnStatus =
false;
737 brokenNodes.push_back( node );
744 QString errorMessage;
745 QList< QPair< QgsVectorLayer*, QDomElement > >::iterator vIt = vLayerList.begin();
746 for ( ; vIt != vLayerList.end(); ++vIt )
748 vIt->first->createJoinCaches();
749 vIt->first->updateFieldMap();
751 if ( !vIt->first->isUsingRendererV2() )
753 vIt->first->readSymbology( vIt->second, errorMessage );
757 return qMakePair( returnStatus, brokenNodes );
769 imp_->file.setFileName( file.filePath() );
783 std::auto_ptr< QDomDocument > doc =
784 std::auto_ptr < QDomDocument > (
new QDomDocument(
"qgis" ) );
786 if ( !
imp_->file.open( QIODevice::ReadOnly ) )
790 setError( tr(
"Unable to open %1" ).arg(
imp_->file.fileName() ) );
799 if ( !doc->setContent( &
imp_->file, &errorMsg, &line, &column ) )
803 QMessageBox::critical( 0, tr(
"Project File Read Error" ),
804 tr(
"%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
807 QString errorString = tr(
"Project file read error: %1 at line %2 column %3" )
808 .arg( errorMsg ).arg( line ).arg( column );
814 setError( tr(
"%1 for file %2" ).arg( errorString ).arg(
imp_->file.fileName() ) );
829 if ( thisVersion > fileVersion )
832 "version of qgis (saved in " + fileVersion.
text() +
834 "). Problems may occur." );
840 QgsDebugMsg(
"Emitting oldProjectVersionWarning(oldVersion)." );
844 projectFile.updateRevision( thisVersion );
859 QgsDebugMsg( QString::number(
imp_->properties_.count() ) +
" properties read" );
871 QPair< bool, QList<QDomNode> > getMapLayersResults =
_getMapLayers( *doc );
874 bool clean = getMapLayersResults.first;
878 QgsDebugMsg(
"Unable to get map layers from project file." );
880 if ( ! getMapLayersResults.second.isEmpty() )
882 QgsDebugMsg(
"there are " + QString::number( getMapLayersResults.second.size() ) +
" broken layers" );
907 QString type = layerNode.toElement().attribute(
"type" );
911 if ( type ==
"vector" )
915 else if ( type ==
"raster" )
919 else if ( type ==
"plugin" )
921 QString typeName = layerNode.toElement().attribute(
"name" );
937 if ( mapLayer->
readXML( layerNode ) )
945 QgsDebugMsg(
"unable to load " + type +
" layer" );
957 imp_->file.setFileName( file.filePath() );
970 if ( !
imp_->file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
975 setError( tr(
"Unable to save to file %1" ).arg(
imp_->file.fileName() ) );
978 QFileInfo myFileInfo(
imp_->file );
979 if ( !myFileInfo.isWritable() )
984 setError( tr(
"%1 is not writeable. Please adjust permissions (if possible) and try again." )
985 .arg(
imp_->file.fileName() ) );
989 QDomImplementation DomImplementation;
991 QDomDocumentType documentType =
992 DomImplementation.createDocumentType(
"qgis",
"http://mrcc.com/qgis.dtd",
994 std::auto_ptr < QDomDocument > doc =
995 std::auto_ptr < QDomDocument > (
new QDomDocument( documentType ) );
998 QDomElement qgisNode = doc->createElement(
"qgis" );
999 qgisNode.setAttribute(
"projectname",
title() );
1002 doc->appendChild( qgisNode );
1005 QDomElement titleNode = doc->createElement(
"title" );
1006 qgisNode.appendChild( titleNode );
1008 QDomText titleText = doc->createTextNode(
title() );
1009 titleNode.appendChild( titleText );
1019 QDomElement projectLayersNode = doc->createElement(
"projectlayers" );
1020 projectLayersNode.setAttribute(
"layercount", qulonglong( layers.size() ) );
1022 QMap<QString, QgsMapLayer*>::iterator li = layers.begin();
1023 while ( li != layers.end() )
1030 ml->
writeXML( projectLayersNode, *doc );
1035 qgisNode.appendChild( projectLayersNode );
1041 QgsDebugMsg( QString(
"there are %1 property scopes" ).arg( static_cast<int>(
imp_->properties_.count() ) ) );
1043 if ( !
imp_->properties_.isEmpty() )
1046 imp_->properties_.writeXML(
"properties", qgisNode, *doc );
1058 QTextStream projectFileStream( &
imp_->file );
1061 doc->save( projectFileStream, 4 );
1068 if ( projectFileStream.pos() == -1 ||
imp_->file.error() != QFile::NoError )
1070 setError( tr(
"Unable to save to file %1. Your project "
1071 "may be corrupted on disk. Try clearing some space on the volume and "
1072 "check file permissions before pressing save again." )
1073 .arg(
imp_->file.fileName() ) );
1100 return addKey_( scope, key, &
imp_->properties_, value );
1110 return addKey_( scope, key, &
imp_->properties_, value );
1119 return addKey_( scope, key, &
imp_->properties_, value );
1125 const QString & value )
1129 return addKey_( scope, key, &
imp_->properties_, value );
1135 const QStringList & value )
1139 return addKey_( scope, key, &
imp_->properties_, value );
1147 const QString & key,
1156 value =
property->value();
1159 bool valid = QVariant::StringList == value.type();
1168 return value.toStringList();
1171 return QStringList();
1177 const QString & key,
1178 const QString & def,
1187 value =
property->value();
1190 bool valid = value.canConvert( QVariant::String );
1199 return value.toString();
1202 return QString( def );
1216 value =
property->value();
1219 bool valid = value.canConvert( QVariant::String );
1228 return value.toInt();
1246 value =
property->value();
1249 bool valid = value.canConvert( QVariant::Double );
1258 return value.toDouble();
1275 value =
property->value();
1278 bool valid = value.canConvert( QVariant::Bool );
1287 return value.toBool();
1309 QStringList entries;
1311 if ( foundProperty )
1328 QStringList entries;
1330 if ( foundProperty )
1359 if ( !src.startsWith(
"./" ) && !src.startsWith(
"../" ) )
1361 #if defined(Q_OS_WIN)
1362 if ( src.startsWith(
"\\\\" ) ||
1363 src.startsWith(
"//" ) ||
1364 ( src[0].isLetter() && src[1] ==
':' ) )
1370 if ( src[0] ==
'/' )
1382 if ( !pfi.exists() )
1385 QFileInfo fi( pfi.canonicalPath() +
"/" + src );
1393 return fi.canonicalFilePath();
1397 QString srcPath = src;
1400 if ( projPath.isEmpty() )
1405 #if defined(Q_OS_WIN)
1406 srcPath.replace(
"\\",
"/" );
1407 projPath.replace(
"\\",
"/" );
1409 bool uncPath = projPath.startsWith(
"//" );
1412 QStringList srcElems = srcPath.split(
"/", QString::SkipEmptyParts );
1413 QStringList projElems = projPath.split(
"/", QString::SkipEmptyParts );
1415 #if defined(Q_OS_WIN)
1418 projElems.insert( 0,
"" );
1419 projElems.insert( 0,
"" );
1424 projElems.removeLast();
1427 projElems << srcElems;
1428 projElems.removeAll(
"." );
1432 while (( pos = projElems.indexOf(
".." ) ) > 0 )
1435 projElems.removeAt( pos - 1 );
1436 projElems.removeAt( pos - 1 );
1439 #if !defined(Q_OS_WIN)
1441 projElems.prepend(
"" );
1444 return projElems.join(
"/" );
1450 if (
readBoolEntry(
"Paths",
"/Absolute",
false ) || src.isEmpty() )
1455 QString srcPath = src;
1458 if ( projPath.isEmpty() )
1463 #if defined( Q_OS_WIN )
1464 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1466 srcPath.replace(
"\\",
"/" );
1468 if ( srcPath.startsWith(
"//" ) )
1471 srcPath =
"\\\\" + srcPath.mid( 2 );
1474 projPath.replace(
"\\",
"/" );
1475 if ( projPath.startsWith(
"//" ) )
1478 projPath =
"\\\\" + projPath.mid( 2 );
1481 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1484 QStringList projElems = projPath.split(
"/", QString::SkipEmptyParts );
1485 QStringList srcElems = srcPath.split(
"/", QString::SkipEmptyParts );
1488 projElems.removeLast();
1490 projElems.removeAll(
"." );
1491 srcElems.removeAll(
"." );
1495 while ( srcElems.size() > 0 &&
1496 projElems.size() > 0 &&
1497 srcElems[0].compare( projElems[0], cs ) == 0 )
1499 srcElems.removeFirst();
1500 projElems.removeFirst();
1510 if ( projElems.size() > 0 )
1513 for (
int i = 0; i < projElems.size(); i++ )
1515 srcElems.insert( 0,
".." );
1522 srcElems.insert( 0,
"." );
1525 return srcElems.join(
"/" );