66 #include <QApplication>
70 #include <QTextStream>
71 #include <QTemporaryFile>
77 #include <sys/utime.h>
95 QStringList keyTokens = QStringList( scope );
96 keyTokens += key.split(
'/', QString::SkipEmptyParts );
99 keyTokens.push_front( QStringLiteral(
"properties" ) );
102 for (
int i = 0; i < keyTokens.size(); ++i )
104 QString keyToken = keyTokens.at( i );
108 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]" );
109 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]" );
111 if ( keyToken.contains( QRegExp( nameCharRegexp ) ) || keyToken.contains( QRegExp( nameStartCharRegexp ) ) )
114 QString errorString = QObject::tr(
"Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
144 while ( !keySequence.isEmpty() )
148 if ( keySequence.first() == currentProperty->
name() )
151 keySequence.pop_front();
153 if ( 1 == keySequence.count() )
156 return currentProperty->
find( keySequence.front() );
158 else if ( keySequence.isEmpty() )
163 return currentProperty;
165 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
167 if ( nextProperty->
isKey() )
171 else if ( nextProperty->
isValue() && 1 == keySequence.count() )
177 return currentProperty;
215 const QVariant &value,
216 bool &propertiesModified )
225 propertiesModified =
false;
226 while ( ! keySequence.isEmpty() )
230 if ( keySequence.first() == currentProperty->
name() )
233 keySequence.pop_front();
237 if ( 1 == keySequence.count() )
240 if ( !property || property->value() != value )
242 currentProperty->
setValue( keySequence.front(), value );
243 propertiesModified =
true;
246 return currentProperty;
250 else if ( keySequence.isEmpty() )
252 if ( currentProperty->
value() != value )
255 propertiesModified =
true;
258 return currentProperty;
260 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
264 if ( currentProperty )
275 if ( ( newPropertyKey = currentProperty->
addKey( keySequence.first() ) ) )
277 currentProperty = newPropertyKey;
310 while ( ! keySequence.isEmpty() )
314 if ( keySequence.first() == currentProperty->
name() )
317 keySequence.pop_front();
321 if ( 1 == keySequence.count() )
323 currentProperty->
removeKey( keySequence.front() );
328 else if ( keySequence.isEmpty() )
330 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
332 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
334 previousQgsPropertyKey = currentProperty;
337 if ( currentProperty )
363 , mSnappingConfig( this )
376 mProperties.
setName( QStringLiteral(
"properties" ) );
389 this, [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
393 this, [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
395 this, [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
397 [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
399 [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
401 [ = ]() { mProjectScope.reset(); emit removeAll(); } );
403 [ = ](
const QList< QgsMapLayer * > &
layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
405 [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
413 [ = ](
const QList<QgsMapLayer *> &
layers )
415 for (
const auto &layer :
layers )
422 [ = ](
const QList<QgsMapLayer *> &
layers )
424 for (
const auto &layer :
layers )
439 mIsBeingDeleted =
true;
442 delete mBadLayerHandler;
443 delete mRelationManager;
444 delete mLayerTreeRegistryBridge;
446 if (
this == sProject )
452 void QgsProject::setInstance(
QgsProject *project )
473 mProjectScope.reset();
481 return mMetadata.
title();
491 return mSaveUserFull;
496 return mSaveDateTime;
506 if ( dirty && mDirtyBlockCount > 0 )
509 if ( mDirty == dirty )
518 if ( path == mHomePath )
522 mCachedHomePath.clear();
523 mProjectScope.reset();
532 const QList<QgsAttributeEditorElement *> elements = parent->
children();
540 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:formcontainers" ).arg( layerId ), container->
name() );
542 if ( !container->
children().empty() )
555 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1" ).arg( layer->layerId() ), layer->name() );
564 for (
const QgsField &field : fields )
567 if ( field.alias().isEmpty() )
568 fieldName = field.name();
570 fieldName = field.alias();
572 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fieldaliases" ).arg( vlayer->
id() ), fieldName );
574 if ( field.editorWidgetSetup().type() == QStringLiteral(
"ValueRelation" ) )
576 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fields:%2:valuerelationvalue" ).arg( vlayer->
id(), field.name() ), field.editorWidgetSetup().config().value( QStringLiteral(
"Value" ) ).toString() );
587 const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->
findGroups();
590 translationContext->
registerTranslation( QStringLiteral(
"project:layergroups" ), groupLayer->name() );
594 const QList<QgsRelation> &relations = mRelationManager->
relations().values();
597 translationContext->
registerTranslation( QStringLiteral(
"project:relations" ), relation.name() );
603 mDataDefinedServerProperties = properties;
608 return mDataDefinedServerProperties;
613 if ( name == mFile.fileName() )
618 mFile.setFileName( name );
619 mCachedHomePath.clear();
620 mProjectScope.reset();
625 if ( newHomePath != oldHomePath )
633 return mFile.fileName();
638 mOriginalPath = path;
643 return mOriginalPath;
648 return QFileInfo( mFile );
661 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
666 return QFileInfo( mFile.fileName() ).lastModified();
675 if ( mFile.fileName().isEmpty() )
678 return QFileInfo( mFile.fileName() ).absolutePath();
686 if ( mFile.fileName().isEmpty() )
689 return QFileInfo( mFile.fileName() ).absoluteFilePath();
697 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
702 return QFileInfo( mFile.fileName() ).completeBaseName();
716 writeEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ),
crs.
isValid() ? 1 : 0 );
717 mProjectScope.reset();
722 if ( adjustEllipsoid )
728 if ( !
crs().isValid() )
731 return readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ),
geoNone() );
736 if (
ellipsoid ==
readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ) ) )
739 mProjectScope.reset();
746 return mTransformContext;
751 if ( context == mTransformContext )
754 mTransformContext = context;
755 mProjectScope.reset();
757 for (
auto &layer : mLayerStore.get()->mapLayers() )
759 layer->setTransformContext( context );
768 mProjectScope.reset();
769 mFile.setFileName( QString() );
772 mSaveUserFull.clear();
773 mSaveDateTime = QDateTime();
775 mCachedHomePath.clear();
776 mAutoTransaction =
false;
777 mEvaluateDefaultValues =
false;
779 mTrustLayerMetadata =
false;
780 mCustomVariables.clear();
782 if ( !settings.
value( QStringLiteral(
"projects/anonymize_new_projects" ),
false,
QgsSettings::Core ).toBool() )
793 mEmbeddedLayers.clear();
794 mRelationManager->
clear();
795 mAnnotationManager->clear();
796 mLayoutManager->clear();
797 mBookmarkManager->
clear();
798 mViewSettings->
reset();
799 mTimeSettings->
reset();
800 mDisplaySettings->
reset();
801 mSnappingConfig.
reset();
809 mLabelingEngineSettings->clear();
816 if ( !mIsBeingDeleted )
824 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/Automatic" ),
true );
825 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/DecimalPlaces" ), 2 );
826 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
829 writeEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), settings.
value( QStringLiteral(
"/qgis/measure/displayunits" ) ).toString() );
830 writeEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), settings.
value( QStringLiteral(
"/qgis/measure/areaunits" ) ).toString() );
832 int red = settings.
value( QStringLiteral(
"qgis/default_canvas_color_red" ), 255 ).toInt();
833 int green = settings.
value( QStringLiteral(
"qgis/default_canvas_color_green" ), 255 ).toInt();
834 int blue = settings.
value( QStringLiteral(
"qgis/default_canvas_color_blue" ), 255 ).toInt();
837 red = settings.
value( QStringLiteral(
"qgis/default_selection_color_red" ), 255 ).toInt();
838 green = settings.
value( QStringLiteral(
"qgis/default_selection_color_green" ), 255 ).toInt();
839 blue = settings.
value( QStringLiteral(
"qgis/default_selection_color_blue" ), 0 ).toInt();
840 int alpha = settings.
value( QStringLiteral(
"qgis/default_selection_color_alpha" ), 255 ).toInt();
855 topQgsPropertyKey.
dump();
891 QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
893 if ( propertiesElem.isNull() )
898 QDomNodeList scopes = propertiesElem.childNodes();
900 if ( scopes.count() < 1 )
902 QgsDebugMsg( QStringLiteral(
"empty ``properties'' XML tag ... bailing" ) );
906 if ( ! project_properties.
readXml( propertiesElem ) )
908 QgsDebugMsg( QStringLiteral(
"Project_properties.readXml() failed" ) );
922 QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral(
"dataDefinedServerProperties" ) );
923 if ( !ddElem.isNull() )
925 if ( !ddServerProperties.
readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
927 QgsDebugMsg( QStringLiteral(
"dataDefinedServerProperties.readXml() failed" ) );
930 return ddServerProperties;
937 static void _getTitle(
const QDomDocument &doc, QString &title )
939 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"title" ) );
949 QDomNode titleNode = nl.item( 0 );
951 if ( !titleNode.hasChildNodes() )
957 QDomNode titleTextNode = titleNode.firstChild();
959 if ( !titleTextNode.isText() )
965 QDomText titleText = titleTextNode.toText();
967 title = titleText.data();
971 static void readProjectFileMetadata(
const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
973 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
981 QDomNode qgisNode = nl.item( 0 );
983 QDomElement qgisElement = qgisNode.toElement();
984 lastUser = qgisElement.attribute( QStringLiteral(
"saveUser" ), QString() );
985 lastUserFull = qgisElement.attribute( QStringLiteral(
"saveUserFull" ), QString() );
986 lastSaveDateTime = QDateTime::fromString( qgisElement.attribute( QStringLiteral(
"saveDateTime" ), QString() ), Qt::ISODate );
992 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
996 QgsDebugMsg( QStringLiteral(
" unable to find qgis element in project file" ) );
1000 QDomNode qgisNode = nl.item( 0 );
1002 QDomElement qgisElement = qgisNode.toElement();
1003 QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral(
"version" ) ) );
1004 return projectVersion;
1010 return mSnappingConfig;
1025 if ( mAvoidIntersectionsMode == mode )
1028 mAvoidIntersectionsMode = mode;
1032 bool QgsProject::_getMapLayers(
const QDomDocument &doc, QList<QDomNode> &brokenNodes, QgsProject::ReadFlags flags )
1037 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"maplayer" ) );
1041 if ( 0 == nl.count() )
1051 bool returnStatus =
true;
1057 if ( depSorter.hasCycle() || depSorter.hasMissingDependency() )
1060 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1061 const int totalLayerCount = sortedLayerNodes.count();
1064 for (
const QDomNode &node : sortedLayerNodes )
1066 const QDomElement element = node.toElement();
1068 const QString name =
translate( QStringLiteral(
"project:layers:%1" ).arg( node.namedItem( QStringLiteral(
"id" ) ).toElement().text() ), node.namedItem( QStringLiteral(
"layername" ) ).toElement().text() );
1069 if ( !name.isNull() )
1070 emit
loadingLayer( tr(
"Loading layer %1" ).arg( name ) );
1072 if ( element.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
1074 createEmbeddedLayer( element.attribute( QStringLiteral(
"id" ) ),
readPath( element.attribute( QStringLiteral(
"project" ) ) ), brokenNodes,
true, flags );
1083 if ( !addLayer( element, brokenNodes, context, flags ) )
1085 returnStatus =
false;
1088 if ( !messages.isEmpty() )
1097 return returnStatus;
1100 bool QgsProject::addLayer(
const QDomElement &layerElem, QList<QDomNode> &brokenNodes,
QgsReadWriteContext &context, QgsProject::ReadFlags flags )
1102 QString type = layerElem.attribute( QStringLiteral(
"type" ) );
1104 std::unique_ptr<QgsMapLayer>
mapLayer;
1106 if ( type == QLatin1String(
"vector" ) )
1108 mapLayer = qgis::make_unique<QgsVectorLayer>();
1112 vl->setReadExtentFromXml( mTrustLayerMetadata );
1115 else if ( type == QLatin1String(
"raster" ) )
1117 mapLayer = qgis::make_unique<QgsRasterLayer>();
1119 else if ( type == QLatin1String(
"mesh" ) )
1121 mapLayer = qgis::make_unique<QgsMeshLayer>();
1123 else if ( type == QLatin1String(
"vector-tile" ) )
1125 mapLayer = qgis::make_unique<QgsVectorTileLayer>();
1127 else if ( type == QLatin1String(
"plugin" ) )
1129 QString
typeName = layerElem.attribute( QStringLiteral(
"name" ) );
1135 QgsDebugMsg( QStringLiteral(
"Unable to create layer" ) );
1143 const QString layerId { layerElem.namedItem( QStringLiteral(
"id" ) ).toElement().text() };
1144 Q_ASSERT( ! layerId.isEmpty() );
1148 QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1152 QList<QgsMapLayer *> newLayers;
1164 QgsDebugMsg(
"Unable to load " + type +
" layer" );
1165 brokenNodes.push_back( layerElem );
1170 if ( ! layerWasStored )
1175 return layerIsValid;
1180 mFile.setFileName( filename );
1181 mCachedHomePath.clear();
1182 mProjectScope.reset();
1184 return read( flags );
1189 QString filename = mFile.fileName();
1194 QTemporaryFile inDevice;
1195 if ( !inDevice.open() )
1197 setError( tr(
"Unable to open %1" ).arg( inDevice.fileName() ) );
1203 if ( !storage->readProject( filename, &inDevice, context ) )
1205 QString err = tr(
"Unable to open %1" ).arg( filename );
1206 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
1207 if ( !messages.isEmpty() )
1208 err += QStringLiteral(
"\n\n" ) + messages.last().message();
1212 returnValue = unzip( inDevice.fileName(), flags );
1218 returnValue = unzip( mFile.fileName(), flags );
1223 returnValue = readProjectFile( mFile.fileName(), flags );
1229 mFile.setFileName( filename );
1230 mCachedHomePath.clear();
1231 mProjectScope.reset();
1236 mTranslator.reset(
nullptr );
1243 bool QgsProject::readProjectFile(
const QString &filename, QgsProject::ReadFlags flags )
1245 QFile projectFile( filename );
1250 QString localeFileName = QStringLiteral(
"%1_%2" ).arg( QFileInfo( projectFile.fileName() ).baseName(), settings.
value( QStringLiteral(
"locale/userLocale" ), QString() ).toString() );
1252 if ( QFile( QStringLiteral(
"%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1254 mTranslator.reset(
new QTranslator() );
1255 mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1258 std::unique_ptr<QDomDocument> doc(
new QDomDocument( QStringLiteral(
"qgis" ) ) );
1260 if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1262 projectFile.close();
1264 setError( tr(
"Unable to open %1" ).arg( projectFile.fileName() ) );
1273 if ( !doc->setContent( &projectFile, &errorMsg, &line, &column ) )
1277 QMessageBox::critical( 0, tr(
"Read Project File" ),
1278 tr(
"%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
1281 QString errorString = tr(
"Project file read error in file %1: %2 at line %3 column %4" )
1282 .arg( projectFile.fileName(), errorMsg ).arg( line ).arg( column );
1286 projectFile.close();
1288 setError( tr(
"%1 for file %2" ).arg( errorString, projectFile.fileName() ) );
1293 projectFile.close();
1301 if ( thisVersion > fileVersion )
1304 "version of qgis (saved in " + fileVersion.
text() +
1306 "). Problems may occur." );
1313 projectFile.updateRevision( thisVersion );
1317 QString
fileName = mFile.fileName();
1318 std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
1320 mAuxiliaryStorage = std::move( aStorage );
1322 mCachedHomePath.clear();
1323 mProjectScope.reset();
1334 dump_( mProperties );
1339 _getTitle( *doc, oldTitle );
1341 readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1343 QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral(
"homePath" ) );
1344 if ( homePathNl.count() > 0 )
1346 QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1347 QString
homePath = homePathElement.attribute( QStringLiteral(
"path" ) );
1357 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), 255 ),
1358 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), 255 ) );
1361 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), 255 ),
1362 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), 255 ),
1363 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), 255 ) );
1372 if (
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ), 0 ) )
1375 QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral(
"projectCrs" ) );
1376 if ( !srsNode.isNull() )
1378 projectCrs.
readXml( srsNode );
1383 QString projCrsString =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSProj4String" ) );
1384 long currentCRS =
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSID" ), -1 );
1385 const QString authid =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCrs" ) );
1388 bool isUserAuthId = authid.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive );
1389 if ( !authid.isEmpty() && !isUserAuthId )
1393 if ( !projectCrs.
isValid() && currentCRS >= 0 )
1399 if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.
isValid() || projectCrs.
toProj() != projCrsString ) )
1413 QStringList datumErrors;
1414 if ( !mTransformContext.
readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
1422 QStringList variableNames =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ) );
1423 QStringList variableValues =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ) );
1425 mCustomVariables.clear();
1426 if ( variableNames.length() == variableValues.length() )
1428 for (
int i = 0; i < variableNames.length(); ++i )
1430 mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
1435 QgsMessageLog::logMessage( tr(
"Project Variables Invalid" ), tr(
"The project contains invalid variable settings." ) );
1438 QDomNodeList nl = doc->elementsByTagName( QStringLiteral(
"projectMetadata" ) );
1439 if ( !nl.isEmpty() )
1441 QDomElement metadataElement = nl.at( 0 ).toElement();
1449 if ( mMetadata.
title().isEmpty() && !oldTitle.isEmpty() )
1456 nl = doc->elementsByTagName( QStringLiteral(
"autotransaction" ) );
1459 QDomElement transactionElement = nl.at( 0 ).toElement();
1460 if ( transactionElement.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1461 mAutoTransaction =
true;
1464 nl = doc->elementsByTagName( QStringLiteral(
"evaluateDefaultValues" ) );
1467 QDomElement evaluateDefaultValuesElement = nl.at( 0 ).toElement();
1468 if ( evaluateDefaultValuesElement.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1469 mEvaluateDefaultValues =
true;
1472 nl = doc->elementsByTagName( QStringLiteral(
"trust" ) );
1475 QDomElement trustElement = nl.at( 0 ).toElement();
1476 if ( trustElement.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1477 mTrustLayerMetadata =
true;
1484 QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
1485 if ( !layerTreeElem.isNull() )
1494 mLayerTreeRegistryBridge->
setEnabled(
false );
1497 QList<QDomNode> brokenNodes;
1498 bool clean = _getMapLayers( *doc, brokenNodes, flags );
1503 QgsDebugMsg( QStringLiteral(
"Unable to get map layers from project file." ) );
1505 if ( !brokenNodes.isEmpty() )
1507 QgsDebugMsg(
"there are " + QString::number( brokenNodes.size() ) +
" broken layers" );
1517 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
1518 for ( QMap<QString, QgsMapLayer *>::iterator it =
layers.begin(); it !=
layers.end(); it++ )
1520 it.value()->resolveReferences(
this );
1523 mLayerTreeRegistryBridge->
setEnabled(
true );
1526 loadEmbeddedNodes( mRootGroup, flags );
1532 if ( !layerTreeElem.isNull() )
1538 QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-canvas" ) );
1539 if ( !layerTreeCanvasElem.isNull( ) )
1547 const QStringList requiredLayerIds =
readListEntry( QStringLiteral(
"RequiredLayers" ), QStringLiteral(
"Layers" ) );
1548 for (
const QString &layerId : requiredLayerIds )
1555 const QStringList disabledLayerIds =
readListEntry( QStringLiteral(
"Identify" ), QStringLiteral(
"/disabledLayers" ) );
1556 for (
const QString &layerId : disabledLayerIds )
1574 mMapThemeCollection->readXml( *doc );
1576 mLabelingEngineSettings->readSettingsFromProject(
this );
1579 mAnnotationManager->readXml( doc->documentElement(), context );
1581 mLayoutManager->readXml( doc->documentElement(), *doc );
1582 mBookmarkManager->
readXml( doc->documentElement(), *doc );
1585 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
1586 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); it++ )
1588 it.value()->setDependencies( it.value()->dependencies() );
1596 const QStringList scales =
readListEntry( QStringLiteral(
"Scales" ), QStringLiteral(
"/ScalesList" ) );
1597 QVector<double> res;
1598 for (
const QString &scale : scales )
1600 const QStringList parts = scale.split(
':' );
1601 if ( parts.size() != 2 )
1605 const double denominator = QLocale().toDouble( parts[1], &ok );
1612 QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectViewSettings" ) );
1613 if ( !viewSettingsElement.isNull() )
1614 mViewSettings->
readXml( viewSettingsElement, context );
1617 QDomElement timeSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectTimeSettings" ) );
1618 if ( !timeSettingsElement.isNull() )
1619 mTimeSettings->
readXml( timeSettingsElement, context );
1621 QDomElement displaySettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectDisplaySettings" ) );
1622 if ( !displaySettingsElement.isNull() )
1623 mDisplaySettings->
readXml( displaySettingsElement, context );
1641 QgsDebugMsgLevel( QString(
"Project save user: %1" ).arg( mSaveUser ), 2 );
1642 QgsDebugMsgLevel( QString(
"Project save user: %1" ).arg( mSaveUserFull ), 2 );
1651 QString newFileName( QStringLiteral(
"%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
1668 bool QgsProject::loadEmbeddedNodes(
QgsLayerTreeGroup *group, QgsProject::ReadFlags flags )
1671 const auto constChildren = group->
children();
1677 if ( childGroup->
customProperty( QStringLiteral(
"embedded" ) ).toInt() )
1680 QString projectPath =
readPath( childGroup->
customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
1681 childGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectPath );
1685 QList<QgsLayerTreeNode *> clonedChildren;
1686 const auto constChildren = newGroup->
children();
1688 clonedChildren << newGroupChild->clone();
1696 loadEmbeddedNodes( childGroup, flags );
1701 if ( child->customProperty( QStringLiteral(
"embedded" ) ).toInt() )
1703 QList<QDomNode> brokenNodes;
1706 valid = valid &&
false;
1718 return mCustomVariables;
1723 if ( variables == mCustomVariables )
1727 QStringList variableNames;
1728 QStringList variableValues;
1730 QVariantMap::const_iterator it = variables.constBegin();
1731 for ( ; it != variables.constEnd(); ++it )
1733 variableNames << it.key();
1734 variableValues << it.value().toString();
1737 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ), variableNames );
1738 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ), variableValues );
1740 mCustomVariables = variables;
1741 mProjectScope.reset();
1748 *mLabelingEngineSettings = settings;
1754 return *mLabelingEngineSettings;
1759 mProjectScope.reset();
1760 return mLayerStore.get();
1765 return mLayerStore.get();
1770 QList<QgsVectorLayer *>
layers;
1771 QStringList layerIds =
readListEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), QStringList() );
1772 const auto constLayerIds = layerIds;
1773 for (
const QString &layerId : constLayerIds )
1784 const auto constLayers =
layers;
1786 list << layer->id();
1787 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), list );
1804 if ( mProjectScope )
1806 std::unique_ptr< QgsExpressionContextScope > projectScope = qgis::make_unique< QgsExpressionContextScope >( *mProjectScope );
1810 return projectScope.release();
1813 mProjectScope = qgis::make_unique< QgsExpressionContextScope >( QObject::tr(
"Project" ) );
1817 QVariantMap::const_iterator it = vars.constBegin();
1819 for ( ; it != vars.constEnd(); ++it )
1821 mProjectScope->setVariable( it.key(), it.value(),
true );
1825 if ( projectPath.isEmpty() )
1826 projectPath = mOriginalPath;
1827 QString projectFolder = QFileInfo( projectPath ).path();
1828 QString projectFilename = QFileInfo( projectPath ).fileName();
1829 QString projectBasename =
baseName();
1858 QVariantMap keywords;
1860 for (
auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
1862 keywords.insert( it.key(), it.value() );
1867 QVariantList layersIds;
1869 const QMap<QString, QgsMapLayer *> layersInProject = mLayerStore->mapLayers();
1870 layersIds.reserve( layersInProject.count() );
1871 layers.reserve( layersInProject.count() );
1872 for (
auto it = layersInProject.constBegin(); it != layersInProject.constEnd(); ++it )
1874 layersIds << it.value()->id();
1880 mProjectScope->addFunction( QStringLiteral(
"project_color" ),
new GetNamedProjectColor(
this ) );
1885 void QgsProject::onMapLayersAdded(
const QList<QgsMapLayer *> &layers )
1887 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
1889 bool tgChanged =
false;
1891 const auto constLayers =
layers;
1894 if ( layer->isValid() )
1896 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
1903 const QString connString = QgsTransaction::connectionString( vlayer->
source() );
1911 mTransactionGroups.insert( qMakePair( key, connString ), tg );
1926 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); it++ )
1928 QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
1929 if ( deps.contains( layer->id() ) )
1932 it.value()->setDependencies( deps );
1942 void QgsProject::onMapLayersRemoved(
const QList<QgsMapLayer *> &layers )
1948 void QgsProject::cleanTransactionGroups(
bool force )
1950 bool changed =
false;
1951 for ( QMap< QPair< QString, QString>,
QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
1953 if ( tg.value()->
isEmpty() || force )
1956 tg = mTransactionGroups.erase( tg );
1974 QList<QDomNode> brokenNodes;
1975 if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
1979 QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
1980 const auto constVectorLayers = vectorLayers;
1984 layer->resolveReferences(
this );
1994 mFile.setFileName( filename );
1995 mCachedHomePath.clear();
2001 mProjectScope.reset();
2007 QString storageFilePath { storage->filePath( mFile.fileName() ) };
2008 if ( storageFilePath.isEmpty() )
2010 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
true );
2014 QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2015 QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2017 if ( !zip( tmpZipFilename ) )
2020 QFile tmpZipFile( tmpZipFilename );
2021 if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2023 setError( tr(
"Unable to read file %1" ).arg( tmpZipFilename ) );
2028 if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2030 QString err = tr(
"Unable to save project to storage %1" ).arg( mFile.fileName() );
2031 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
2032 if ( !messages.isEmpty() )
2033 err += QStringLiteral(
"\n\n" ) + messages.last().message();
2039 QFile::remove( tmpZipFilename );
2046 return zip( mFile.fileName() );
2052 const bool asOk = saveAuxiliaryStorage();
2053 const bool writeOk = writeProjectFile( mFile.fileName() );
2056 if ( !asOk && writeOk )
2058 const QString err = mAuxiliaryStorage->errorString();
2059 setError( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
2062 return asOk && writeOk;
2066 bool QgsProject::writeProjectFile(
const QString &filename )
2068 QFile projectFile( filename );
2074 QFileInfo myFileInfo( projectFile );
2075 if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2077 setError( tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
2078 .arg( projectFile.fileName() ) );
2086 QDomImplementation DomImplementation;
2087 DomImplementation.setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2089 QDomDocumentType documentType =
2090 DomImplementation.createDocumentType( QStringLiteral(
"qgis" ), QStringLiteral(
"http://mrcc.com/qgis.dtd" ),
2091 QStringLiteral(
"SYSTEM" ) );
2092 std::unique_ptr<QDomDocument> doc(
new QDomDocument( documentType ) );
2094 QDomElement qgisNode = doc->createElement( QStringLiteral(
"qgis" ) );
2095 qgisNode.setAttribute( QStringLiteral(
"projectname" ),
title() );
2096 qgisNode.setAttribute( QStringLiteral(
"version" ), QStringLiteral(
"%1" ).arg(
Qgis::version() ) );
2099 if ( !settings.
value( QStringLiteral(
"projects/anonymize_saved_projects" ),
false,
QgsSettings::Core ).toBool() )
2103 qgisNode.setAttribute( QStringLiteral(
"saveUser" ), newSaveUser );
2104 qgisNode.setAttribute( QStringLiteral(
"saveUserFull" ), newSaveUserFull );
2105 mSaveUser = newSaveUser;
2106 mSaveUserFull = newSaveUserFull;
2107 mSaveDateTime = QDateTime::currentDateTime();
2108 qgisNode.setAttribute( QStringLiteral(
"saveDateTime" ), mSaveDateTime.toString( Qt::ISODate ) );
2113 mSaveUserFull.clear();
2114 mSaveDateTime = QDateTime();
2116 doc->appendChild( qgisNode );
2118 QDomElement homePathNode = doc->createElement( QStringLiteral(
"homePath" ) );
2119 homePathNode.setAttribute( QStringLiteral(
"path" ), mHomePath );
2120 qgisNode.appendChild( homePathNode );
2123 QDomElement titleNode = doc->createElement( QStringLiteral(
"title" ) );
2124 qgisNode.appendChild( titleNode );
2126 QDomElement transactionNode = doc->createElement( QStringLiteral(
"autotransaction" ) );
2127 transactionNode.setAttribute( QStringLiteral(
"active" ), mAutoTransaction ? 1 : 0 );
2128 qgisNode.appendChild( transactionNode );
2130 QDomElement evaluateDefaultValuesNode = doc->createElement( QStringLiteral(
"evaluateDefaultValues" ) );
2131 evaluateDefaultValuesNode.setAttribute( QStringLiteral(
"active" ), mEvaluateDefaultValues ? 1 : 0 );
2132 qgisNode.appendChild( evaluateDefaultValuesNode );
2134 QDomElement trustNode = doc->createElement( QStringLiteral(
"trust" ) );
2135 trustNode.setAttribute( QStringLiteral(
"active" ), mTrustLayerMetadata ? 1 : 0 );
2136 qgisNode.appendChild( trustNode );
2138 QDomText titleText = doc->createTextNode(
title() );
2139 titleNode.appendChild( titleText );
2142 QDomElement srsNode = doc->createElement( QStringLiteral(
"projectCrs" ) );
2144 qgisNode.appendChild( srsNode );
2151 clonedRoot->
writeXml( qgisNode, context );
2155 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsMode" ),
static_cast<int>( mAvoidIntersectionsMode ) );
2165 QDomElement projectLayersNode = doc->createElement( QStringLiteral(
"projectlayers" ) );
2167 QMap<QString, QgsMapLayer *>::ConstIterator li =
layers.constBegin();
2168 while ( li !=
layers.end() )
2174 QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->
id() );
2175 if ( emIt == mEmbeddedLayers.constEnd() )
2177 QDomElement maplayerElem;
2183 maplayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2188 QDomDocument document;
2191 maplayerElem = document.firstChildElement();
2195 QgsDebugMsg( QStringLiteral(
"Could not restore layer properties for layer %1" ).arg( ml->
id() ) );
2201 projectLayersNode.appendChild( maplayerElem );
2207 if ( emIt.value().second )
2209 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2210 mapLayerElem.setAttribute( QStringLiteral(
"embedded" ), 1 );
2211 mapLayerElem.setAttribute( QStringLiteral(
"project" ),
writePath( emIt.value().first ) );
2212 mapLayerElem.setAttribute( QStringLiteral(
"id" ), ml->
id() );
2213 projectLayersNode.appendChild( mapLayerElem );
2220 qgisNode.appendChild( projectLayersNode );
2222 QDomElement layerOrderNode = doc->createElement( QStringLiteral(
"layerorder" ) );
2224 for (
QgsMapLayer *layer : constCustomLayerOrder )
2226 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"layer" ) );
2227 mapLayerElem.setAttribute( QStringLiteral(
"id" ), layer->id() );
2228 layerOrderNode.appendChild( mapLayerElem );
2230 qgisNode.appendChild( layerOrderNode );
2232 mLabelingEngineSettings->writeSettingsToProject(
this );
2234 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorRedPart" ), mBackgroundColor.red() );
2235 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), mBackgroundColor.green() );
2236 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), mBackgroundColor.blue() );
2238 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorRedPart" ), mSelectionColor.red() );
2239 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), mSelectionColor.green() );
2240 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), mSelectionColor.blue() );
2241 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), mSelectionColor.alpha() );
2245 dump_( mProperties );
2248 QgsDebugMsgLevel( QStringLiteral(
"there are %1 property scopes" ).arg(
static_cast<int>( mProperties.
count() ) ), 2 );
2253 mProperties.
writeXml( QStringLiteral(
"properties" ), qgisNode, *doc );
2256 QDomElement ddElem = doc->createElement( QStringLiteral(
"dataDefinedServerProperties" ) );
2257 mDataDefinedServerProperties.
writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
2258 qgisNode.appendChild( ddElem );
2260 mMapThemeCollection->writeXml( *doc );
2262 mTransformContext.
writeXml( qgisNode, context );
2264 QDomElement metadataElem = doc->createElement( QStringLiteral(
"projectMetadata" ) );
2266 qgisNode.appendChild( metadataElem );
2268 QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
2269 qgisNode.appendChild( annotationsElem );
2271 QDomElement layoutElem = mLayoutManager->writeXml( *doc );
2272 qgisNode.appendChild( layoutElem );
2274 QDomElement bookmarkElem = mBookmarkManager->
writeXml( *doc );
2275 qgisNode.appendChild( bookmarkElem );
2277 QDomElement viewSettingsElem = mViewSettings->
writeXml( *doc, context );
2278 qgisNode.appendChild( viewSettingsElem );
2280 QDomElement timeSettingsElement = mTimeSettings->
writeXml( *doc, context );
2281 qgisNode.appendChild( timeSettingsElement );
2283 QDomElement displaySettingsElem = mDisplaySettings->
writeXml( *doc, context );
2284 qgisNode.appendChild( displaySettingsElem );
2292 QFile backupFile( QStringLiteral(
"%1~" ).arg( filename ) );
2294 ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
2295 ok &= projectFile.open( QIODevice::ReadOnly );
2298 while ( ok && !projectFile.atEnd() )
2300 ba = projectFile.read( 10240 );
2301 ok &= backupFile.write( ba ) == ba.size();
2304 projectFile.close();
2309 setError( tr(
"Unable to create backup file %1" ).arg( backupFile.fileName() ) );
2314 struct utimbuf tb = {
static_cast<time_t
>( fi.lastRead().toSecsSinceEpoch() ),
static_cast<time_t
>( fi.lastModified().toSecsSinceEpoch() ) };
2315 utime( backupFile.fileName().toUtf8().constData(), &tb );
2318 if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
2320 projectFile.close();
2323 setError( tr(
"Unable to save to file %1" ).arg( projectFile.fileName() ) );
2327 QTemporaryFile tempFile;
2328 bool ok = tempFile.open();
2331 QTextStream projectFileStream( &tempFile );
2332 doc->save( projectFileStream, 2 );
2333 ok &= projectFileStream.pos() > -1;
2335 ok &= tempFile.seek( 0 );
2338 while ( ok && !tempFile.atEnd() )
2340 ba = tempFile.read( 10240 );
2341 ok &= projectFile.write( ba ) == ba.size();
2344 ok &= projectFile.error() == QFile::NoError;
2346 projectFile.close();
2353 setError( tr(
"Unable to save to file %1. Your project "
2354 "may be corrupted on disk. Try clearing some space on the volume and "
2355 "check file permissions before pressing save again." )
2356 .arg( projectFile.fileName() ) );
2368 bool propertiesModified;
2369 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2371 if ( propertiesModified )
2379 bool propertiesModified;
2380 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2382 if ( propertiesModified )
2390 bool propertiesModified;
2391 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2393 if ( propertiesModified )
2401 bool propertiesModified;
2402 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2404 if ( propertiesModified )
2412 bool propertiesModified;
2413 bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2415 if ( propertiesModified )
2423 const QStringList &def,
2432 value =
property->value();
2434 bool valid = QVariant::StringList == value.type();
2440 return value.toStringList();
2459 value =
property->value();
2461 bool valid = value.canConvert( QVariant::String );
2466 return value.toString();
2481 value =
property->value();
2484 bool valid = value.canConvert( QVariant::Int );
2493 return value.toInt();
2506 QVariant value =
property->value();
2508 bool valid = value.canConvert( QVariant::Double );
2513 return value.toDouble();
2526 QVariant value =
property->value();
2528 bool valid = value.canConvert( QVariant::Bool );
2533 return value.toBool();
2541 if (
findKey_( scope, key, mProperties ) )
2547 return !
findKey_( scope, key, mProperties );
2555 QStringList entries;
2557 if ( foundProperty )
2572 QStringList entries;
2574 if ( foundProperty )
2587 dump_( mProperties );
2592 bool absolutePaths =
readBoolEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
2594 if ( ! absolutePaths )
2601 filePath = storage->filePath( mFile.fileName() );
2621 void QgsProject::setError(
const QString &errorMessage )
2623 mErrorMessage = errorMessage;
2628 return mErrorMessage;
2631 void QgsProject::clearError()
2633 setError( QString() );
2638 delete mBadLayerHandler;
2639 mBadLayerHandler = handler;
2644 QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find(
id );
2645 if ( it == mEmbeddedLayers.constEnd() )
2649 return it.value().first;
2653 bool saveFlag, QgsProject::ReadFlags flags )
2657 static QString sPrevProjectFilePath;
2658 static QDateTime sPrevProjectFileTimestamp;
2659 static QDomDocument sProjectDocument;
2661 QString qgsProjectFile = projectFilePath;
2663 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
2665 archive.
unzip( projectFilePath );
2669 QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
2671 if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
2673 sPrevProjectFilePath.clear();
2675 QFile projectFile( qgsProjectFile );
2676 if ( !projectFile.open( QIODevice::ReadOnly ) )
2681 if ( !sProjectDocument.setContent( &projectFile ) )
2686 sPrevProjectFilePath = projectFilePath;
2687 sPrevProjectFileTimestamp = projectFileTimestamp;
2691 bool useAbsolutePaths =
true;
2693 QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
2694 if ( !propertiesElem.isNull() )
2696 QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral(
"Paths" ) ).firstChildElement( QStringLiteral(
"Absolute" ) );
2697 if ( !absElem.isNull() )
2699 useAbsolutePaths = absElem.text().compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
2704 if ( !useAbsolutePaths )
2709 QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) );
2710 if ( projectLayersElem.isNull() )
2715 QDomNodeList mapLayerNodes = projectLayersElem.elementsByTagName( QStringLiteral(
"maplayer" ) );
2716 for (
int i = 0; i < mapLayerNodes.size(); ++i )
2719 QDomElement mapLayerElem = mapLayerNodes.at( i ).toElement();
2720 QString
id = mapLayerElem.firstChildElement( QStringLiteral(
"id" ) ).text();
2721 if (
id == layerId )
2724 if ( mapLayerElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
2729 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
2731 if ( addLayer( mapLayerElem, brokenNodes, embeddedContext, flags ) )
2737 mEmbeddedLayers.remove( layerId );
2749 QString qgsProjectFile = projectFilePath;
2751 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
2753 archive.
unzip( projectFilePath );
2758 QFile projectFile( qgsProjectFile );
2759 if ( !projectFile.open( QIODevice::ReadOnly ) )
2764 QDomDocument projectDocument;
2765 if ( !projectDocument.setContent( &projectFile ) )
2777 QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
2778 if ( !layerTreeElem.isNull() )
2788 if ( !group || group->
customProperty( QStringLiteral(
"embedded" ) ).toBool() )
2801 newGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectFilePath );
2804 mLayerTreeRegistryBridge->
setEnabled(
false );
2805 initializeEmbeddedSubtree( projectFilePath, newGroup, flags );
2806 mLayerTreeRegistryBridge->
setEnabled(
true );
2809 const auto constFindLayerIds = newGroup->
findLayerIds();
2810 for (
const QString &layerId : constFindLayerIds )
2823 void QgsProject::initializeEmbeddedSubtree(
const QString &projectFilePath,
QgsLayerTreeGroup *group, QgsProject::ReadFlags flags )
2825 const auto constChildren = group->
children();
2829 child->setCustomProperty( QStringLiteral(
"embedded" ), 1 );
2838 QList<QDomNode> brokenNodes;
2846 return mEvaluateDefaultValues;
2855 QMap<QString, QgsMapLayer *>::const_iterator layerIt =
layers.constBegin();
2856 for ( ; layerIt !=
layers.constEnd(); ++layerIt )
2858 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() );
2870 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
2876 return readNumEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), 0 );
2881 QString distanceUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), QString() );
2882 if ( !distanceUnitString.isEmpty() )
2899 QString areaUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), QString() );
2900 if ( !areaUnitString.isEmpty() )
2917 if ( !mCachedHomePath.isEmpty() )
2918 return mCachedHomePath;
2922 if ( !mHomePath.isEmpty() )
2924 QFileInfo homeInfo( mHomePath );
2925 if ( !homeInfo.isRelative() )
2927 mCachedHomePath = mHomePath;
2933 mCachedHomePath = pfi.path();
2935 return mCachedHomePath;
2938 if ( !pfi.exists() )
2940 mCachedHomePath = mHomePath;
2944 if ( !mHomePath.isEmpty() )
2947 mCachedHomePath = QDir::cleanPath( pfi.path() +
'/' + mHomePath );
2951 mCachedHomePath = pfi.canonicalPath();
2953 return mCachedHomePath;
2963 return mRelationManager;
2968 return mLayoutManager.get();
2973 return mLayoutManager.get();
2978 return mBookmarkManager;
2983 return mBookmarkManager;
2988 return mViewSettings;
2993 return mViewSettings;
2998 return mTimeSettings;
3003 return mTimeSettings;
3008 return mDisplaySettings;
3013 return mDisplaySettings;
3023 return mMapThemeCollection.get();
3028 return mAnnotationManager.get();
3033 return mAnnotationManager.get();
3038 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
3039 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3044 if (
layers.contains( it.value() ) )
3059 for (
const QString &layerId : layerIds )
3075 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3087 return mAutoTransaction;
3097 onMapLayersAdded(
mapLayers().values() );
3099 cleanTransactionGroups(
true );
3105 return mTransactionGroups;
3116 return mLayerStore->count();
3121 return mLayerStore->validCount();
3126 return mLayerStore->mapLayer( layerId );
3131 return mLayerStore->mapLayersByName( layerName );
3136 QList<QgsMapLayer *>
layers;
3137 const auto constMapLayers { mLayerStore->mapLayers() };
3138 for (
const auto &l : constMapLayers )
3140 if ( ! l->shortName().isEmpty() )
3142 if ( l->shortName() == shortName )
3145 else if ( l->name() == shortName )
3153 bool QgsProject::unzip(
const QString &filename, QgsProject::ReadFlags flags )
3159 if ( !archive->unzip( filename ) )
3161 setError( tr(
"Unable to unzip file '%1'" ).arg( filename ) );
3166 if ( archive->projectFile().isEmpty() )
3168 setError( tr(
"Zip archive does not provide a project file" ) );
3173 if ( !archive->auxiliaryStorageFile().isEmpty() )
3177 mAuxiliaryStorage.reset(
new QgsAuxiliaryStorage( archive->auxiliaryStorageFile(),
false ) );
3185 if ( ! readProjectFile( archive->projectFile(), flags ) )
3187 setError( tr(
"Cannot read unzipped qgs project file" ) );
3192 mArchive = std::move( archive );
3193 mArchive->clearProjectFile();
3198 bool QgsProject::zip(
const QString &filename )
3204 const QString
baseName = QFileInfo( filename ).baseName();
3205 const QString qgsFileName = QStringLiteral(
"%1.qgs" ).arg(
baseName );
3206 QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
3208 bool writeOk =
false;
3209 if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3211 writeOk = writeProjectFile( qgsFile.fileName() );
3218 setError( tr(
"Unable to write temporary qgs file" ) );
3223 const QFileInfo info( qgsFile );
3226 if ( ! saveAuxiliaryStorage( asFileName ) )
3228 const QString err = mAuxiliaryStorage->errorString();
3229 setError( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
3234 archive->addFile( qgsFile.fileName() );
3235 archive->addFile( asFileName );
3238 if ( !archive->zip( filename ) )
3240 setError( tr(
"Unable to perform zip" ) );
3253 const QList<QgsMapLayer *> &layers,
3255 bool takeOwnership )
3257 const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers(
layers, takeOwnership ) };
3258 if ( !myResultList.isEmpty() )
3261 for (
auto &l : myResultList )
3271 if ( mAuxiliaryStorage )
3286 mProjectScope.reset();
3288 return myResultList;
3294 bool takeOwnership )
3296 QList<QgsMapLayer *> addedLayers;
3297 addedLayers =
addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
3298 return addedLayers.isEmpty() ? nullptr : addedLayers[0];
3303 mProjectScope.reset();
3304 mLayerStore->removeMapLayers( layerIds );
3309 mProjectScope.reset();
3310 mLayerStore->removeMapLayers(
layers );
3315 mProjectScope.reset();
3316 mLayerStore->removeMapLayer( layerId );
3321 mProjectScope.reset();
3322 mLayerStore->removeMapLayer( layer );
3327 mProjectScope.reset();
3328 return mLayerStore->takeMapLayer( layer );
3333 mProjectScope.reset();
3334 mLayerStore->removeAllMapLayers();
3339 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
3340 QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin();
3341 for ( ; it !=
layers.constEnd(); ++it )
3343 it.value()->reload();
3349 return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
3354 return mTransactionGroups.value( qMakePair( providerKey, connString ) );
3364 if ( settings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), QStringLiteral(
"NoAction" ),
QgsSettings::App ).toString() == QStringLiteral(
"UseProjectCrs" )
3365 || settings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), 0,
QgsSettings::App ).toString() == 2 )
3373 QString layerDefaultCrs = settings.
value( QStringLiteral(
"/Projections/layerDefaultCrs" ),
geoEpsgCrsAuthId() ).toString();
3382 mTrustLayerMetadata = trust;
3385 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3387 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
3395 bool QgsProject::saveAuxiliaryStorage(
const QString &filename )
3399 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3404 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
3412 if ( !mAuxiliaryStorage->exists( *
this ) && filename.isEmpty() && empty )
3416 else if ( !filename.isEmpty() )
3418 return mAuxiliaryStorage->saveAs( filename );
3422 return mAuxiliaryStorage->saveAs( *
this );
3431 QgsProject::DataDefinedServerProperty::WMSOnlineResource,
3435 return sPropertyDefinitions;
3440 return mAuxiliaryStorage.get();
3445 return mAuxiliaryStorage.get();
3459 mProjectScope.reset();
3471 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3483 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
3484 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3489 if (
layers.contains( it.value() ) )
3499 QStringList customColors;
3500 QStringList customColorLabels;
3502 QgsNamedColorList::const_iterator colorIt = colors.constBegin();
3503 for ( ; colorIt != colors.constEnd(); ++colorIt )
3506 QString label = ( *colorIt ).second;
3507 customColors.append( color );
3508 customColorLabels.append( label );
3510 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ), customColors );
3511 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ), customColorLabels );
3512 mProjectScope.reset();
3518 if ( mBackgroundColor == color )
3521 mBackgroundColor = color;
3527 return mBackgroundColor;
3532 if ( mSelectionColor == color )
3535 mSelectionColor = color;
3541 return mSelectionColor;
3575 QString
QgsProject::translate(
const QString &context,
const QString &sourceText,
const char *disambiguation,
int n )
const
3582 QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
3584 if ( result.isEmpty() )
3596 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3601 if ( !( ( *it )->accept( visitor ) ) )
3610 if ( !mLayoutManager->accept( visitor ) )
3613 if ( !mAnnotationManager->accept( visitor ) )
3620 GetNamedProjectColor::GetNamedProjectColor(
const QgsProject *project )
3627 QStringList colorStrings = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ) );
3628 QStringList colorLabels = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ) );
3632 for ( QStringList::iterator it = colorStrings.begin();
3633 it != colorStrings.end(); ++it )
3637 if ( colorLabels.length() > colorIndex )
3639 label = colorLabels.at( colorIndex );
3642 mColors.insert( label.toLower(), color );
3647 GetNamedProjectColor::GetNamedProjectColor(
const QHash<QString, QColor> &colors )
3655 QString colorName = values.at( 0 ).toString().toLower();
3656 if ( mColors.contains( colorName ) )
3658 return QStringLiteral(
"%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
3666 return new GetNamedProjectColor( mColors );