37 #include <QApplication>
41 #include <QTextStream>
61 QStringList keyTokens = QStringList( scope );
62 keyTokens += key.split(
'/', QString::SkipEmptyParts );
65 keyTokens.push_front(
"properties" );
92 while ( ! keySequence.isEmpty() )
96 if ( keySequence.first() == currentProperty->
name() )
99 keySequence.pop_front();
102 if ( 1 == keySequence.count() )
104 return currentProperty->
find( keySequence.front() );
110 else if ( keySequence.isEmpty() )
112 return currentProperty;
114 else if (( nextProperty = currentProperty->
find( keySequence.first() ) ) )
116 if ( nextProperty->
isKey() )
124 else if ( nextProperty->
isValue() && ( 1 == keySequence.count() ) )
126 return currentProperty;
169 while ( ! keySequence.isEmpty() )
173 if ( keySequence.first() == currentProperty->
name() )
176 keySequence.pop_front();
180 if ( 1 == keySequence.count() )
182 currentProperty->
setValue( keySequence.front(), value );
183 return currentProperty;
187 else if ( keySequence.isEmpty() )
191 return currentProperty;
193 else if (( newProperty = currentProperty->
find( keySequence.first() ) ) )
197 if ( currentProperty )
208 newProperty = currentProperty->
addKey( keySequence.first() );
241 while ( ! keySequence.isEmpty() )
245 if ( keySequence.first() == currentProperty->
name() )
248 keySequence.pop_front();
252 if ( 1 == keySequence.count() )
254 currentProperty->
removeKey( keySequence.front() );
259 else if ( keySequence.isEmpty() )
261 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
263 else if (( nextProperty = currentProperty->
find( keySequence.first() ) ) )
265 previousQgsPropertyKey = currentProperty;
268 if ( currentProperty )
342 writeEntry(
"PositionPrecision",
"/Automatic",
true );
343 writeEntry(
"PositionPrecision",
"/DecimalPlaces", 2 );
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 );
720 bool QgsProject::addLayer(
const QDomElement& layerElem, QList<QDomNode>& brokenNodes, QList< QPair< QgsVectorLayer*, QDomElement > >& vectorLayerList )
722 QString type = layerElem.attribute(
"type" );
726 if ( type ==
"vector" )
730 else if ( type ==
"raster" )
734 else if ( type ==
"plugin" )
736 QString typeName = layerElem.attribute(
"name" );
747 Q_CHECK_PTR( mapLayer );
754 QList<QgsMapLayer *> myLayers;
755 myLayers << mapLayer;
760 vectorLayerList.push_back( qMakePair( vLayer, layerElem ) );
768 QgsDebugMsg(
"Unable to load " + type +
" layer" );
769 brokenNodes.push_back( layerElem );
780 imp_->file.setFileName( file.filePath() );
794 std::auto_ptr< QDomDocument > doc =
795 std::auto_ptr < QDomDocument > (
new QDomDocument(
"qgis" ) );
797 if ( !
imp_->file.open( QIODevice::ReadOnly | QIODevice::Text ) )
801 setError(
tr(
"Unable to open %1" ).arg(
imp_->file.fileName() ) );
810 if ( !doc->setContent( &
imp_->file, &errorMsg, &line, &column ) )
814 QMessageBox::critical( 0,
tr(
"Project File Read Error" ),
815 tr(
"%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
818 QString errorString =
tr(
"Project file read error: %1 at line %2 column %3" )
819 .arg( errorMsg ).arg( line ).arg( column );
825 setError(
tr(
"%1 for file %2" ).arg( errorString ).arg(
imp_->file.fileName() ) );
840 if ( thisVersion > fileVersion )
843 "version of qgis (saved in " + fileVersion.
text() +
845 "). Problems may occur." );
851 QgsDebugMsg(
"Emitting oldProjectVersionWarning(oldVersion)." );
855 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() );
943 if ( QFile::exists( backup ) )
944 QFile::remove( backup );
945 QFile::rename(
fileName(), backup );
951 if ( !
imp_->file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
956 setError(
tr(
"Unable to save to file %1" ).arg(
imp_->file.fileName() ) );
959 QFileInfo myFileInfo(
imp_->file );
960 if ( !myFileInfo.isWritable() )
965 setError(
tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
966 .arg(
imp_->file.fileName() ) );
972 QDomImplementation DomImplementation;
973 DomImplementation.setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
975 QDomDocumentType documentType =
976 DomImplementation.createDocumentType(
"qgis",
"http://mrcc.com/qgis.dtd",
978 std::auto_ptr < QDomDocument > doc =
979 std::auto_ptr < QDomDocument > (
new QDomDocument( documentType ) );
982 QDomElement qgisNode = doc->createElement(
"qgis" );
983 qgisNode.setAttribute(
"projectname",
title() );
986 doc->appendChild( qgisNode );
989 QDomElement titleNode = doc->createElement(
"title" );
990 qgisNode.appendChild( titleNode );
992 QDomText titleText = doc->createTextNode(
title() );
993 titleNode.appendChild( titleText );
1003 QDomElement projectLayersNode = doc->createElement(
"projectlayers" );
1004 projectLayersNode.setAttribute(
"layercount", qulonglong( layers.size() ) );
1006 QMap<QString, QgsMapLayer*>::ConstIterator li = layers.constBegin();
1007 while ( li != layers.end() )
1015 QHash< QString, QPair< QString, bool> >::const_iterator emIt =
mEmbeddedLayers.find( ml->
id() );
1019 QDomElement maplayerElem = doc->createElement(
"maplayer" );
1025 projectLayersNode.appendChild( maplayerElem );
1030 if ( emIt.value().second )
1032 QDomElement mapLayerElem = doc->createElement(
"maplayer" );
1033 mapLayerElem.setAttribute(
"embedded", 1 );
1034 mapLayerElem.setAttribute(
"project",
writePath( emIt.value().first ) );
1035 mapLayerElem.setAttribute(
"id", ml->
id() );
1036 projectLayersNode.appendChild( mapLayerElem );
1043 qgisNode.appendChild( projectLayersNode );
1049 QgsDebugMsg( QString(
"there are %1 property scopes" ).arg( static_cast<int>(
imp_->properties_.count() ) ) );
1051 if ( !
imp_->properties_.isEmpty() )
1054 imp_->properties_.writeXML(
"properties", qgisNode, *doc );
1066 QTextStream projectFileStream( &
imp_->file );
1069 doc->save( projectFileStream, 4 );
1076 if ( projectFileStream.pos() == -1 ||
imp_->file.error() != QFile::NoError )
1078 setError(
tr(
"Unable to save to file %1. Your project "
1079 "may be corrupted on disk. Try clearing some space on the volume and "
1080 "check file permissions before pressing save again." )
1081 .arg(
imp_->file.fileName() ) );
1110 return addKey_( scope, key, &
imp_->properties_, value );
1120 return addKey_( scope, key, &
imp_->properties_, value );
1129 return addKey_( scope, key, &
imp_->properties_, value );
1135 const QString & value )
1139 return addKey_( scope, key, &
imp_->properties_, value );
1145 const QStringList & value )
1149 return addKey_( scope, key, &
imp_->properties_, value );
1157 const QString & key,
1167 value =
property->value();
1170 bool valid = QVariant::StringList == value.type();
1179 return value.toStringList();
1188 const QString & key,
1189 const QString & def,
1198 value =
property->value();
1201 bool valid = value.canConvert( QVariant::String );
1210 return value.toString();
1213 return QString( def );
1227 value =
property->value();
1230 bool valid = value.canConvert( QVariant::String );
1239 return value.toInt();
1257 value =
property->value();
1260 bool valid = value.canConvert( QVariant::Double );
1269 return value.toDouble();
1286 value =
property->value();
1289 bool valid = value.canConvert( QVariant::Bool );
1298 return value.toBool();
1320 QStringList entries;
1322 if ( foundProperty )
1338 QStringList entries;
1340 if ( foundProperty )
1370 if ( ! vsiPrefix.isEmpty() )
1372 src.remove( 0, vsiPrefix.size() );
1376 if ( !src.startsWith(
"./" ) && !src.startsWith(
"../" ) )
1378 #if defined(Q_OS_WIN)
1379 if ( src.startsWith(
"\\\\" ) ||
1380 src.startsWith(
"//" ) ||
1381 ( src[0].isLetter() && src[1] ==
':' ) )
1384 return vsiPrefix + src;
1387 if ( src[0] ==
'/' )
1390 return vsiPrefix + src;
1399 if ( home.isNull() )
1400 return vsiPrefix + src;
1402 QFileInfo fi( home +
"/" + src );
1406 return vsiPrefix + src;
1410 return vsiPrefix + fi.canonicalFilePath();
1414 QString srcPath = src;
1417 if ( projPath.isEmpty() )
1419 return vsiPrefix + src;
1422 #if defined(Q_OS_WIN)
1423 srcPath.replace(
"\\",
"/" );
1424 projPath.replace(
"\\",
"/" );
1426 bool uncPath = projPath.startsWith(
"//" );
1429 QStringList srcElems = srcPath.split(
"/", QString::SkipEmptyParts );
1430 QStringList projElems = projPath.split(
"/", QString::SkipEmptyParts );
1432 #if defined(Q_OS_WIN)
1435 projElems.insert( 0,
"" );
1436 projElems.insert( 0,
"" );
1441 projElems.removeLast();
1444 projElems << srcElems;
1445 projElems.removeAll(
"." );
1449 while (( pos = projElems.indexOf(
".." ) ) > 0 )
1452 projElems.removeAt( pos - 1 );
1453 projElems.removeAt( pos - 1 );
1456 #if !defined(Q_OS_WIN)
1458 projElems.prepend(
"" );
1461 return vsiPrefix + projElems.join(
"/" );
1467 if (
readBoolEntry(
"Paths",
"/Absolute",
false ) || src.isEmpty() )
1472 QString srcPath = src;
1475 if ( projPath.isEmpty() )
1482 if ( ! vsiPrefix.isEmpty() )
1484 srcPath.remove( 0, vsiPrefix.size() );
1487 #if defined( Q_OS_WIN )
1488 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
1490 srcPath.replace(
"\\",
"/" );
1492 if ( srcPath.startsWith(
"//" ) )
1495 srcPath =
"\\\\" + srcPath.mid( 2 );
1498 projPath.replace(
"\\",
"/" );
1499 if ( projPath.startsWith(
"//" ) )
1502 projPath =
"\\\\" + projPath.mid( 2 );
1505 const Qt::CaseSensitivity cs = Qt::CaseSensitive;
1508 QStringList projElems = projPath.split(
"/", QString::SkipEmptyParts );
1509 QStringList srcElems = srcPath.split(
"/", QString::SkipEmptyParts );
1512 projElems.removeLast();
1514 projElems.removeAll(
"." );
1515 srcElems.removeAll(
"." );
1519 while ( srcElems.size() > 0 &&
1520 projElems.size() > 0 &&
1521 srcElems[0].compare( projElems[0], cs ) == 0 )
1523 srcElems.removeFirst();
1524 projElems.removeFirst();
1534 if ( projElems.size() > 0 )
1537 for (
int i = 0; i < projElems.size(); i++ )
1539 srcElems.insert( 0,
".." );
1546 srcElems.insert( 0,
"." );
1549 return vsiPrefix + srcElems.join(
"/" );
1575 QHash< QString, QPair< QString, bool > >::const_iterator it =
mEmbeddedLayers.find(
id );
1580 return it.value().first;
1584 QList< QPair< QgsVectorLayer*, QDomElement > >& vectorLayerList,
bool saveFlag )
1586 QFile projectFile( projectFilePath );
1587 if ( !projectFile.open( QIODevice::ReadOnly ) )
1592 QDomDocument projectDocument;
1593 if ( !projectDocument.setContent( &projectFile ) )
1599 bool useAbsolutePathes =
true;
1600 QDomElement propertiesElem = projectDocument.documentElement().firstChildElement(
"properties" );
1601 if ( !propertiesElem.isNull() )
1603 QDomElement absElem = propertiesElem.firstChildElement(
"Paths" ).firstChildElement(
"Absolute" );
1604 if ( !absElem.isNull() )
1606 useAbsolutePathes = absElem.text().compare(
"true", Qt::CaseInsensitive ) == 0;
1610 QDomElement projectLayersElem = projectDocument.documentElement().firstChildElement(
"projectlayers" );
1611 if ( projectLayersElem.isNull() )
1616 QDomNodeList mapLayerNodes = projectLayersElem.elementsByTagName(
"maplayer" );
1617 for (
int i = 0; i < mapLayerNodes.size(); ++i )
1620 QDomElement mapLayerElem = mapLayerNodes.at( i ).toElement();
1621 QString
id = mapLayerElem.firstChildElement(
"id" ).text();
1622 if (
id == layerId )
1625 if ( mapLayerElem.attribute(
"embedded" ) ==
"1" )
1630 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
1633 if ( !useAbsolutePathes )
1635 QDomElement provider = mapLayerElem.firstChildElement(
"provider" );
1636 if ( provider.text() ==
"spatialite" )
1638 QDomElement dsElem = mapLayerElem.firstChildElement(
"datasource" );
1642 QFileInfo absoluteDs( QFileInfo( projectFilePath ).absolutePath() +
"/" + uri.database() );
1643 if ( absoluteDs.exists() )
1646 dsElem.removeChild( dsElem.childNodes().at( 0 ) );
1647 dsElem.appendChild( projectDocument.createTextNode( uri.uri() ) );
1652 QDomElement dsElem = mapLayerElem.firstChildElement(
"datasource" );
1653 QString debug( QFileInfo( projectFilePath ).absolutePath() +
"/" + dsElem.text() );
1654 QFileInfo absoluteDs( QFileInfo( projectFilePath ).absolutePath() +
"/" + dsElem.text() );
1655 if ( absoluteDs.exists() )
1657 dsElem.removeChild( dsElem.childNodes().at( 0 ) );
1658 dsElem.appendChild( projectDocument.createTextNode( absoluteDs.absoluteFilePath() ) );
1663 if (
addLayer( mapLayerElem, brokenNodes, vectorLayerList ) )
1680 QStringList layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList;
1681 snapSettings( layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList );
1682 int idx = layerIdList.indexOf( layerId );
1685 layerIdList.removeAt( idx );
1686 enabledList.removeAt( idx );
1687 snapTypeList.removeAt( idx );
1688 toleranceUnitList.removeAt( idx );
1689 toleranceList.removeAt( idx );
1690 avoidIntersectionList.removeOne( layerId );
1693 layerIdList.append( layerId );
1696 enabledList.append( enabled ?
"enabled" :
"disabled" );
1702 typeString =
"to_segment";
1706 typeString =
"to_vertex_and_segment";
1710 typeString =
"to_vertex";
1712 snapTypeList.append( typeString );
1718 toleranceList.append( QString::number( tolerance ) );
1721 if ( avoidIntersection )
1723 avoidIntersectionList.append( layerId );
1726 writeEntry(
"Digitizing",
"/LayerSnappingList", layerIdList );
1727 writeEntry(
"Digitizing",
"/LayerSnappingEnabledList", enabledList );
1728 writeEntry(
"Digitizing",
"/LayerSnappingToleranceList", toleranceList );
1729 writeEntry(
"Digitizing",
"/LayerSnappingToleranceUnitList", toleranceUnitList );
1730 writeEntry(
"Digitizing",
"/LayerSnapToList", snapTypeList );
1731 writeEntry(
"Digitizing",
"/AvoidIntersectionsList", avoidIntersectionList );
1736 bool& avoidIntersection )
const
1738 QStringList layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList;
1739 snapSettings( layerIdList, enabledList, snapTypeList, toleranceUnitList, toleranceList, avoidIntersectionList );
1740 int idx = layerIdList.indexOf( layerId );
1747 int minListEntries = idx + 1;
1748 if ( layerIdList.size() < minListEntries || enabledList.size() < minListEntries || snapTypeList.size() < minListEntries ||
1749 toleranceUnitList.size() < minListEntries || toleranceList.size() < minListEntries )
1755 enabled = enabledList.at( idx ) ==
"enabled";
1758 QString snapType = snapTypeList.at( idx );
1759 if ( snapType ==
"to_segment" )
1763 else if ( snapType ==
"to_vertex_and_segment" )
1773 if ( toleranceUnitList.at( idx ) ==
"1" )
1783 tolerance = toleranceList.at( idx ).toDouble();
1786 avoidIntersection = ( avoidIntersectionList.indexOf( layerId ) != -1 );
1791 void QgsProject::snapSettings( QStringList& layerIdList, QStringList& enabledList, QStringList& snapTypeList, QStringList& toleranceUnitList, QStringList& toleranceList,
1792 QStringList& avoidIntersectionList )
const
1794 layerIdList =
readListEntry(
"Digitizing",
"/LayerSnappingList" );
1795 enabledList =
readListEntry(
"Digitizing",
"/LayerSnappingEnabledList" );
1796 toleranceList =
readListEntry(
"Digitizing",
"/LayerSnappingToleranceList" );
1797 toleranceUnitList =
readListEntry(
"Digitizing",
"/LayerSnappingToleranceUnitList" );
1798 snapTypeList =
readListEntry(
"Digitizing",
"/LayerSnapToList" );
1799 avoidIntersectionList =
readListEntry(
"Digitizing",
"/AvoidIntersectionsList" );
1821 if ( !pfi.exists() )
1822 return QString::null;
1824 return pfi.canonicalPath();