36 #include <QApplication>
40 #include <QTextStream>
60 QStringList keyTokens = QStringList( scope );
61 keyTokens += key.split(
'/', QString::SkipEmptyParts );
64 keyTokens.push_front(
"properties" );
91 while ( ! keySequence.isEmpty() )
95 if ( keySequence.first() == currentProperty->
name() )
98 keySequence.pop_front();
101 if ( 1 == keySequence.count() )
103 return currentProperty->
find( keySequence.front() );
109 else if ( keySequence.isEmpty() )
111 return currentProperty;
113 else if (( nextProperty = currentProperty->
find( keySequence.first() ) ) )
115 if ( nextProperty->
isKey() )
123 else if ( nextProperty->
isValue() && ( 1 == keySequence.count() ) )
125 return currentProperty;
168 while ( ! keySequence.isEmpty() )
172 if ( keySequence.first() == currentProperty->
name() )
175 keySequence.pop_front();
179 if ( 1 == keySequence.count() )
181 currentProperty->
setValue( keySequence.front(), value );
182 return currentProperty;
186 else if ( keySequence.isEmpty() )
190 return currentProperty;
192 else if (( newProperty = currentProperty->
find( keySequence.first() ) ) )
196 if ( currentProperty )
207 newProperty = currentProperty->
addKey( keySequence.first() );
240 while ( ! keySequence.isEmpty() )
244 if ( keySequence.first() == currentProperty->
name() )
247 keySequence.pop_front();
251 if ( 1 == keySequence.count() )
253 currentProperty->
removeKey( keySequence.front() );
258 else if ( keySequence.isEmpty() )
260 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
262 else if (( nextProperty = currentProperty->
find( keySequence.first() ) ) )
264 previousQgsPropertyKey = currentProperty;
267 if ( currentProperty )
339 writeEntry(
"PositionPrecision",
"/Automatic",
true );
340 writeEntry(
"PositionPrecision",
"/DecimalPlaces", 2 );
360 if ( !QgsProject::theProject_ )
400 imp_->file.setFileName( name );
409 return imp_->file.fileName();
419 topQgsPropertyKey.
dump();
459 QDomNodeList properties = doc.elementsByTagName(
"properties" );
461 if ( properties.count() > 1 )
463 QgsDebugMsg(
"there appears to be more than one ``properties'' XML tag ... bailing" );
466 else if ( properties.count() < 1 )
473 QDomNodeList scopes = properties.item( 0 ).childNodes();
475 if ( scopes.count() < 1 )
477 QgsDebugMsg(
"empty ``properties'' XML tag ... bailing" );
481 QDomNode propertyNode = properties.item( 0 );
483 if ( ! project_properties.
readXML( propertyNode ) )
485 QgsDebugMsg(
"Project_properties.readXML() failed" );
491 while ( i < scopes.count() )
493 QDomNode curr_scope_node = scopes.item( i );
495 qDebug(
"found %d property node(s) for scope %s",
496 curr_scope_node.childNodes().count(),
497 curr_scope_node.nodeName().utf8().constData() );
499 QString key( curr_scope_node.nodeName() );
509 currentKey = project_properties.
addKey( key );
513 qDebug(
"%s:%d unable to add key", __FILE__, __LINE__ );
517 if ( ! currentKey->readXML( curr_scope_node ) )
519 qDebug(
"%s:%d unable to read XML for property %s", __FILE__, __LINE__,
520 curr_scope_node.nodeName().utf8().constData() );
542 static void _getTitle( QDomDocument
const &doc, QString & title )
544 QDomNodeList nl = doc.elementsByTagName(
"title" );
554 QDomNode titleNode = nl.item( 0 );
556 if ( !titleNode.hasChildNodes() )
562 QDomNode titleTextNode = titleNode.firstChild();
564 if ( !titleTextNode.isText() )
570 QDomText titleText = titleTextNode.toText();
572 title = titleText.data();
583 QDomNodeList nl = doc.elementsByTagName(
"qgis" );
587 QgsDebugMsg(
" unable to find qgis element in project file" );
591 QDomNode qgisNode = nl.item( 0 );
593 QDomElement qgisElement = qgisNode.toElement();
595 return projectVersion;
652 QDomNodeList nl = doc.elementsByTagName(
"maplayer" );
658 QList<QDomNode> brokenNodes;
665 if ( 0 == nl.count() )
667 return qMakePair(
true, brokenNodes );
675 bool returnStatus =
true;
681 QList< QPair< QgsVectorLayer*, QDomElement > > vLayerList;
683 for (
int i = 0; i < nl.count(); i++ )
685 QDomNode node = nl.item( i );
686 QDomElement element = node.toElement();
688 QString name = node.namedItem(
"layername" ).toElement().text();
689 if ( !name.isNull() )
692 if ( element.attribute(
"embedded" ) ==
"1" )
699 if ( !
addLayer( element, brokenNodes, vLayerList ) )
701 returnStatus =
false;
709 QList< QPair< QgsVectorLayer*, QDomElement > >::iterator vIt = vLayerList.begin();
710 for ( ; vIt != vLayerList.end(); ++vIt )
712 vIt->first->createJoinCaches();
713 vIt->first->updateFields();
716 return qMakePair( returnStatus, brokenNodes );
721 bool QgsProject::addLayer(
const QDomElement& layerElem, QList<QDomNode>& brokenNodes, QList< QPair< QgsVectorLayer*, QDomElement > >& vectorLayerList )
723 QString type = layerElem.attribute(
"type" );
727 if ( type ==
"vector" )
731 else if ( type ==
"raster" )
735 else if ( type ==
"plugin" )
737 QString typeName = layerElem.attribute(
"name" );
748 Q_CHECK_PTR( mapLayer );
755 QList<QgsMapLayer *> myLayers;
756 myLayers << mapLayer;
761 vectorLayerList.push_back( qMakePair( vLayer, layerElem ) );
769 QgsDebugMsg(
"Unable to load " + type +
" layer" );
770 brokenNodes.push_back( layerElem );
781 imp_->file.setFileName( file.filePath() );
795 std::auto_ptr< QDomDocument > doc =
796 std::auto_ptr < QDomDocument > (
new QDomDocument(
"qgis" ) );
798 if ( !
imp_->file.open( QIODevice::ReadOnly | QIODevice::Text ) )
802 setError(
tr(
"Unable to open %1" ).arg(
imp_->file.fileName() ) );
811 if ( !doc->setContent( &
imp_->file, &errorMsg, &line, &column ) )
815 QMessageBox::critical( 0,
tr(
"Project File Read Error" ),
816 tr(
"%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
819 QString errorString =
tr(
"Project file read error: %1 at line %2 column %3" )
820 .arg( errorMsg ).arg( line ).arg( column );
826 setError(
tr(
"%1 for file %2" ).arg( errorString ).arg(
imp_->file.fileName() ) );
841 if ( thisVersion > fileVersion )
844 "version of qgis (saved in " + fileVersion.
text() +
846 "). Problems may occur." );
852 QgsDebugMsg(
"Emitting oldProjectVersionWarning(oldVersion)." );
856 projectFile.updateRevision( thisVersion );
872 QgsDebugMsg( QString::number(
imp_->properties_.count() ) +
" properties read" );
884 QPair< bool, QList<QDomNode> > getMapLayersResults =
_getMapLayers( *doc );
887 bool clean = getMapLayersResults.first;
891 QgsDebugMsg(
"Unable to get map layers from project file." );
893 if ( ! getMapLayersResults.second.isEmpty() )
895 QgsDebugMsg(
"there are " + QString::number( getMapLayersResults.second.size() ) +
" broken layers" );
920 QList<QDomNode> brokenNodes;
921 QList< QPair< QgsVectorLayer*, QDomElement > > vectorLayerList;
922 return addLayer( layerNode.toElement(), brokenNodes, vectorLayerList );
929 imp_->file.setFileName( file.filePath() );
942 if ( !
imp_->file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
947 setError(
tr(
"Unable to save to file %1" ).arg(
imp_->file.fileName() ) );
950 QFileInfo myFileInfo(
imp_->file );
951 if ( !myFileInfo.isWritable() )
956 setError(
tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
957 .arg(
imp_->file.fileName() ) );
963 QDomImplementation DomImplementation;
964 DomImplementation.setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
966 QDomDocumentType documentType =
967 DomImplementation.createDocumentType(
"qgis",
"http://mrcc.com/qgis.dtd",
969 std::auto_ptr < QDomDocument > doc =
970 std::auto_ptr < QDomDocument > (
new QDomDocument( documentType ) );
973 QDomElement qgisNode = doc->createElement(
"qgis" );
974 qgisNode.setAttribute(
"projectname",
title() );
977 doc->appendChild( qgisNode );
980 QDomElement titleNode = doc->createElement(
"title" );
981 qgisNode.appendChild( titleNode );
983 QDomText titleText = doc->createTextNode(
title() );
984 titleNode.appendChild( titleText );
994 QDomElement projectLayersNode = doc->createElement(
"projectlayers" );
995 projectLayersNode.setAttribute(
"layercount", qulonglong( layers.size() ) );
997 QMap<QString, QgsMapLayer*>::ConstIterator li = layers.constBegin();
998 while ( li != layers.end() )
1006 QHash< QString, QPair< QString, bool> >::const_iterator emIt =
mEmbeddedLayers.find( ml->
id() );
1010 QDomElement maplayerElem = doc->createElement(
"maplayer" );
1016 projectLayersNode.appendChild( maplayerElem );
1021 if ( emIt.value().second )
1023 QDomElement mapLayerElem = doc->createElement(
"maplayer" );
1024 mapLayerElem.setAttribute(
"embedded", 1 );
1025 mapLayerElem.setAttribute(
"project",
writePath( emIt.value().first ) );
1026 mapLayerElem.setAttribute(
"id", ml->
id() );
1027 projectLayersNode.appendChild( mapLayerElem );
1034 qgisNode.appendChild( projectLayersNode );
1040 QgsDebugMsg( QString(
"there are %1 property scopes" ).arg( static_cast<int>(
imp_->properties_.count() ) ) );
1042 if ( !
imp_->properties_.isEmpty() )
1045 imp_->properties_.writeXML(
"properties", qgisNode, *doc );
1057 QTextStream projectFileStream( &
imp_->file );
1060 doc->save( projectFileStream, 4 );
1067 if ( projectFileStream.pos() == -1 ||
imp_->file.error() != QFile::NoError )
1069 setError(
tr(
"Unable to save to file %1. Your project "
1070 "may be corrupted on disk. Try clearing some space on the volume and "
1071 "check file permissions before pressing save again." )
1072 .arg(
imp_->file.fileName() ) );
1101 return addKey_( scope, key, &
imp_->properties_, value );
1111 return addKey_( scope, key, &
imp_->properties_, value );
1120 return addKey_( scope, key, &
imp_->properties_, value );
1126 const QString & value )
1130 return addKey_( scope, key, &
imp_->properties_, value );
1136 const QStringList & value )
1140 return addKey_( scope, key, &
imp_->properties_, value );
1148 const QString & key,
1158 value =
property->value();
1161 bool valid = QVariant::StringList == value.type();
1170 return value.toStringList();
1179 const QString & key,
1180 const QString & def,
1189 value =
property->value();
1192 bool valid = value.canConvert( QVariant::String );
1201 return value.toString();
1204 return QString( def );
1218 value =
property->value();
1221 bool valid = value.canConvert( QVariant::String );
1230 return value.toInt();
1248 value =
property->value();
1251 bool valid = value.canConvert( QVariant::Double );
1260 return value.toDouble();
1277 value =
property->value();
1280 bool valid = value.canConvert( QVariant::Bool );
1289 return value.toBool();
1311 QStringList entries;
1313 if ( foundProperty )
1330 QStringList entries;
1332 if ( foundProperty )
1361 if ( !src.startsWith(
"./" ) && !src.startsWith(
"../" ) )
1363 #if defined(Q_OS_WIN)
1364 if ( src.startsWith(
"\\\\" ) ||
1365 src.startsWith(
"//" ) ||
1366 ( src[0].isLetter() && src[1] ==
':' ) )
1372 if ( src[0] ==
'/' )
1384 if ( home.isNull() )
1387 QFileInfo fi( home +
"/" + src );
1395 return fi.canonicalFilePath();
1399 QString srcPath = src;
1402 if ( projPath.isEmpty() )
1407 #if defined(Q_OS_WIN)
1408 srcPath.replace(
"\\",
"/" );
1409 projPath.replace(
"\\",
"/" );
1411 bool uncPath = projPath.startsWith(
"//" );
1414 QStringList srcElems = srcPath.split(
"/", QString::SkipEmptyParts );
1415 QStringList projElems = projPath.split(
"/", QString::SkipEmptyParts );
1417 #if defined(Q_OS_WIN)
1420 projElems.insert( 0,
"" );
1421 projElems.insert( 0,
"" );
1426 projElems.removeLast();
1429 projElems << srcElems;
1430 projElems.removeAll(
"." );
1434 while (( pos = projElems.indexOf(
".." ) ) > 0 )
1437 projElems.removeAt( pos - 1 );
1438 projElems.removeAt( pos - 1 );
1441 #if !defined(Q_OS_WIN)
1443 projElems.prepend(
"" );
1446 return projElems.join(
"/" );
1452 if (
readBoolEntry(
"Paths",
"/Absolute",
false ) || src.isEmpty() )
1457 QString srcPath = src;
1460 if ( projPath.isEmpty() )
1465 #if defined( Q_OS_WIN )
1466 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1468 srcPath.replace(
"\\",
"/" );
1470 if ( srcPath.startsWith(
"//" ) )
1473 srcPath =
"\\\\" + srcPath.mid( 2 );
1476 projPath.replace(
"\\",
"/" );
1477 if ( projPath.startsWith(
"//" ) )
1480 projPath =
"\\\\" + projPath.mid( 2 );
1483 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1486 QStringList projElems = projPath.split(
"/", QString::SkipEmptyParts );
1487 QStringList srcElems = srcPath.split(
"/", QString::SkipEmptyParts );
1490 projElems.removeLast();
1492 projElems.removeAll(
"." );
1493 srcElems.removeAll(
"." );
1497 while ( srcElems.size() > 0 &&
1498 projElems.size() > 0 &&
1499 srcElems[0].compare( projElems[0], cs ) == 0 )
1501 srcElems.removeFirst();
1502 projElems.removeFirst();
1512 if ( projElems.size() > 0 )
1515 for (
int i = 0; i < projElems.size(); i++ )
1517 srcElems.insert( 0,
".." );
1524 srcElems.insert( 0,
"." );
1527 return srcElems.join(
"/" );
1553 QHash< QString, QPair< QString, bool > >::const_iterator it =
mEmbeddedLayers.find(
id );
1558 return it.value().first;
1562 QList< QPair< QgsVectorLayer*, QDomElement > >& vectorLayerList,
bool saveFlag )
1564 QFile projectFile( projectFilePath );
1565 if ( !projectFile.open( QIODevice::ReadOnly ) )
1570 QDomDocument projectDocument;
1571 if ( !projectDocument.setContent( &projectFile ) )
1577 bool useAbsolutePathes =
true;
1578 QDomElement propertiesElem = projectDocument.documentElement().firstChildElement(
"properties" );
1579 if ( !propertiesElem.isNull() )
1581 QDomElement absElem = propertiesElem.firstChildElement(
"Paths" ).firstChildElement(
"Absolute" );
1582 if ( !absElem.isNull() )
1584 useAbsolutePathes = absElem.text().compare(
"true", Qt::CaseInsensitive ) == 0;
1588 QDomElement projectLayersElem = projectDocument.documentElement().firstChildElement(
"projectlayers" );
1589 if ( projectLayersElem.isNull() )
1594 QDomNodeList mapLayerNodes = projectLayersElem.elementsByTagName(
"maplayer" );
1595 for (
int i = 0; i < mapLayerNodes.size(); ++i )
1598 QDomElement mapLayerElem = mapLayerNodes.at( i ).toElement();
1599 QString
id = mapLayerElem.firstChildElement(
"id" ).text();
1600 if (
id == layerId )
1603 if ( mapLayerElem.attribute(
"embedded" ) ==
"1" )
1608 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
1611 if ( !useAbsolutePathes )
1613 QDomElement provider = mapLayerElem.firstChildElement(
"provider" );
1614 if ( provider.text() ==
"spatialite" )
1616 QDomElement dsElem = mapLayerElem.firstChildElement(
"datasource" );
1620 QFileInfo absoluteDs( QFileInfo( projectFilePath ).absolutePath() +
"/" + uri.database() );
1621 if ( absoluteDs.exists() )
1624 dsElem.removeChild( dsElem.childNodes().at( 0 ) );
1625 dsElem.appendChild( projectDocument.createTextNode( uri.uri() ) );
1630 QDomElement dsElem = mapLayerElem.firstChildElement(
"datasource" );
1631 QString debug( QFileInfo( projectFilePath ).absolutePath() +
"/" + dsElem.text() );
1632 QFileInfo absoluteDs( QFileInfo( projectFilePath ).absolutePath() +
"/" + dsElem.text() );
1633 if ( absoluteDs.exists() )
1635 dsElem.removeChild( dsElem.childNodes().at( 0 ) );
1636 dsElem.appendChild( projectDocument.createTextNode( absoluteDs.absoluteFilePath() ) );
1641 if (
addLayer( mapLayerElem, brokenNodes, vectorLayerList ) )
1658 QStringList layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList;
1659 snapSettings( layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList );
1660 int idx = layerIdList.indexOf( layerId );
1663 layerIdList.removeAt( idx );
1664 enabledList.removeAt( idx );
1665 snapTypeList.removeAt( idx );
1666 toleranceUnitList.removeAt( idx );
1667 toleranceList.removeAt( idx );
1668 avoidIntersectionList.removeOne( layerId );
1671 layerIdList.append( layerId );
1674 enabledList.append( enabled ?
"enabled" :
"disabled" );
1680 typeString =
"to_segment";
1684 typeString =
"to_vertex_and_segment";
1688 typeString =
"to_vertex";
1690 snapTypeList.append( typeString );
1696 toleranceList.append( QString::number( tolerance ) );
1699 if ( avoidIntersection )
1701 avoidIntersectionList.append( layerId );
1704 writeEntry(
"Digitizing",
"/LayerSnappingList", layerIdList );
1705 writeEntry(
"Digitizing",
"/LayerSnappingEnabledList", enabledList );
1706 writeEntry(
"Digitizing",
"/LayerSnappingToleranceList", toleranceList );
1707 writeEntry(
"Digitizing",
"/LayerSnappingToleranceUnitList", toleranceUnitList );
1708 writeEntry(
"Digitizing",
"/LayerSnapToList", snapTypeList );
1709 writeEntry(
"Digitizing",
"/AvoidIntersectionsList", avoidIntersectionList );
1714 bool& avoidIntersection )
const
1716 QStringList layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList;
1717 snapSettings( layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList );
1718 int idx = layerIdList.indexOf( layerId );
1725 int minListEntries = idx + 1;
1726 if ( layerIdList.size() < minListEntries || enabledList.size() < minListEntries || snapTypeList.size() < minListEntries ||
1727 toleranceUnitList.size() < minListEntries || toleranceList.size() < minListEntries )
1733 enabled = enabledList.at( idx ) ==
"enabled";
1736 QString snapType = snapTypeList.at( idx );
1737 if ( snapType ==
"to_segment" )
1741 else if ( snapType ==
"to_vertex_and_segment" )
1751 if ( toleranceUnitList.at( idx ) ==
"1" )
1761 tolerance = toleranceList.at( idx ).toDouble();
1764 avoidIntersection = ( avoidIntersectionList.indexOf( layerId ) != -1 );
1769 void QgsProject::snapSettings( QStringList& layerIdList, QStringList& enabledList, QStringList& snapTypeList, QStringList& toleranceUnitList, QStringList& toleranceList,
1770 QStringList& avoidIntersectionList )
const
1772 layerIdList =
readListEntry(
"Digitizing",
"/LayerSnappingList" );
1773 enabledList =
readListEntry(
"Digitizing",
"/LayerSnappingEnabledList" );
1774 toleranceList =
readListEntry(
"Digitizing",
"/LayerSnappingToleranceList" );
1775 toleranceUnitList =
readListEntry(
"Digitizing",
"/LayerSnappingToleranceUnitList" );
1776 snapTypeList =
readListEntry(
"Digitizing",
"/LayerSnapToList" );
1777 avoidIntersectionList =
readListEntry(
"Digitizing",
"/AvoidIntersectionsList" );
1799 if ( !pfi.exists() )
1800 return QString::null;
1802 return pfi.canonicalPath();