68 #include <QApplication>
72 #include <QTextStream>
73 #include <QTemporaryFile>
79 #include <sys/utime.h>
97 QStringList keyTokens = QStringList( scope );
98 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
99 keyTokens += key.split(
'/', QString::SkipEmptyParts );
101 keyTokens += key.split(
'/', Qt::SkipEmptyParts );
105 keyTokens.push_front( QStringLiteral(
"properties" ) );
108 for (
int i = 0; i < keyTokens.size(); ++i )
110 QString keyToken = keyTokens.at( i );
114 QString nameCharRegexp = QStringLiteral(
"[^:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x2FF\\x370-\\x37D\\x37F-\\x1FFF\\x200C-\\x200D\\x2070-\\x218F\\x2C00-\\x2FEF\\x3001-\\xD7FF\\xF900-\\xFDCF\\xFDF0-\\xFFFD\\-\\.0-9\\xB7\\x0300-\\x036F\\x203F-\\x2040]" );
115 QString nameStartCharRegexp = QStringLiteral(
"^[^:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x2FF\\x370-\\x37D\\x37F-\\x1FFF\\x200C-\\x200D\\x2070-\\x218F\\x2C00-\\x2FEF\\x3001-\\xD7FF\\xF900-\\xFDCF\\xFDF0-\\xFFFD]" );
117 if ( keyToken.contains( QRegExp( nameCharRegexp ) ) || keyToken.contains( QRegExp( nameStartCharRegexp ) ) )
120 QString errorString = QObject::tr(
"Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
150 while ( !keySequence.isEmpty() )
154 if ( keySequence.first() == currentProperty->
name() )
157 keySequence.pop_front();
159 if ( 1 == keySequence.count() )
162 return currentProperty->
find( keySequence.front() );
164 else if ( keySequence.isEmpty() )
169 return currentProperty;
171 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
173 if ( nextProperty->
isKey() )
177 else if ( nextProperty->
isValue() && 1 == keySequence.count() )
183 return currentProperty;
221 const QVariant &value,
222 bool &propertiesModified )
231 propertiesModified =
false;
232 while ( ! keySequence.isEmpty() )
236 if ( keySequence.first() == currentProperty->
name() )
239 keySequence.pop_front();
243 if ( 1 == keySequence.count() )
246 if ( !property || property->value() != value )
248 currentProperty->
setValue( keySequence.front(), value );
249 propertiesModified =
true;
252 return currentProperty;
256 else if ( keySequence.isEmpty() )
258 if ( currentProperty->
value() != value )
261 propertiesModified =
true;
264 return currentProperty;
266 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
270 if ( currentProperty )
281 if ( ( newPropertyKey = currentProperty->
addKey( keySequence.first() ) ) )
283 currentProperty = newPropertyKey;
316 while ( ! keySequence.isEmpty() )
320 if ( keySequence.first() == currentProperty->
name() )
323 keySequence.pop_front();
327 if ( 1 == keySequence.count() )
329 currentProperty->
removeKey( keySequence.front() );
334 else if ( keySequence.isEmpty() )
336 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
338 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
340 previousQgsPropertyKey = currentProperty;
343 if ( currentProperty )
369 , mSnappingConfig( this )
382 mProperties.
setName( QStringLiteral(
"properties" ) );
385 mMainAnnotationLayer->setParent(
this );
399 this, [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
403 this, [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
405 this, [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
407 [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
409 [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
411 [ = ]() { mProjectScope.reset(); emit removeAll(); } );
413 [ = ](
const QList< QgsMapLayer * > &
layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
415 [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
423 [ = ](
const QList<QgsMapLayer *> &
layers )
425 for (
const auto &layer :
layers )
432 [ = ](
const QList<QgsMapLayer *> &
layers )
434 for (
const auto &layer :
layers )
449 mIsBeingDeleted =
true;
452 delete mBadLayerHandler;
453 delete mRelationManager;
454 delete mLayerTreeRegistryBridge;
456 if (
this == sProject )
483 mProjectScope.reset();
491 return mMetadata.
title();
501 return mSaveUserFull;
506 return mSaveDateTime;
521 if ( dirty && mDirtyBlockCount > 0 )
524 if ( mDirty == dirty )
533 if ( path == mHomePath )
537 mCachedHomePath.clear();
538 mProjectScope.reset();
547 const QList<QgsAttributeEditorElement *> elements = parent->
children();
555 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:formcontainers" ).arg( layerId ), container->
name() );
557 if ( !container->
children().empty() )
570 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1" ).arg( layer->layerId() ), layer->name() );
587 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fieldaliases" ).arg( vlayer->
id() ), fieldName );
602 const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->
findGroups();
605 translationContext->
registerTranslation( QStringLiteral(
"project:layergroups" ), groupLayer->name() );
609 const QList<QgsRelation> &relations = mRelationManager->
relations().values();
612 translationContext->
registerTranslation( QStringLiteral(
"project:relations" ), relation.name() );
618 mDataDefinedServerProperties = properties;
623 return mDataDefinedServerProperties;
628 if ( name == mFile.fileName() )
633 mFile.setFileName( name );
634 mCachedHomePath.clear();
635 mProjectScope.reset();
640 if ( newHomePath != oldHomePath )
648 return mFile.fileName();
653 mOriginalPath = path;
658 return mOriginalPath;
663 return QFileInfo( mFile );
676 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
681 return QFileInfo( mFile.fileName() ).lastModified();
690 if ( mFile.fileName().isEmpty() )
693 return QFileInfo( mFile.fileName() ).absolutePath();
701 if ( mFile.fileName().isEmpty() )
704 return QFileInfo( mFile.fileName() ).absoluteFilePath();
712 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
717 return QFileInfo( mFile.fileName() ).completeBaseName();
731 writeEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ),
crs.
isValid() ? 1 : 0 );
732 mProjectScope.reset();
737 if ( adjustEllipsoid )
743 if ( !
crs().isValid() )
746 return readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ),
geoNone() );
751 if (
ellipsoid ==
readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ) ) )
754 mProjectScope.reset();
761 return mTransformContext;
766 if ( context == mTransformContext )
769 mTransformContext = context;
770 mProjectScope.reset();
773 for (
auto &layer : mLayerStore.get()->mapLayers() )
775 layer->setTransformContext( context );
784 mProjectScope.reset();
785 mFile.setFileName( QString() );
788 mSaveUserFull.clear();
789 mSaveDateTime = QDateTime();
792 mCachedHomePath.clear();
793 mAutoTransaction =
false;
794 mEvaluateDefaultValues =
false;
796 mTrustLayerMetadata =
false;
797 mCustomVariables.clear();
799 if ( !settings.
value( QStringLiteral(
"projects/anonymize_new_projects" ),
false,
QgsSettings::Core ).toBool() )
810 mEmbeddedLayers.clear();
811 mRelationManager->
clear();
812 mAnnotationManager->clear();
813 mLayoutManager->clear();
814 mBookmarkManager->
clear();
815 mViewSettings->
reset();
816 mTimeSettings->
reset();
817 mDisplaySettings->
reset();
818 mSnappingConfig.
reset();
826 mLabelingEngineSettings->clear();
833 if ( !mIsBeingDeleted )
841 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/Automatic" ),
true );
842 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/DecimalPlaces" ), 2 );
843 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
846 writeEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), settings.
value( QStringLiteral(
"/qgis/measure/displayunits" ) ).toString() );
847 writeEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), settings.
value( QStringLiteral(
"/qgis/measure/areaunits" ) ).toString() );
849 int red = settings.
value( QStringLiteral(
"qgis/default_canvas_color_red" ), 255 ).toInt();
850 int green = settings.
value( QStringLiteral(
"qgis/default_canvas_color_green" ), 255 ).toInt();
851 int blue = settings.
value( QStringLiteral(
"qgis/default_canvas_color_blue" ), 255 ).toInt();
854 red = settings.
value( QStringLiteral(
"qgis/default_selection_color_red" ), 255 ).toInt();
855 green = settings.
value( QStringLiteral(
"qgis/default_selection_color_green" ), 255 ).toInt();
856 blue = settings.
value( QStringLiteral(
"qgis/default_selection_color_blue" ), 0 ).toInt();
857 int alpha = settings.
value( QStringLiteral(
"qgis/default_selection_color_alpha" ), 255 ).toInt();
862 if ( mMainAnnotationLayer )
863 mMainAnnotationLayer->
reset();
874 topQgsPropertyKey.
dump();
910 QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
912 if ( propertiesElem.isNull() )
917 QDomNodeList scopes = propertiesElem.childNodes();
919 if ( scopes.count() < 1 )
921 QgsDebugMsg( QStringLiteral(
"empty ``properties'' XML tag ... bailing" ) );
925 if ( ! project_properties.
readXml( propertiesElem ) )
927 QgsDebugMsg( QStringLiteral(
"Project_properties.readXml() failed" ) );
941 QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral(
"dataDefinedServerProperties" ) );
942 if ( !ddElem.isNull() )
944 if ( !ddServerProperties.
readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
946 QgsDebugMsg( QStringLiteral(
"dataDefinedServerProperties.readXml() failed" ) );
949 return ddServerProperties;
956 static void _getTitle(
const QDomDocument &doc, QString &title )
958 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"title" ) );
968 QDomNode titleNode = nl.item( 0 );
970 if ( !titleNode.hasChildNodes() )
976 QDomNode titleTextNode = titleNode.firstChild();
978 if ( !titleTextNode.isText() )
984 QDomText titleText = titleTextNode.toText();
986 title = titleText.data();
990 static void readProjectFileMetadata(
const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
992 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1000 QDomNode qgisNode = nl.item( 0 );
1002 QDomElement qgisElement = qgisNode.toElement();
1003 lastUser = qgisElement.attribute( QStringLiteral(
"saveUser" ), QString() );
1004 lastUserFull = qgisElement.attribute( QStringLiteral(
"saveUserFull" ), QString() );
1005 lastSaveDateTime = QDateTime::fromString( qgisElement.attribute( QStringLiteral(
"saveDateTime" ), QString() ), Qt::ISODate );
1011 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1015 QgsDebugMsg( QStringLiteral(
" unable to find qgis element in project file" ) );
1019 QDomNode qgisNode = nl.item( 0 );
1021 QDomElement qgisElement = qgisNode.toElement();
1022 QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral(
"version" ) ) );
1023 return projectVersion;
1029 return mSnappingConfig;
1044 if ( mAvoidIntersectionsMode == mode )
1047 mAvoidIntersectionsMode = mode;
1051 bool QgsProject::_getMapLayers(
const QDomDocument &doc, QList<QDomNode> &brokenNodes, QgsProject::ReadFlags flags )
1056 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"maplayer" ) );
1060 if ( 0 == nl.count() )
1070 bool returnStatus =
true;
1075 if ( depSorter.hasCycle() )
1079 if ( depSorter.hasMissingDependency() )
1080 returnStatus =
false;
1084 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1085 const int totalLayerCount = sortedLayerNodes.count();
1088 for (
const QDomNode &node : sortedLayerNodes )
1090 const QDomElement element = node.toElement();
1092 const QString name =
translate( QStringLiteral(
"project:layers:%1" ).arg( node.namedItem( QStringLiteral(
"id" ) ).toElement().text() ), node.namedItem( QStringLiteral(
"layername" ) ).toElement().text() );
1093 if ( !name.isNull() )
1094 emit
loadingLayer( tr(
"Loading layer %1" ).arg( name ) );
1096 profile.switchTask( name );
1098 if ( element.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
1100 createEmbeddedLayer( element.attribute( QStringLiteral(
"id" ) ),
readPath( element.attribute( QStringLiteral(
"project" ) ) ), brokenNodes,
true, flags );
1109 if ( !addLayer( element, brokenNodes, context, flags ) )
1111 returnStatus =
false;
1114 if ( !messages.isEmpty() )
1123 return returnStatus;
1126 bool QgsProject::addLayer(
const QDomElement &layerElem, QList<QDomNode> &brokenNodes,
QgsReadWriteContext &context, QgsProject::ReadFlags flags )
1128 QString type = layerElem.attribute( QStringLiteral(
"type" ) );
1130 std::unique_ptr<QgsMapLayer>
mapLayer;
1133 if ( type == QLatin1String(
"vector" ) )
1135 mapLayer = qgis::make_unique<QgsVectorLayer>();
1142 else if ( type == QLatin1String(
"raster" ) )
1144 mapLayer = qgis::make_unique<QgsRasterLayer>();
1146 else if ( type == QLatin1String(
"mesh" ) )
1148 mapLayer = qgis::make_unique<QgsMeshLayer>();
1150 else if ( type == QLatin1String(
"vector-tile" ) )
1152 mapLayer = qgis::make_unique<QgsVectorTileLayer>();
1154 else if ( type == QLatin1String(
"plugin" ) )
1156 QString
typeName = layerElem.attribute( QStringLiteral(
"name" ) );
1159 else if ( type == QLatin1String(
"annotation" ) )
1162 mapLayer = qgis::make_unique<QgsAnnotationLayer>( QString(), options );
1166 QgsDebugMsg( QStringLiteral(
"Unable to create layer" ) );
1174 const QString layerId { layerElem.namedItem( QStringLiteral(
"id" ) ).toElement().text() };
1175 Q_ASSERT( ! layerId.isEmpty() );
1179 QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1186 profile.switchTask( tr(
"Load layer source" ) );
1189 profile.switchTask( tr(
"Add layer to project" ) );
1190 QList<QgsMapLayer *> newLayers;
1202 QgsDebugMsg(
"Unable to load " + type +
" layer" );
1203 brokenNodes.push_back( layerElem );
1208 if ( ! layerWasStored )
1213 return layerIsValid;
1218 mFile.setFileName( filename );
1219 mCachedHomePath.clear();
1220 mProjectScope.reset();
1222 return read( flags );
1227 QString filename = mFile.fileName();
1232 QTemporaryFile inDevice;
1233 if ( !inDevice.open() )
1235 setError( tr(
"Unable to open %1" ).arg( inDevice.fileName() ) );
1241 if ( !storage->readProject( filename, &inDevice, context ) )
1243 QString err = tr(
"Unable to open %1" ).arg( filename );
1244 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
1245 if ( !messages.isEmpty() )
1246 err += QStringLiteral(
"\n\n" ) + messages.last().message();
1250 returnValue = unzip( inDevice.fileName(), flags );
1256 returnValue = unzip( mFile.fileName(), flags );
1261 returnValue = readProjectFile( mFile.fileName(), flags );
1267 mFile.setFileName( filename );
1268 mCachedHomePath.clear();
1269 mProjectScope.reset();
1274 mTranslator.reset(
nullptr );
1281 bool QgsProject::readProjectFile(
const QString &filename, QgsProject::ReadFlags flags )
1283 QFile projectFile( filename );
1291 QString localeFileName = QStringLiteral(
"%1_%2" ).arg( QFileInfo( projectFile.fileName() ).baseName(), settings.
value( QStringLiteral(
"locale/userLocale" ), QString() ).toString() );
1293 if ( QFile( QStringLiteral(
"%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1295 mTranslator.reset(
new QTranslator() );
1296 mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1299 profile.switchTask( tr(
"Reading project file" ) );
1300 std::unique_ptr<QDomDocument> doc(
new QDomDocument( QStringLiteral(
"qgis" ) ) );
1302 if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1304 projectFile.close();
1306 setError( tr(
"Unable to open %1" ).arg( projectFile.fileName() ) );
1315 if ( !doc->setContent( &projectFile, &errorMsg, &line, &column ) )
1319 QMessageBox::critical( 0, tr(
"Read Project File" ),
1320 tr(
"%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
1323 QString errorString = tr(
"Project file read error in file %1: %2 at line %3 column %4" )
1324 .arg( projectFile.fileName(), errorMsg ).arg( line ).arg( column );
1328 projectFile.close();
1330 setError( tr(
"%1 for file %2" ).arg( errorString, projectFile.fileName() ) );
1335 projectFile.close();
1343 profile.switchTask( tr(
"Updating project file" ) );
1344 if ( thisVersion > fileVersion )
1347 "version of qgis (saved in " + fileVersion.
text() +
1349 "). Problems may occur." );
1356 projectFile.updateRevision( thisVersion );
1360 profile.switchTask( tr(
"Creating auxiliary storage" ) );
1361 QString
fileName = mFile.fileName();
1362 std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
1364 mAuxiliaryStorage = std::move( aStorage );
1366 mCachedHomePath.clear();
1367 mProjectScope.reset();
1368 mSaveVersion = fileVersion;
1371 profile.switchTask( tr(
"Reading properties" ) );
1380 dump_( mProperties );
1385 _getTitle( *doc, oldTitle );
1387 readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1389 QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral(
"homePath" ) );
1390 if ( homePathNl.count() > 0 )
1392 QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1393 QString
homePath = homePathElement.attribute( QStringLiteral(
"path" ) );
1403 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), 255 ),
1404 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), 255 ) );
1407 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), 255 ),
1408 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), 255 ),
1409 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), 255 ) );
1418 if (
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ), 0 ) )
1421 QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral(
"projectCrs" ) );
1422 if ( !srsNode.isNull() )
1424 projectCrs.
readXml( srsNode );
1429 QString projCrsString =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSProj4String" ) );
1430 long currentCRS =
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSID" ), -1 );
1431 const QString authid =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCrs" ) );
1434 bool isUserAuthId = authid.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive );
1435 if ( !authid.isEmpty() && !isUserAuthId )
1439 if ( !projectCrs.
isValid() && currentCRS >= 0 )
1445 if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.
isValid() || projectCrs.
toProj() != projCrsString ) )
1459 QStringList datumErrors;
1460 if ( !mTransformContext.
readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
1468 QStringList variableNames =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ) );
1469 QStringList variableValues =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ) );
1471 mCustomVariables.clear();
1472 if ( variableNames.length() == variableValues.length() )
1474 for (
int i = 0; i < variableNames.length(); ++i )
1476 mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
1481 QgsMessageLog::logMessage( tr(
"Project Variables Invalid" ), tr(
"The project contains invalid variable settings." ) );
1484 QDomNodeList nl = doc->elementsByTagName( QStringLiteral(
"projectMetadata" ) );
1485 if ( !nl.isEmpty() )
1487 QDomElement metadataElement = nl.at( 0 ).toElement();
1495 if ( mMetadata.
title().isEmpty() && !oldTitle.isEmpty() )
1502 nl = doc->elementsByTagName( QStringLiteral(
"autotransaction" ) );
1505 QDomElement transactionElement = nl.at( 0 ).toElement();
1506 if ( transactionElement.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1507 mAutoTransaction =
true;
1510 nl = doc->elementsByTagName( QStringLiteral(
"evaluateDefaultValues" ) );
1513 QDomElement evaluateDefaultValuesElement = nl.at( 0 ).toElement();
1514 if ( evaluateDefaultValuesElement.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1515 mEvaluateDefaultValues =
true;
1519 nl = doc->elementsByTagName( QStringLiteral(
"trust" ) );
1522 QDomElement trustElement = nl.at( 0 ).toElement();
1523 if ( trustElement.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1524 mTrustLayerMetadata =
true;
1528 profile.switchTask( tr(
"Loading layer tree" ) );
1531 QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
1532 if ( !layerTreeElem.isNull() )
1541 mLayerTreeRegistryBridge->
setEnabled(
false );
1544 profile.switchTask( tr(
"Reading map layers" ) );
1546 QList<QDomNode> brokenNodes;
1547 bool clean = _getMapLayers( *doc, brokenNodes, flags );
1552 QgsDebugMsg( QStringLiteral(
"Unable to get map layers from project file." ) );
1554 if ( !brokenNodes.isEmpty() )
1556 QgsDebugMsg(
"there are " + QString::number( brokenNodes.size() ) +
" broken layers" );
1564 mMainAnnotationLayer->
readLayerXml( doc->documentElement().firstChildElement( QStringLiteral(
"main-annotation-layer" ) ), context );
1569 profile.switchTask( tr(
"Resolving layer references" ) );
1570 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
1571 for ( QMap<QString, QgsMapLayer *>::iterator it =
layers.begin(); it !=
layers.end(); ++it )
1573 it.value()->resolveReferences(
this );
1576 mLayerTreeRegistryBridge->
setEnabled(
true );
1579 profile.switchTask( tr(
"Loading embedded layers" ) );
1580 loadEmbeddedNodes( mRootGroup, flags );
1583 profile.switchTask( tr(
"Resolving references" ) );
1586 if ( !layerTreeElem.isNull() )
1592 QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-canvas" ) );
1593 if ( !layerTreeCanvasElem.isNull( ) )
1601 const QStringList requiredLayerIds =
readListEntry( QStringLiteral(
"RequiredLayers" ), QStringLiteral(
"Layers" ) );
1602 for (
const QString &layerId : requiredLayerIds )
1609 const QStringList disabledLayerIds =
readListEntry( QStringLiteral(
"Identify" ), QStringLiteral(
"/disabledLayers" ) );
1610 for (
const QString &layerId : disabledLayerIds )
1626 profile.switchTask( tr(
"Loading map themes" ) );
1629 mMapThemeCollection->readXml( *doc );
1631 profile.switchTask( tr(
"Loading label settings" ) );
1632 mLabelingEngineSettings->readSettingsFromProject(
this );
1635 profile.switchTask( tr(
"Loading annotations" ) );
1636 mAnnotationManager->readXml( doc->documentElement(), context );
1639 profile.switchTask( tr(
"Loading layouts" ) );
1640 mLayoutManager->readXml( doc->documentElement(), *doc );
1642 profile.switchTask( tr(
"Loading bookmarks" ) );
1643 mBookmarkManager->
readXml( doc->documentElement(), *doc );
1646 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
1647 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
1649 it.value()->setDependencies( it.value()->dependencies() );
1652 profile.switchTask( tr(
"Loading snapping settings" ) );
1656 profile.switchTask( tr(
"Loading view settings" ) );
1659 const QStringList scales =
readListEntry( QStringLiteral(
"Scales" ), QStringLiteral(
"/ScalesList" ) );
1660 QVector<double> res;
1661 for (
const QString &scale : scales )
1663 const QStringList parts = scale.split(
':' );
1664 if ( parts.size() != 2 )
1668 const double denominator = QLocale().toDouble( parts[1], &ok );
1675 QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectViewSettings" ) );
1676 if ( !viewSettingsElement.isNull() )
1677 mViewSettings->
readXml( viewSettingsElement, context );
1680 profile.switchTask( tr(
"Loading temporal settings" ) );
1681 QDomElement timeSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectTimeSettings" ) );
1682 if ( !timeSettingsElement.isNull() )
1683 mTimeSettings->
readXml( timeSettingsElement, context );
1685 profile.switchTask( tr(
"Loading display settings" ) );
1686 QDomElement displaySettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectDisplaySettings" ) );
1687 if ( !displaySettingsElement.isNull() )
1688 mDisplaySettings->
readXml( displaySettingsElement, context );
1690 profile.switchTask( tr(
"Updating variables" ) );
1692 profile.switchTask( tr(
"Updating CRS" ) );
1697 profile.switchTask( tr(
"Reading external settings" ) );
1701 profile.switchTask( tr(
"Updating interface" ) );
1711 QgsDebugMsgLevel( QString(
"Project save user: %1" ).arg( mSaveUser ), 2 );
1712 QgsDebugMsgLevel( QString(
"Project save user: %1" ).arg( mSaveUserFull ), 2 );
1721 QString newFileName( QStringLiteral(
"%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
1738 bool QgsProject::loadEmbeddedNodes(
QgsLayerTreeGroup *group, QgsProject::ReadFlags flags )
1741 const auto constChildren = group->
children();
1747 if ( childGroup->
customProperty( QStringLiteral(
"embedded" ) ).toInt() )
1750 QString projectPath =
readPath( childGroup->
customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
1751 childGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectPath );
1755 QList<QgsLayerTreeNode *> clonedChildren;
1756 const auto constChildren = newGroup->
children();
1758 clonedChildren << newGroupChild->clone();
1766 loadEmbeddedNodes( childGroup, flags );
1771 if ( child->customProperty( QStringLiteral(
"embedded" ) ).toInt() )
1773 QList<QDomNode> brokenNodes;
1776 valid = valid &&
false;
1788 return mCustomVariables;
1793 if ( variables == mCustomVariables )
1797 QStringList variableNames;
1798 QStringList variableValues;
1800 QVariantMap::const_iterator it = variables.constBegin();
1801 for ( ; it != variables.constEnd(); ++it )
1803 variableNames << it.key();
1804 variableValues << it.value().toString();
1807 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ), variableNames );
1808 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ), variableValues );
1810 mCustomVariables = variables;
1811 mProjectScope.reset();
1818 *mLabelingEngineSettings = settings;
1824 return *mLabelingEngineSettings;
1829 mProjectScope.reset();
1830 return mLayerStore.get();
1835 return mLayerStore.get();
1840 QList<QgsVectorLayer *>
layers;
1841 QStringList layerIds =
readListEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), QStringList() );
1842 const auto constLayerIds = layerIds;
1843 for (
const QString &layerId : constLayerIds )
1854 const auto constLayers =
layers;
1856 list << layer->id();
1857 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), list );
1874 if ( mProjectScope )
1876 std::unique_ptr< QgsExpressionContextScope > projectScope = qgis::make_unique< QgsExpressionContextScope >( *mProjectScope );
1880 return projectScope.release();
1883 mProjectScope = qgis::make_unique< QgsExpressionContextScope >( QObject::tr(
"Project" ) );
1887 QVariantMap::const_iterator it = vars.constBegin();
1889 for ( ; it != vars.constEnd(); ++it )
1891 mProjectScope->setVariable( it.key(), it.value(),
true );
1895 if ( projectPath.isEmpty() )
1896 projectPath = mOriginalPath;
1897 QString projectFolder = QFileInfo( projectPath ).path();
1898 QString projectFilename = QFileInfo( projectPath ).fileName();
1899 QString projectBasename =
baseName();
1928 QVariantMap keywords;
1930 for (
auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
1932 keywords.insert( it.key(), it.value() );
1937 QVariantList layersIds;
1939 const QMap<QString, QgsMapLayer *> layersInProject = mLayerStore->mapLayers();
1940 layersIds.reserve( layersInProject.count() );
1941 layers.reserve( layersInProject.count() );
1942 for (
auto it = layersInProject.constBegin(); it != layersInProject.constEnd(); ++it )
1944 layersIds << it.value()->id();
1950 mProjectScope->addFunction( QStringLiteral(
"project_color" ),
new GetNamedProjectColor(
this ) );
1955 void QgsProject::onMapLayersAdded(
const QList<QgsMapLayer *> &layers )
1957 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
1959 bool tgChanged =
false;
1961 const auto constLayers =
layers;
1964 if ( layer->isValid() )
1966 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
1973 const QString connString = QgsTransaction::connectionString( vlayer->
source() );
1981 mTransactionGroups.insert( qMakePair( key, connString ), tg );
1996 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
1998 QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
1999 if ( deps.contains( layer->id() ) )
2002 it.value()->setDependencies( deps );
2012 void QgsProject::onMapLayersRemoved(
const QList<QgsMapLayer *> &layers )
2018 void QgsProject::cleanTransactionGroups(
bool force )
2020 bool changed =
false;
2021 for ( QMap< QPair< QString, QString>,
QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
2023 if ( tg.value()->
isEmpty() || force )
2026 tg = mTransactionGroups.erase( tg );
2044 QList<QDomNode> brokenNodes;
2045 if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
2049 QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
2050 const auto constVectorLayers = vectorLayers;
2054 layer->resolveReferences(
this );
2064 mFile.setFileName( filename );
2065 mCachedHomePath.clear();
2071 mProjectScope.reset();
2077 QString storageFilePath { storage->filePath( mFile.fileName() ) };
2078 if ( storageFilePath.isEmpty() )
2080 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
true );
2084 QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2085 QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2087 if ( !zip( tmpZipFilename ) )
2090 QFile tmpZipFile( tmpZipFilename );
2091 if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2093 setError( tr(
"Unable to read file %1" ).arg( tmpZipFilename ) );
2098 if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2100 QString err = tr(
"Unable to save project to storage %1" ).arg( mFile.fileName() );
2101 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
2102 if ( !messages.isEmpty() )
2103 err += QStringLiteral(
"\n\n" ) + messages.last().message();
2109 QFile::remove( tmpZipFilename );
2116 return zip( mFile.fileName() );
2122 const bool asOk = saveAuxiliaryStorage();
2123 const bool writeOk = writeProjectFile( mFile.fileName() );
2126 if ( !asOk && writeOk )
2128 const QString err = mAuxiliaryStorage->errorString();
2129 setError( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
2132 return asOk && writeOk;
2136 bool QgsProject::writeProjectFile(
const QString &filename )
2138 QFile projectFile( filename );
2144 QFileInfo myFileInfo( projectFile );
2145 if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2147 setError( tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
2148 .arg( projectFile.fileName() ) );
2156 QDomImplementation DomImplementation;
2157 DomImplementation.setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2159 QDomDocumentType documentType =
2160 DomImplementation.createDocumentType( QStringLiteral(
"qgis" ), QStringLiteral(
"http://mrcc.com/qgis.dtd" ),
2161 QStringLiteral(
"SYSTEM" ) );
2162 std::unique_ptr<QDomDocument> doc(
new QDomDocument( documentType ) );
2164 QDomElement qgisNode = doc->createElement( QStringLiteral(
"qgis" ) );
2165 qgisNode.setAttribute( QStringLiteral(
"projectname" ),
title() );
2166 qgisNode.setAttribute( QStringLiteral(
"version" ),
Qgis::version() );
2169 if ( !settings.
value( QStringLiteral(
"projects/anonymize_saved_projects" ),
false,
QgsSettings::Core ).toBool() )
2173 qgisNode.setAttribute( QStringLiteral(
"saveUser" ), newSaveUser );
2174 qgisNode.setAttribute( QStringLiteral(
"saveUserFull" ), newSaveUserFull );
2175 mSaveUser = newSaveUser;
2176 mSaveUserFull = newSaveUserFull;
2177 mSaveDateTime = QDateTime::currentDateTime();
2178 qgisNode.setAttribute( QStringLiteral(
"saveDateTime" ), mSaveDateTime.toString( Qt::ISODate ) );
2183 mSaveUserFull.clear();
2184 mSaveDateTime = QDateTime();
2186 doc->appendChild( qgisNode );
2189 QDomElement homePathNode = doc->createElement( QStringLiteral(
"homePath" ) );
2190 homePathNode.setAttribute( QStringLiteral(
"path" ), mHomePath );
2191 qgisNode.appendChild( homePathNode );
2194 QDomElement titleNode = doc->createElement( QStringLiteral(
"title" ) );
2195 qgisNode.appendChild( titleNode );
2197 QDomElement transactionNode = doc->createElement( QStringLiteral(
"autotransaction" ) );
2198 transactionNode.setAttribute( QStringLiteral(
"active" ), mAutoTransaction ? 1 : 0 );
2199 qgisNode.appendChild( transactionNode );
2201 QDomElement evaluateDefaultValuesNode = doc->createElement( QStringLiteral(
"evaluateDefaultValues" ) );
2202 evaluateDefaultValuesNode.setAttribute( QStringLiteral(
"active" ), mEvaluateDefaultValues ? 1 : 0 );
2203 qgisNode.appendChild( evaluateDefaultValuesNode );
2205 QDomElement trustNode = doc->createElement( QStringLiteral(
"trust" ) );
2206 trustNode.setAttribute( QStringLiteral(
"active" ), mTrustLayerMetadata ? 1 : 0 );
2207 qgisNode.appendChild( trustNode );
2209 QDomText titleText = doc->createTextNode(
title() );
2210 titleNode.appendChild( titleText );
2213 QDomElement srsNode = doc->createElement( QStringLiteral(
"projectCrs" ) );
2215 qgisNode.appendChild( srsNode );
2222 clonedRoot->
writeXml( qgisNode, context );
2226 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsMode" ),
static_cast<int>( mAvoidIntersectionsMode ) );
2234 QDomElement annotationLayerNode = doc->createElement( QStringLiteral(
"main-annotation-layer" ) );
2235 mMainAnnotationLayer->
writeLayerXml( annotationLayerNode, *doc, context );
2236 qgisNode.appendChild( annotationLayerNode );
2240 QDomElement projectLayersNode = doc->createElement( QStringLiteral(
"projectlayers" ) );
2242 QMap<QString, QgsMapLayer *>::ConstIterator li =
layers.constBegin();
2243 while ( li !=
layers.end() )
2249 QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->
id() );
2250 if ( emIt == mEmbeddedLayers.constEnd() )
2252 QDomElement maplayerElem;
2258 maplayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2263 QDomDocument document;
2266 maplayerElem = document.firstChildElement();
2270 QgsDebugMsg( QStringLiteral(
"Could not restore layer properties for layer %1" ).arg( ml->
id() ) );
2276 projectLayersNode.appendChild( maplayerElem );
2282 if ( emIt.value().second )
2284 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2285 mapLayerElem.setAttribute( QStringLiteral(
"embedded" ), 1 );
2286 mapLayerElem.setAttribute( QStringLiteral(
"project" ),
writePath( emIt.value().first ) );
2287 mapLayerElem.setAttribute( QStringLiteral(
"id" ), ml->
id() );
2288 projectLayersNode.appendChild( mapLayerElem );
2295 qgisNode.appendChild( projectLayersNode );
2297 QDomElement layerOrderNode = doc->createElement( QStringLiteral(
"layerorder" ) );
2299 for (
QgsMapLayer *layer : constCustomLayerOrder )
2301 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"layer" ) );
2302 mapLayerElem.setAttribute( QStringLiteral(
"id" ), layer->id() );
2303 layerOrderNode.appendChild( mapLayerElem );
2305 qgisNode.appendChild( layerOrderNode );
2307 mLabelingEngineSettings->writeSettingsToProject(
this );
2309 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorRedPart" ), mBackgroundColor.red() );
2310 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), mBackgroundColor.green() );
2311 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), mBackgroundColor.blue() );
2313 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorRedPart" ), mSelectionColor.red() );
2314 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), mSelectionColor.green() );
2315 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), mSelectionColor.blue() );
2316 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), mSelectionColor.alpha() );
2320 dump_( mProperties );
2323 QgsDebugMsgLevel( QStringLiteral(
"there are %1 property scopes" ).arg(
static_cast<int>( mProperties.
count() ) ), 2 );
2328 mProperties.
writeXml( QStringLiteral(
"properties" ), qgisNode, *doc );
2331 QDomElement ddElem = doc->createElement( QStringLiteral(
"dataDefinedServerProperties" ) );
2332 mDataDefinedServerProperties.
writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
2333 qgisNode.appendChild( ddElem );
2335 mMapThemeCollection->writeXml( *doc );
2337 mTransformContext.
writeXml( qgisNode, context );
2339 QDomElement metadataElem = doc->createElement( QStringLiteral(
"projectMetadata" ) );
2341 qgisNode.appendChild( metadataElem );
2343 QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
2344 qgisNode.appendChild( annotationsElem );
2346 QDomElement layoutElem = mLayoutManager->writeXml( *doc );
2347 qgisNode.appendChild( layoutElem );
2349 QDomElement bookmarkElem = mBookmarkManager->
writeXml( *doc );
2350 qgisNode.appendChild( bookmarkElem );
2352 QDomElement viewSettingsElem = mViewSettings->
writeXml( *doc, context );
2353 qgisNode.appendChild( viewSettingsElem );
2355 QDomElement timeSettingsElement = mTimeSettings->
writeXml( *doc, context );
2356 qgisNode.appendChild( timeSettingsElement );
2358 QDomElement displaySettingsElem = mDisplaySettings->
writeXml( *doc, context );
2359 qgisNode.appendChild( displaySettingsElem );
2367 QFile backupFile( QStringLiteral(
"%1~" ).arg( filename ) );
2369 ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
2370 ok &= projectFile.open( QIODevice::ReadOnly );
2373 while ( ok && !projectFile.atEnd() )
2375 ba = projectFile.read( 10240 );
2376 ok &= backupFile.write( ba ) == ba.size();
2379 projectFile.close();
2384 setError( tr(
"Unable to create backup file %1" ).arg( backupFile.fileName() ) );
2389 struct utimbuf tb = {
static_cast<time_t
>( fi.lastRead().toSecsSinceEpoch() ),
static_cast<time_t
>( fi.lastModified().toSecsSinceEpoch() ) };
2390 utime( backupFile.fileName().toUtf8().constData(), &tb );
2393 if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
2395 projectFile.close();
2398 setError( tr(
"Unable to save to file %1" ).arg( projectFile.fileName() ) );
2402 QTemporaryFile tempFile;
2403 bool ok = tempFile.open();
2406 QTextStream projectFileStream( &tempFile );
2407 doc->save( projectFileStream, 2 );
2408 ok &= projectFileStream.pos() > -1;
2410 ok &= tempFile.seek( 0 );
2413 while ( ok && !tempFile.atEnd() )
2415 ba = tempFile.read( 10240 );
2416 ok &= projectFile.write( ba ) == ba.size();
2419 ok &= projectFile.error() == QFile::NoError;
2421 projectFile.close();
2428 setError( tr(
"Unable to save to file %1. Your project "
2429 "may be corrupted on disk. Try clearing some space on the volume and "
2430 "check file permissions before pressing save again." )
2431 .arg( projectFile.fileName() ) );
2443 bool propertiesModified;
2444 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2446 if ( propertiesModified )
2454 bool propertiesModified;
2455 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2457 if ( propertiesModified )
2465 bool propertiesModified;
2466 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2468 if ( propertiesModified )
2476 bool propertiesModified;
2477 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2479 if ( propertiesModified )
2487 bool propertiesModified;
2488 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2490 if ( propertiesModified )
2498 const QStringList &def,
2507 value =
property->value();
2509 bool valid = QVariant::StringList == value.type();
2515 return value.toStringList();
2537 value =
property->value();
2539 bool valid = value.canConvert( QVariant::String );
2544 return value.toString();
2561 value =
property->value();
2564 bool valid = value.canConvert( QVariant::Int );
2573 return value.toInt();
2586 QVariant value =
property->value();
2588 bool valid = value.canConvert( QVariant::Double );
2593 return value.toDouble();
2608 QVariant value =
property->value();
2610 bool valid = value.canConvert( QVariant::Bool );
2615 return value.toBool();
2625 if (
findKey_( scope, key, mProperties ) )
2631 return !
findKey_( scope, key, mProperties );
2639 QStringList entries;
2641 if ( foundProperty )
2656 QStringList entries;
2658 if ( foundProperty )
2671 dump_( mProperties );
2676 bool absolutePaths =
readBoolEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
2678 if ( ! absolutePaths )
2685 filePath = storage->filePath( mFile.fileName() );
2705 void QgsProject::setError(
const QString &errorMessage )
2707 mErrorMessage = errorMessage;
2712 return mErrorMessage;
2715 void QgsProject::clearError()
2717 setError( QString() );
2722 delete mBadLayerHandler;
2723 mBadLayerHandler = handler;
2728 QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find(
id );
2729 if ( it == mEmbeddedLayers.constEnd() )
2733 return it.value().first;
2737 bool saveFlag, QgsProject::ReadFlags flags )
2741 static QString sPrevProjectFilePath;
2742 static QDateTime sPrevProjectFileTimestamp;
2743 static QDomDocument sProjectDocument;
2745 QString qgsProjectFile = projectFilePath;
2747 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
2749 archive.
unzip( projectFilePath );
2753 QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
2755 if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
2757 sPrevProjectFilePath.clear();
2759 QFile projectFile( qgsProjectFile );
2760 if ( !projectFile.open( QIODevice::ReadOnly ) )
2765 if ( !sProjectDocument.setContent( &projectFile ) )
2770 sPrevProjectFilePath = projectFilePath;
2771 sPrevProjectFileTimestamp = projectFileTimestamp;
2775 bool useAbsolutePaths =
true;
2777 QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
2778 if ( !propertiesElem.isNull() )
2780 QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral(
"Paths" ) ).firstChildElement( QStringLiteral(
"Absolute" ) );
2781 if ( !absElem.isNull() )
2783 useAbsolutePaths = absElem.text().compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
2788 if ( !useAbsolutePaths )
2793 QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) );
2794 if ( projectLayersElem.isNull() )
2799 QDomNodeList mapLayerNodes = projectLayersElem.elementsByTagName( QStringLiteral(
"maplayer" ) );
2800 for (
int i = 0; i < mapLayerNodes.size(); ++i )
2803 QDomElement mapLayerElem = mapLayerNodes.at( i ).toElement();
2804 QString
id = mapLayerElem.firstChildElement( QStringLiteral(
"id" ) ).text();
2805 if (
id == layerId )
2808 if ( mapLayerElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
2813 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
2815 if ( addLayer( mapLayerElem, brokenNodes, embeddedContext, flags ) )
2821 mEmbeddedLayers.remove( layerId );
2833 QString qgsProjectFile = projectFilePath;
2835 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
2837 archive.
unzip( projectFilePath );
2842 QFile projectFile( qgsProjectFile );
2843 if ( !projectFile.open( QIODevice::ReadOnly ) )
2848 QDomDocument projectDocument;
2849 if ( !projectDocument.setContent( &projectFile ) )
2861 QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
2862 if ( !layerTreeElem.isNull() )
2872 if ( !group || group->
customProperty( QStringLiteral(
"embedded" ) ).toBool() )
2885 newGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectFilePath );
2888 mLayerTreeRegistryBridge->
setEnabled(
false );
2889 initializeEmbeddedSubtree( projectFilePath, newGroup, flags );
2890 mLayerTreeRegistryBridge->
setEnabled(
true );
2893 const auto constFindLayerIds = newGroup->
findLayerIds();
2894 for (
const QString &layerId : constFindLayerIds )
2907 void QgsProject::initializeEmbeddedSubtree(
const QString &projectFilePath,
QgsLayerTreeGroup *group, QgsProject::ReadFlags flags )
2909 const auto constChildren = group->
children();
2913 child->setCustomProperty( QStringLiteral(
"embedded" ), 1 );
2922 QList<QDomNode> brokenNodes;
2930 return mEvaluateDefaultValues;
2939 QMap<QString, QgsMapLayer *>::const_iterator layerIt =
layers.constBegin();
2940 for ( ; layerIt !=
layers.constEnd(); ++layerIt )
2942 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() );
2954 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
2960 return readNumEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), 0 );
2965 QString distanceUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), QString() );
2966 if ( !distanceUnitString.isEmpty() )
2983 QString areaUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), QString() );
2984 if ( !areaUnitString.isEmpty() )
3001 if ( !mCachedHomePath.isEmpty() )
3002 return mCachedHomePath;
3006 if ( !mHomePath.isEmpty() )
3008 QFileInfo homeInfo( mHomePath );
3009 if ( !homeInfo.isRelative() )
3011 mCachedHomePath = mHomePath;
3017 mCachedHomePath = pfi.path();
3019 return mCachedHomePath;
3022 if ( !pfi.exists() )
3024 mCachedHomePath = mHomePath;
3028 if ( !mHomePath.isEmpty() )
3031 mCachedHomePath = QDir::cleanPath( pfi.path() +
'/' + mHomePath );
3035 mCachedHomePath = pfi.canonicalPath();
3037 return mCachedHomePath;
3047 return mRelationManager;
3052 return mLayoutManager.get();
3057 return mLayoutManager.get();
3062 return mBookmarkManager;
3067 return mBookmarkManager;
3072 return mViewSettings;
3077 return mViewSettings;
3082 return mTimeSettings;
3087 return mTimeSettings;
3092 return mDisplaySettings;
3097 return mDisplaySettings;
3107 return mMapThemeCollection.get();
3112 return mAnnotationManager.get();
3117 return mAnnotationManager.get();
3122 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
3123 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3128 if (
layers.contains( it.value() ) )
3143 for (
const QString &layerId : layerIds )
3159 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3171 return mAutoTransaction;
3181 onMapLayersAdded(
mapLayers().values() );
3183 cleanTransactionGroups(
true );
3189 return mTransactionGroups;
3200 return mLayerStore->count();
3205 return mLayerStore->validCount();
3210 return mLayerStore->mapLayer( layerId );
3215 return mLayerStore->mapLayersByName( layerName );
3220 QList<QgsMapLayer *>
layers;
3221 const auto constMapLayers { mLayerStore->mapLayers() };
3222 for (
const auto &l : constMapLayers )
3224 if ( ! l->shortName().isEmpty() )
3226 if ( l->shortName() == shortName )
3229 else if ( l->name() == shortName )
3237 bool QgsProject::unzip(
const QString &filename, QgsProject::ReadFlags flags )
3243 if ( !archive->unzip( filename ) )
3245 setError( tr(
"Unable to unzip file '%1'" ).arg( filename ) );
3250 if ( archive->projectFile().isEmpty() )
3252 setError( tr(
"Zip archive does not provide a project file" ) );
3257 if ( !archive->auxiliaryStorageFile().isEmpty() )
3261 mAuxiliaryStorage.reset(
new QgsAuxiliaryStorage( archive->auxiliaryStorageFile(),
false ) );
3269 if ( ! readProjectFile( archive->projectFile(), flags ) )
3271 setError( tr(
"Cannot read unzipped qgs project file" ) );
3276 mArchive = std::move( archive );
3277 mArchive->clearProjectFile();
3282 bool QgsProject::zip(
const QString &filename )
3288 const QString
baseName = QFileInfo( filename ).baseName();
3289 const QString qgsFileName = QStringLiteral(
"%1.qgs" ).arg(
baseName );
3290 QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
3292 bool writeOk =
false;
3293 if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3295 writeOk = writeProjectFile( qgsFile.fileName() );
3302 setError( tr(
"Unable to write temporary qgs file" ) );
3307 const QFileInfo info( qgsFile );
3310 if ( ! saveAuxiliaryStorage( asFileName ) )
3312 const QString err = mAuxiliaryStorage->errorString();
3313 setError( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
3318 archive->addFile( qgsFile.fileName() );
3319 archive->addFile( asFileName );
3322 if ( !archive->zip( filename ) )
3324 setError( tr(
"Unable to perform zip" ) );
3337 const QList<QgsMapLayer *> &layers,
3339 bool takeOwnership )
3341 const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers(
layers, takeOwnership ) };
3342 if ( !myResultList.isEmpty() )
3345 for (
auto &l : myResultList )
3355 if ( mAuxiliaryStorage )
3370 mProjectScope.reset();
3372 return myResultList;
3378 bool takeOwnership )
3380 QList<QgsMapLayer *> addedLayers;
3381 addedLayers =
addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
3382 return addedLayers.isEmpty() ? nullptr : addedLayers[0];
3387 mProjectScope.reset();
3388 mLayerStore->removeMapLayers( layerIds );
3393 mProjectScope.reset();
3394 mLayerStore->removeMapLayers(
layers );
3399 mProjectScope.reset();
3400 mLayerStore->removeMapLayer( layerId );
3405 mProjectScope.reset();
3406 mLayerStore->removeMapLayer( layer );
3411 mProjectScope.reset();
3412 return mLayerStore->takeMapLayer( layer );
3417 return mMainAnnotationLayer;
3422 mProjectScope.reset();
3423 mLayerStore->removeAllMapLayers();
3428 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
3429 QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin();
3430 for ( ; it !=
layers.constEnd(); ++it )
3432 it.value()->reload();
3438 return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
3443 return mTransactionGroups.value( qMakePair( providerKey, connString ) );
3453 if ( settings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), QStringLiteral(
"NoAction" ),
QgsSettings::App ).toString() == QStringLiteral(
"UseProjectCrs" )
3454 || settings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), 0,
QgsSettings::App ).toString() == 2 )
3462 QString layerDefaultCrs = settings.
value( QStringLiteral(
"/Projections/layerDefaultCrs" ),
geoEpsgCrsAuthId() ).toString();
3471 mTrustLayerMetadata = trust;
3474 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3476 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
3484 bool QgsProject::saveAuxiliaryStorage(
const QString &filename )
3488 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3493 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
3501 if ( !mAuxiliaryStorage->exists( *
this ) && filename.isEmpty() && empty )
3505 else if ( !filename.isEmpty() )
3507 return mAuxiliaryStorage->saveAs( filename );
3511 return mAuxiliaryStorage->saveAs( *
this );
3520 QgsProject::DataDefinedServerProperty::WMSOnlineResource,
3524 return sPropertyDefinitions;
3529 return mAuxiliaryStorage.get();
3534 return mAuxiliaryStorage.get();
3548 mProjectScope.reset();
3560 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3572 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
3573 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3578 if (
layers.contains( it.value() ) )
3588 QStringList customColors;
3589 QStringList customColorLabels;
3591 QgsNamedColorList::const_iterator colorIt = colors.constBegin();
3592 for ( ; colorIt != colors.constEnd(); ++colorIt )
3595 QString label = ( *colorIt ).second;
3596 customColors.append( color );
3597 customColorLabels.append( label );
3599 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ), customColors );
3600 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ), customColorLabels );
3601 mProjectScope.reset();
3607 if ( mBackgroundColor == color )
3610 mBackgroundColor = color;
3616 return mBackgroundColor;
3621 if ( mSelectionColor == color )
3624 mSelectionColor = color;
3630 return mSelectionColor;
3664 QString
QgsProject::translate(
const QString &context,
const QString &sourceText,
const char *disambiguation,
int n )
const
3671 QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
3673 if ( result.isEmpty() )
3685 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3690 if ( !( ( *it )->accept( visitor ) ) )
3699 if ( !mLayoutManager->accept( visitor ) )
3702 if ( !mAnnotationManager->accept( visitor ) )
3709 GetNamedProjectColor::GetNamedProjectColor(
const QgsProject *project )
3716 QStringList colorStrings = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ) );
3717 QStringList colorLabels = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ) );
3721 for ( QStringList::iterator it = colorStrings.begin();
3722 it != colorStrings.end(); ++it )
3726 if ( colorLabels.length() > colorIndex )
3728 label = colorLabels.at( colorIndex );
3731 mColors.insert( label.toLower(), color );
3736 GetNamedProjectColor::GetNamedProjectColor(
const QHash<QString, QColor> &colors )
3744 QString colorName = values.at( 0 ).toString().toLower();
3745 if ( mColors.contains( colorName ) )
3747 return QStringLiteral(
"%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
3755 return new GetNamedProjectColor( mColors );