79#include <QApplication>
84#include <QTemporaryFile>
87#include <QStandardPaths>
89#include <QRegularExpression>
111 QStringList keyTokens = QStringList( scope );
112#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
113 keyTokens += key.split(
'/', QString::SkipEmptyParts );
115 keyTokens += key.split(
'/', Qt::SkipEmptyParts );
119 keyTokens.push_front( QStringLiteral(
"properties" ) );
122 for (
int i = 0; i < keyTokens.size(); ++i )
124 const QString keyToken = keyTokens.at( i );
128 const thread_local QRegularExpression sInvalidRegexp = QRegularExpression( QStringLiteral(
"([^:A-Z_a-z\\x{C0}-\\x{D6}\\x{D8}-\\x{F6}\\x{F8}-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\-\\.0-9\\x{B7}\\x{0300}-\\x{036F}\\x{203F}-\\x{2040}]|^[^:A-Z_a-z\\x{C0}-\\x{D6}\\x{D8}-\\x{F6}\\x{F8}-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}])" ) );
129 if ( keyToken.contains( sInvalidRegexp ) )
131 const QString errorString = QObject::tr(
"Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
159 while ( !keySequence.isEmpty() )
163 if ( keySequence.first() == currentProperty->
name() )
166 keySequence.pop_front();
168 if ( 1 == keySequence.count() )
171 return currentProperty->
find( keySequence.front() );
173 else if ( keySequence.isEmpty() )
178 return currentProperty;
180 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
182 if ( nextProperty->
isKey() )
186 else if ( nextProperty->
isValue() && 1 == keySequence.count() )
192 return currentProperty;
230 const QVariant &value,
231 bool &propertiesModified )
240 propertiesModified =
false;
241 while ( ! keySequence.isEmpty() )
245 if ( keySequence.first() == currentProperty->
name() )
248 keySequence.pop_front();
252 if ( 1 == keySequence.count() )
255 if ( !property || property->value() != value )
257 currentProperty->
setValue( keySequence.front(), value );
258 propertiesModified =
true;
261 return currentProperty;
265 else if ( keySequence.isEmpty() )
267 if ( currentProperty->
value() != value )
270 propertiesModified =
true;
273 return currentProperty;
275 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
279 if ( currentProperty )
290 if ( ( newPropertyKey = currentProperty->
addKey( keySequence.first() ) ) )
292 currentProperty = newPropertyKey;
324 while ( ! keySequence.isEmpty() )
328 if ( keySequence.first() == currentProperty->
name() )
331 keySequence.pop_front();
335 if ( 1 == keySequence.count() )
337 currentProperty->
removeKey( keySequence.front() );
342 else if ( keySequence.isEmpty() )
344 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
346 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
348 previousQgsPropertyKey = currentProperty;
351 if ( currentProperty )
375 , mCapabilities( capabilities )
378 , mSnappingConfig( this )
396 mProperties.
setName( QStringLiteral(
"properties" ) );
399 mMainAnnotationLayer->setParent(
this );
413 this, [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
415 this, [ = ](
const QList<QgsMapLayer *> &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
417 this, [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
419 this, [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
421 [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
423 [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
425 [ = ]() { mProjectScope.reset(); emit removeAll(); } );
427 [ = ](
const QList< QgsMapLayer * > &
layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
429 [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
437 [ = ](
const QList<QgsMapLayer *> &
layers )
439 for ( const auto &layer : layers )
441 disconnect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
446 [ = ](
const QList<QgsMapLayer *> &layers )
448 for ( const auto &layer : layers )
450 connect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
459 mStyleSettings->combinedStyleModel()->addDefaultStyle();
465 mIsBeingDeleted =
true;
468 releaseHandlesToProjectArchive();
469 delete mBadLayerHandler;
470 delete mRelationManager;
471 delete mLayerTreeRegistryBridge;
473 if (
this == sProject )
504 mProjectScope.reset();
515 return mMetadata.
title();
524 if ( oldEvaluateDefaultValues != newEvaluateDefaultValues )
527 for (
auto layerIt =
layers.constBegin(); layerIt !=
layers.constEnd(); ++layerIt )
529 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
530 if ( vl->dataProvider() )
537 if ( oldTrustLayerMetadata != newTrustLayerMetadata )
540 for (
auto layerIt =
layers.constBegin(); layerIt !=
layers.constEnd(); ++layerIt )
542 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
544 vl->setReadExtentFromXml( newTrustLayerMetadata );
549 if ( mFlags !=
flags )
560 Qgis::ProjectFlags newFlags = mFlags;
564 newFlags &= ~(
static_cast< int >( flag ) );
579 return mSaveUserFull;
586 return mSaveDateTime;
607 if ( dirty && mDirtyBlockCount > 0 )
613 if ( mDirty == dirty )
624 if ( path == mHomePath )
628 mCachedHomePath.clear();
629 mProjectScope.reset();
640 const QList<QgsAttributeEditorElement *> elements = parent->
children();
648 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:formcontainers" ).arg( layerId ), container->
name() );
650 if ( !container->
children().empty() )
665 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1" ).arg( layer->layerId() ), layer->name() );
674 for (
const QgsField &field : fields )
677 if ( field.alias().isEmpty() )
678 fieldName = field.name();
680 fieldName = field.alias();
682 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fieldaliases" ).arg( vlayer->
id() ), fieldName );
684 if ( field.editorWidgetSetup().type() == QLatin1String(
"ValueRelation" ) )
686 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fields:%2:valuerelationvalue" ).arg( vlayer->
id(), field.name() ), field.editorWidgetSetup().config().value( QStringLiteral(
"Value" ) ).toString() );
697 const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->
findGroups();
700 translationContext->
registerTranslation( QStringLiteral(
"project:layergroups" ), groupLayer->name() );
704 const QList<QgsRelation> &relations = mRelationManager->
relations().values();
707 translationContext->
registerTranslation( QStringLiteral(
"project:relations" ), relation.name() );
715 mDataDefinedServerProperties = properties;
722 return mDataDefinedServerProperties;
729 switch ( mTransactionMode )
750 switch ( mTransactionMode )
757 commitErrors.append( tr(
"Trying to commit changes without a layer specified. This only works if the transaction mode is buffered" ) );
766 return mEditBufferGroup.
commitChanges( commitErrors, stopEditing );
776 switch ( mTransactionMode )
783 rollbackErrors.append( tr(
"Trying to roll back changes without a layer specified. This only works if the transaction mode is buffered" ) );
786 bool success = vectorLayer->
rollBack( stopEditing );
792 return mEditBufferGroup.
rollBack( rollbackErrors, stopEditing );
802 if ( name == mFile.fileName() )
805 const QString oldHomePath =
homePath();
807 mFile.setFileName( name );
808 mCachedHomePath.clear();
809 mProjectScope.reset();
813 const QString newHomePath =
homePath();
814 if ( newHomePath != oldHomePath )
825 return mFile.fileName();
832 mOriginalPath = path;
839 return mOriginalPath;
846 return QFileInfo( mFile );
864 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
869 return QFileInfo( mFile.fileName() ).lastModified();
880 if ( mFile.fileName().isEmpty() )
883 return QFileInfo( mFile.fileName() ).absolutePath();
894 if ( mFile.fileName().isEmpty() )
897 return QFileInfo( mFile.fileName() ).absoluteFilePath();
908 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
913 return QFileInfo( mFile.fileName() ).completeBaseName();
921 const bool absolutePaths =
readBoolEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
932 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
true );
935 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
955 writeEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ),
crs.
isValid() ? 1 : 0 );
956 mProjectScope.reset();
967 if ( adjustEllipsoid )
976 if ( !
crs().isValid() )
979 return readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ),
geoNone() );
986 if (
ellipsoid ==
readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ) ) )
989 mProjectScope.reset();
999 return mTransformContext;
1006 if ( context == mTransformContext )
1009 mTransformContext = context;
1010 mProjectScope.reset();
1013 for (
auto &layer : mLayerStore.get()->mapLayers() )
1015 layer->setTransformContext( context );
1024 ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
1028 mProjectScope.reset();
1029 mFile.setFileName( QString() );
1032 mSaveUserFull.clear();
1033 mSaveDateTime = QDateTime();
1036 mCachedHomePath.clear();
1038 mFlags = Qgis::ProjectFlags();
1040 mCustomVariables.clear();
1044 if ( !mSettings.
value( QStringLiteral(
"projects/anonymize_new_projects" ),
false,
QgsSettings::Core ).toBool() )
1063 mEmbeddedLayers.clear();
1064 mRelationManager->
clear();
1065 mAnnotationManager->clear();
1066 mLayoutManager->clear();
1067 m3DViewsManager->clear();
1068 mBookmarkManager->
clear();
1069 mSensorManager->
clear();
1070 mViewSettings->
reset();
1071 mTimeSettings->
reset();
1072 mElevationProperties->
reset();
1073 mDisplaySettings->
reset();
1074 mGpsSettings->
reset();
1075 mSnappingConfig.
reset();
1083 mLabelingEngineSettings->clear();
1087 releaseHandlesToProjectArchive();
1093 mStyleSettings->
reset();
1097 if ( !mIsBeingDeleted )
1105 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/Automatic" ),
true );
1106 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/DecimalPlaces" ), 2 );
1108 const bool defaultRelativePaths = mSettings.
value( QStringLiteral(
"/qgis/defaultProjectPathsRelative" ),
true ).toBool();
1111 int red = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_red" ), 255 ).toInt();
1112 int green = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_green" ), 255 ).toInt();
1113 int blue = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_blue" ), 255 ).toInt();
1116 red = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_red" ), 255 ).toInt();
1117 green = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_green" ), 255 ).toInt();
1118 blue = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_blue" ), 0 ).toInt();
1119 const int alpha = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_alpha" ), 255 ).toInt();
1125 mRootGroup->
clear();
1126 if ( mMainAnnotationLayer )
1127 mMainAnnotationLayer->
reset();
1129 snapSingleBlocker.release();
1131 if ( !mBlockSnappingUpdates )
1143 topQgsPropertyKey.
dump();
1176 const QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
1178 if ( propertiesElem.isNull() )
1183 const QDomNodeList scopes = propertiesElem.childNodes();
1185 if ( propertiesElem.firstChild().isNull() )
1187 QgsDebugError( QStringLiteral(
"empty ``properties'' XML tag ... bailing" ) );
1191 if ( ! project_properties.
readXml( propertiesElem ) )
1193 QgsDebugError( QStringLiteral(
"Project_properties.readXml() failed" ) );
1207 const QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral(
"dataDefinedServerProperties" ) );
1208 if ( !ddElem.isNull() )
1210 if ( !ddServerProperties.
readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
1212 QgsDebugError( QStringLiteral(
"dataDefinedServerProperties.readXml() failed" ) );
1215 return ddServerProperties;
1222static void _getTitle(
const QDomDocument &doc, QString &title )
1224 const QDomElement titleNode = doc.documentElement().firstChildElement( QStringLiteral(
"title" ) );
1228 if ( titleNode.isNull() )
1234 if ( !titleNode.hasChildNodes() )
1240 const QDomNode titleTextNode = titleNode.firstChild();
1242 if ( !titleTextNode.isText() )
1248 const QDomText titleText = titleTextNode.toText();
1250 title = titleText.data();
1254static void readProjectFileMetadata(
const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
1256 const QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1260 QgsDebugError( QStringLiteral(
"unable to find qgis element" ) );
1264 const QDomNode qgisNode = nl.item( 0 );
1266 const QDomElement qgisElement = qgisNode.toElement();
1267 lastUser = qgisElement.attribute( QStringLiteral(
"saveUser" ), QString() );
1268 lastUserFull = qgisElement.attribute( QStringLiteral(
"saveUserFull" ), QString() );
1269 lastSaveDateTime = QDateTime::fromString( qgisElement.attribute( QStringLiteral(
"saveDateTime" ), QString() ), Qt::ISODate );
1274 const QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1278 QgsDebugError( QStringLiteral(
" unable to find qgis element in project file" ) );
1282 const QDomNode qgisNode = nl.item( 0 );
1284 const QDomElement qgisElement = qgisNode.toElement();
1285 QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral(
"version" ) ) );
1286 return projectVersion;
1293 return mSnappingConfig;
1312 if ( mAvoidIntersectionsMode == mode )
1315 mAvoidIntersectionsMode = mode;
1319static QgsMapLayer::ReadFlags projectFlagsToLayerReadFlags( Qgis::ProjectReadFlags projectReadFlags, Qgis::ProjectFlags projectFlags )
1321 QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1344void QgsProject::preloadProviders(
const QVector<QDomNode> ¶llelLayerNodes,
1346 QMap<QString, QgsDataProvider *> &loadedProviders,
1347 QgsMapLayer::ReadFlags layerReadFlags,
1348 int totalProviderCount )
1353 QMap<QString, LayerToLoad> layersToLoad;
1355 for (
const QDomNode &node : parallelLayerNodes )
1359 const QDomElement layerElement = node.toElement();
1361 layerToLoad.
layerId = layerElement.namedItem( QStringLiteral(
"id" ) ).toElement().text();
1362 layerToLoad.
provider = layerElement.namedItem( QStringLiteral(
"provider" ) ).toElement().text();
1363 layerToLoad.
dataSource = layerElement.namedItem( QStringLiteral(
"datasource" ) ).toElement().text();
1374 layersToLoad.insert( layerToLoad.
layerId, layerToLoad );
1377 while ( !layersToLoad.isEmpty() )
1379 const QList<LayerToLoad> layersToAttemptInParallel = layersToLoad.values();
1380 QString layerToAttemptInMainThread;
1382 QHash<QString, QgsRunnableProviderCreator *> runnables;
1383 QThreadPool threadPool;
1386 for (
const LayerToLoad &lay : layersToAttemptInParallel )
1389 runnables.insert( lay.layerId, run );
1395 layersToLoad.remove( layId );
1398 Q_ASSERT( finishedRun );
1400 std::unique_ptr<QgsDataProvider> provider( finishedRun->
dataProvider() );
1401 Q_ASSERT( provider && provider->isValid() );
1403 loadedProviders.insert( layId, provider.release() );
1408 if ( layerToAttemptInMainThread.isEmpty() )
1409 layerToAttemptInMainThread = layId;
1413 if ( i == parallelLayerNodes.count() || !isValid )
1416 threadPool.start( run );
1420 threadPool.waitForDone();
1422 qDeleteAll( runnables );
1425 auto it = layersToLoad.find( layerToAttemptInMainThread );
1426 if ( it != layersToLoad.end() )
1428 std::unique_ptr<QgsDataProvider> provider;
1432 QgsDataProvider::ReadFlags providerFlags = lay.
flags;
1438 if ( provider && provider->isValid() )
1443 layersToLoad.erase( it );
1446 loadedProviders.insert( layerId, provider.release() );
1454void QgsProject::releaseHandlesToProjectArchive()
1459bool QgsProject::_getMapLayers(
const QDomDocument &doc, QList<QDomNode> &brokenNodes, Qgis::ProjectReadFlags flags )
1466 QDomElement layerElement = doc.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) ).firstChildElement( QStringLiteral(
"maplayer" ) );
1470 if ( layerElement.isNull() )
1480 bool returnStatus =
true;
1483 while ( ! layerElement.isNull() )
1486 layerElement = layerElement.nextSiblingElement( QStringLiteral(
"maplayer" ) );
1492 if ( depSorter.hasCycle() )
1496 if ( depSorter.hasMissingDependency() )
1497 returnStatus =
false;
1501 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1502 const int totalLayerCount = sortedLayerNodes.count();
1504 QVector<QDomNode> parallelLoading;
1505 QMap<QString, QgsDataProvider *> loadedProviders;
1509 profile.switchTask( tr(
"Load providers in parallel" ) );
1510 for (
const QDomNode &node : sortedLayerNodes )
1512 const QDomElement element = node.toElement();
1513 if ( element.attribute( QStringLiteral(
"embedded" ) ) != QLatin1String(
"1" ) )
1515 const QString layerId = node.namedItem( QStringLiteral(
"id" ) ).toElement().text();
1516 if ( !depSorter.isLayerDependent( layerId ) )
1518 const QDomNode mnl = element.namedItem( QStringLiteral(
"provider" ) );
1519 const QDomElement mne = mnl.toElement();
1520 const QString provider = mne.text();
1524 parallelLoading.append( node );
1533 if ( !parallelLoading.isEmpty() )
1534 preloadProviders( parallelLoading, context, loadedProviders, projectFlagsToLayerReadFlags(
flags, mFlags ), sortedLayerNodes.count() );
1537 int i = loadedProviders.count();
1538 for (
const QDomNode &node : std::as_const( sortedLayerNodes ) )
1540 const QDomElement element = node.toElement();
1541 const QString name =
translate( QStringLiteral(
"project:layers:%1" ).arg( node.namedItem( QStringLiteral(
"id" ) ).toElement().text() ), node.namedItem( QStringLiteral(
"layername" ) ).toElement().text() );
1542 if ( !name.isNull() )
1543 emit
loadingLayer( tr(
"Loading layer %1" ).arg( name ) );
1545 profile.switchTask( name );
1546 if ( element.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
1548 createEmbeddedLayer( element.attribute( QStringLiteral(
"id" ) ),
readPath( element.attribute( QStringLiteral(
"project" ) ) ), brokenNodes,
true,
flags );
1556 QString layerId = element.namedItem( QStringLiteral(
"id" ) ).toElement().text();
1558 if ( !addLayer( element, brokenNodes, context,
flags, loadedProviders.take( layerId ) ) )
1560 returnStatus =
false;
1563 if ( !messages.isEmpty() )
1572 return returnStatus;
1575bool QgsProject::addLayer(
const QDomElement &layerElem,
1576 QList<QDomNode> &brokenNodes,
1578 Qgis::ProjectReadFlags flags,
1583 const QString type = layerElem.attribute( QStringLiteral(
"type" ) );
1585 std::unique_ptr<QgsMapLayer>
mapLayer;
1593 QgsDebugError( QStringLiteral(
"Unknown layer type \"%1\"" ).arg( type ) );
1597 switch ( layerType )
1600 mapLayer = std::make_unique<QgsVectorLayer>();
1604 mapLayer = std::make_unique<QgsRasterLayer>();
1608 mapLayer = std::make_unique<QgsMeshLayer>();
1612 mapLayer = std::make_unique<QgsVectorTileLayer>();
1616 mapLayer = std::make_unique<QgsPointCloudLayer>();
1620 mapLayer = std::make_unique<QgsTiledSceneLayer>();
1625 const QString
typeName = layerElem.attribute( QStringLiteral(
"name" ) );
1633 mapLayer = std::make_unique<QgsAnnotationLayer>( QString(), options );
1640 mapLayer = std::make_unique<QgsGroupLayer>( QString(), options );
1647 QgsDebugError( QStringLiteral(
"Unable to create layer" ) );
1655 const QString layerId { layerElem.namedItem( QStringLiteral(
"id" ) ).toElement().text() };
1656 Q_ASSERT( ! layerId.isEmpty() );
1660 QgsMapLayer::ReadFlags layerFlags = projectFlagsToLayerReadFlags(
flags, mFlags );
1662 profile.switchTask( tr(
"Load layer source" ) );
1669 if ( vl->dataProvider() )
1676 profile.switchTask( tr(
"Add layer to project" ) );
1677 QList<QgsMapLayer *> newLayers;
1689 vLayer->joinBuffer()->resolveReferences(
this );
1698 brokenNodes.push_back( layerElem );
1701 const bool wasEditable = layerElem.attribute( QStringLiteral(
"editable" ), QStringLiteral(
"0" ) ).toInt();
1713 if ( ! layerWasStored )
1718 return layerIsValid;
1725 mFile.setFileName( filename );
1726 mCachedHomePath.clear();
1727 mProjectScope.reset();
1736 const QString filename = mFile.fileName();
1741 QTemporaryFile inDevice;
1742 if ( !inDevice.open() )
1744 setError( tr(
"Unable to open %1" ).arg( inDevice.fileName() ) );
1750 if ( !storage->readProject( filename, &inDevice, context ) )
1752 QString err = tr(
"Unable to open %1" ).arg( filename );
1753 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
1754 if ( !messages.isEmpty() )
1755 err += QStringLiteral(
"\n\n" ) + messages.last().message();
1759 returnValue = unzip( inDevice.fileName(),
flags );
1765 returnValue = unzip( mFile.fileName(),
flags );
1770 const QFileInfo finfo( mFile.fileName() );
1771 const QString attachmentsZip = finfo.absoluteDir().absoluteFilePath( QStringLiteral(
"%1_attachments.zip" ).arg( finfo.completeBaseName() ) );
1772 if ( QFile( attachmentsZip ).exists() )
1774 std::unique_ptr<QgsArchive> archive(
new QgsArchive() );
1775 if ( archive->unzip( attachmentsZip ) )
1777 releaseHandlesToProjectArchive();
1778 mArchive = std::move( archive );
1781 returnValue = readProjectFile( mFile.fileName(),
flags );
1787 mFile.setFileName( filename );
1788 mCachedHomePath.clear();
1789 mProjectScope.reset();
1794 mTranslator.reset(
nullptr );
1801bool QgsProject::readProjectFile(
const QString &filename, Qgis::ProjectReadFlags flags )
1806 ScopedIntIncrementor snapSignalBlock( &mBlockSnappingUpdates );
1808 QFile projectFile( filename );
1816 if ( QFile( QStringLiteral(
"%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1818 mTranslator.reset(
new QTranslator() );
1819 ( void )mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1822 profile.switchTask( tr(
"Reading project file" ) );
1823 std::unique_ptr<QDomDocument> doc(
new QDomDocument( QStringLiteral(
"qgis" ) ) );
1825 if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1827 projectFile.close();
1829 setError( tr(
"Unable to open %1" ).arg( projectFile.fileName() ) );
1834 QTextStream textStream( &projectFile );
1835#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1836 textStream.setCodec(
"UTF-8" );
1838 QString projectString = textStream.readAll();
1839 projectFile.close();
1841 for (
int i = 0; i < 32; i++ )
1843 if ( i == 9 || i == 10 || i == 13 )
1847 projectString.replace( QChar( i ), QStringLiteral(
"%1%2%1" ).arg(
FONTMARKER_CHR_FIX, QString::number( i ) ) );
1853 if ( !doc->setContent( projectString, &errorMsg, &line, &column ) )
1855 const QString errorString = tr(
"Project file read error in file %1: %2 at line %3 column %4" )
1856 .arg( projectFile.fileName(), errorMsg ).arg( line ).arg( column );
1858 setError( errorString );
1863 projectFile.close();
1871 profile.switchTask( tr(
"Updating project file" ) );
1872 if ( thisVersion > fileVersion )
1874 const bool isOlderMajorVersion = fileVersion.
majorVersion() < thisVersion.majorVersion();
1876 if ( isOlderMajorVersion )
1879 "version of qgis (saved in " + fileVersion.
text() +
1881 "). Problems may occur." );
1892 projectFile.updateRevision( thisVersion );
1894 else if ( fileVersion > thisVersion )
1897 "version of qgis (saved in " + fileVersion.
text() +
1899 "). Problems may occur." );
1905 profile.switchTask( tr(
"Creating auxiliary storage" ) );
1906 const QString
fileName = mFile.fileName();
1911 std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
1912 std::unique_ptr<QgsArchive> archive = std::move( mArchive );
1918 releaseHandlesToProjectArchive();
1920 mAuxiliaryStorage = std::move( aStorage );
1921 mArchive = std::move( archive );
1926 mCachedHomePath.clear();
1927 mProjectScope.reset();
1928 mSaveVersion = fileVersion;
1931 profile.switchTask( tr(
"Reading properties" ) );
1940 dump_( mProperties );
1945 _getTitle( *doc, oldTitle );
1947 readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1949 const QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral(
"homePath" ) );
1950 if ( homePathNl.count() > 0 )
1952 const QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1953 const QString
homePath = homePathElement.attribute( QStringLiteral(
"path" ) );
1963 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), 255 ),
1964 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), 255 ) );
1967 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), 255 ),
1968 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), 255 ),
1969 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), 255 ) );
1973 const QString distanceUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), QString() );
1974 if ( !distanceUnitString.isEmpty() )
1977 const QString areaUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), QString() );
1978 if ( !areaUnitString.isEmpty() )
1987 if (
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ), 0 ) )
1990 const QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral(
"projectCrs" ) );
1991 if ( !srsNode.isNull() )
1993 projectCrs.
readXml( srsNode );
1998 const QString projCrsString =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSProj4String" ) );
1999 const long currentCRS =
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSID" ), -1 );
2000 const QString authid =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCrs" ) );
2003 const bool isUserAuthId = authid.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive );
2004 if ( !authid.isEmpty() && !isUserAuthId )
2008 if ( !projectCrs.
isValid() && currentCRS >= 0 )
2014 if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.
isValid() || projectCrs.
toProj() != projCrsString ) )
2028 QStringList datumErrors;
2029 if ( !mTransformContext.
readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
2036 const QDomNode elevationShadingNode = doc->documentElement().namedItem( QStringLiteral(
"elevation-shading-renderer" ) );
2037 if ( !elevationShadingNode.isNull() )
2039 mElevationShadingRenderer.
readXml( elevationShadingNode.toElement(), context );
2046 const QStringList variableNames =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ) );
2047 const QStringList variableValues =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ) );
2049 mCustomVariables.clear();
2050 if ( variableNames.length() == variableValues.length() )
2052 for (
int i = 0; i < variableNames.length(); ++i )
2054 mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
2059 QgsMessageLog::logMessage( tr(
"Project Variables Invalid" ), tr(
"The project contains invalid variable settings." ) );
2062 QDomElement element = doc->documentElement().firstChildElement( QStringLiteral(
"projectMetadata" ) );
2064 if ( !element.isNull() )
2073 if ( mMetadata.
title().isEmpty() && !oldTitle.isEmpty() )
2081 element = doc->documentElement().firstChildElement( QStringLiteral(
"transaction" ) );
2082 if ( !element.isNull() )
2089 element = doc->documentElement().firstChildElement( QStringLiteral(
"autotransaction" ) );
2090 if ( ! element.isNull() )
2092 mTransactionMode =
static_cast<Qgis::TransactionMode>( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() );
2097 profile.switchTask( tr(
"Loading layer tree" ) );
2100 QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
2101 if ( !layerTreeElem.isNull() )
2113 mLayerTreeRegistryBridge->
setEnabled(
false );
2116 profile.switchTask( tr(
"Reading map layers" ) );
2118 loadProjectFlags( doc.get() );
2120 QList<QDomNode> brokenNodes;
2121 const bool clean = _getMapLayers( *doc, brokenNodes,
flags );
2126 QgsDebugError( QStringLiteral(
"Unable to get map layers from project file." ) );
2128 if ( !brokenNodes.isEmpty() )
2130 QgsDebugError(
"there are " + QString::number( brokenNodes.size() ) +
" broken layers" );
2138 mMainAnnotationLayer->
readLayerXml( doc->documentElement().firstChildElement( QStringLiteral(
"main-annotation-layer" ) ), context );
2142 profile.switchTask( tr(
"Loading embedded layers" ) );
2143 loadEmbeddedNodes( mRootGroup,
flags );
2147 profile.switchTask( tr(
"Resolving layer references" ) );
2148 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
2149 for ( QMap<QString, QgsMapLayer *>::iterator it =
layers.begin(); it !=
layers.end(); ++it )
2151 it.value()->resolveReferences(
this );
2154 mLayerTreeRegistryBridge->
setEnabled(
true );
2157 profile.switchTask( tr(
"Resolving references" ) );
2168 if ( !layerTreeElem.isNull() )
2174 const QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-canvas" ) );
2175 if ( !layerTreeCanvasElem.isNull( ) )
2183 const QStringList requiredLayerIds =
readListEntry( QStringLiteral(
"RequiredLayers" ), QStringLiteral(
"Layers" ) );
2184 for (
const QString &layerId : requiredLayerIds )
2191 const QStringList disabledLayerIds =
readListEntry( QStringLiteral(
"Identify" ), QStringLiteral(
"/disabledLayers" ) );
2192 for (
const QString &layerId : disabledLayerIds )
2205 QString styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Marker" ) );
2206 if ( !styleName.isEmpty() )
2211 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Line" ) );
2212 if ( !styleName.isEmpty() )
2217 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Fill" ) );
2218 if ( !styleName.isEmpty() )
2223 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/ColorRamp" ) );
2224 if ( !styleName.isEmpty() )
2234 double opacity = 1.0;
2237 double alpha =
readDoubleEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/AlphaInt" ), 255, &ok );
2239 opacity = alpha / 255.0;
2240 double newOpacity =
readDoubleEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Opacity" ), 1.0, &ok );
2242 opacity = newOpacity;
2246 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Marker" ) );
2247 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Line" ) );
2248 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Fill" ) );
2249 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/ColorRamp" ) );
2250 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/RandomColors" ) );
2251 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/AlphaInt" ) );
2252 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Opacity" ) );
2260 profile.switchTask( tr(
"Storing original layer properties" ) );
2266 profile.switchTask( tr(
"Loading map themes" ) );
2269 mMapThemeCollection->readXml( *doc );
2271 profile.switchTask( tr(
"Loading label settings" ) );
2272 mLabelingEngineSettings->readSettingsFromProject(
this );
2275 profile.switchTask( tr(
"Loading annotations" ) );
2276 mAnnotationManager->readXml( doc->documentElement(), context );
2279 profile.switchTask( tr(
"Loading layouts" ) );
2280 mLayoutManager->readXml( doc->documentElement(), *doc );
2285 profile.switchTask( tr(
"Loading 3D Views" ) );
2286 m3DViewsManager->readXml( doc->documentElement(), *doc );
2289 profile.switchTask( tr(
"Loading bookmarks" ) );
2290 mBookmarkManager->
readXml( doc->documentElement(), *doc );
2292 profile.switchTask( tr(
"Loading sensors" ) );
2293 mSensorManager->
readXml( doc->documentElement(), *doc );
2296 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
2297 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
2299 it.value()->setDependencies( it.value()->dependencies() );
2302 profile.switchTask( tr(
"Loading snapping settings" ) );
2306 profile.switchTask( tr(
"Loading view settings" ) );
2309 const QStringList scales =
readListEntry( QStringLiteral(
"Scales" ), QStringLiteral(
"/ScalesList" ) );
2310 QVector<double> res;
2311 for (
const QString &scale : scales )
2313 const QStringList parts = scale.split(
':' );
2314 if ( parts.size() != 2 )
2318 const double denominator = QLocale().toDouble( parts[1], &ok );
2325 const QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectViewSettings" ) );
2326 if ( !viewSettingsElement.isNull() )
2327 mViewSettings->
readXml( viewSettingsElement, context );
2330 profile.switchTask( tr(
"Loading style properties" ) );
2331 const QDomElement styleSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectStyleSettings" ) );
2332 if ( !styleSettingsElement.isNull() )
2335 mStyleSettings->
readXml( styleSettingsElement, context,
flags );
2339 profile.switchTask( tr(
"Loading temporal settings" ) );
2340 const QDomElement timeSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectTimeSettings" ) );
2341 if ( !timeSettingsElement.isNull() )
2342 mTimeSettings->
readXml( timeSettingsElement, context );
2345 profile.switchTask( tr(
"Loading elevation properties" ) );
2346 const QDomElement elevationPropertiesElement = doc->documentElement().firstChildElement( QStringLiteral(
"ElevationProperties" ) );
2347 if ( !elevationPropertiesElement.isNull() )
2348 mElevationProperties->
readXml( elevationPropertiesElement, context );
2351 profile.switchTask( tr(
"Loading display settings" ) );
2353 const QDomElement displaySettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectDisplaySettings" ) );
2354 if ( !displaySettingsElement.isNull() )
2355 mDisplaySettings->
readXml( displaySettingsElement, context );
2358 profile.switchTask( tr(
"Loading GPS settings" ) );
2360 const QDomElement gpsSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectGpsSettings" ) );
2361 if ( !gpsSettingsElement.isNull() )
2362 mGpsSettings->
readXml( gpsSettingsElement, context );
2366 profile.switchTask( tr(
"Updating variables" ) );
2368 profile.switchTask( tr(
"Updating CRS" ) );
2373 profile.switchTask( tr(
"Reading external settings" ) );
2377 profile.switchTask( tr(
"Updating interface" ) );
2379 snapSignalBlock.release();
2380 if ( !mBlockSnappingUpdates )
2391 QgsDebugMsgLevel( QStringLiteral(
"Project save user: %1" ).arg( mSaveUser ), 2 );
2392 QgsDebugMsgLevel( QStringLiteral(
"Project save user: %1" ).arg( mSaveUserFull ), 2 );
2401 const QString newFileName( QStringLiteral(
"%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
2416 const QMap<QString, QgsMapLayer *> loadedLayers =
mapLayers();
2417 for (
auto it = loadedLayers.constBegin(); it != loadedLayers.constEnd(); ++it )
2419 if ( it.value()->isValid() && it.value()->customProperty( QStringLiteral(
"_layer_was_editable" ) ).toBool() )
2421 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( it.value() ) )
2423 it.value()->removeCustomProperty( QStringLiteral(
"_layer_was_editable" ) );
2430bool QgsProject::loadEmbeddedNodes(
QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
2435 const auto constChildren = group->
children();
2441 if ( childGroup->
customProperty( QStringLiteral(
"embedded" ) ).toInt() )
2444 const QString projectPath =
readPath( childGroup->
customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
2445 childGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectPath );
2449 QList<QgsLayerTreeNode *> clonedChildren;
2450 const QList<QgsLayerTreeNode *> constChildren = newGroup->
children();
2451 clonedChildren.reserve( constChildren.size() );
2453 clonedChildren << newGroupChild->clone();
2461 loadEmbeddedNodes( childGroup,
flags );
2466 if ( child->customProperty( QStringLiteral(
"embedded" ) ).toInt() )
2468 QList<QDomNode> brokenNodes;
2471 valid = valid &&
false;
2486 return mCustomVariables;
2493 if ( variables == mCustomVariables )
2497 QStringList variableNames;
2498 QStringList variableValues;
2500 QVariantMap::const_iterator it = variables.constBegin();
2501 for ( ; it != variables.constEnd(); ++it )
2503 variableNames << it.key();
2504 variableValues << it.value().toString();
2507 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ), variableNames );
2508 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ), variableValues );
2510 mCustomVariables = variables;
2511 mProjectScope.reset();
2520 *mLabelingEngineSettings = settings;
2528 return *mLabelingEngineSettings;
2535 mProjectScope.reset();
2536 return mLayerStore.get();
2543 return mLayerStore.get();
2550 QList<QgsVectorLayer *>
layers;
2551 const QStringList layerIds =
readListEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), QStringList() );
2552 const auto constLayerIds = layerIds;
2553 for (
const QString &layerId : constLayerIds )
2566 list.reserve(
layers.size() );
2568 list << layer->id();
2569 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), list );
2591 if ( mProjectScope )
2593 std::unique_ptr< QgsExpressionContextScope > projectScope = std::make_unique< QgsExpressionContextScope >( *mProjectScope );
2600 projectScope->addFunction( QStringLiteral(
"sensor_data" ),
new GetSensorData(
sensorManager()->sensorsData() ) );
2602 return projectScope.release();
2605 mProjectScope = std::make_unique< QgsExpressionContextScope >( QObject::tr(
"Project" ) );
2609 QVariantMap::const_iterator it = vars.constBegin();
2611 for ( ; it != vars.constEnd(); ++it )
2613 mProjectScope->setVariable( it.key(), it.value(),
true );
2617 if ( projectPath.isEmpty() )
2618 projectPath = mOriginalPath;
2619 const QString projectFolder = QFileInfo( projectPath ).path();
2620 const QString projectFilename = QFileInfo( projectPath ).fileName();
2621 const QString projectBasename =
baseName();
2650 QVariantMap keywords;
2652 for (
auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
2654 keywords.insert( it.key(), it.value() );
2659 QVariantList layersIds;
2661 const QMap<QString, QgsMapLayer *> layersInProject = mLayerStore->mapLayers();
2662 layersIds.reserve( layersInProject.count() );
2663 layers.reserve( layersInProject.count() );
2664 for (
auto it = layersInProject.constBegin(); it != layersInProject.constEnd(); ++it )
2666 layersIds << it.value()->id();
2672 mProjectScope->addFunction( QStringLiteral(
"project_color" ),
new GetNamedProjectColor(
this ) );
2677void QgsProject::onMapLayersAdded(
const QList<QgsMapLayer *> &layers )
2681 const QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
2683 const auto constLayers =
layers;
2686 if ( ! layer->isValid() )
2689 if (
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer ) )
2692 if ( vlayer->dataProvider() )
2700 for ( QMap<QString, QgsMapLayer *>::const_iterator it = existingMaps.cbegin(); it != existingMaps.cend(); ++it )
2702 const QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
2703 if ( deps.contains( layer->id() ) )
2706 it.value()->setDependencies( deps );
2711 updateTransactionGroups();
2717void QgsProject::onMapLayersRemoved(
const QList<QgsMapLayer *> &layers )
2725void QgsProject::cleanTransactionGroups(
bool force )
2729 bool changed =
false;
2730 for ( QMap< QPair< QString, QString>,
QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
2732 if ( tg.value()->isEmpty() || force )
2735 tg = mTransactionGroups.erase( tg );
2747void QgsProject::updateTransactionGroups()
2751 mEditBufferGroup.
clear();
2753 switch ( mTransactionMode )
2757 cleanTransactionGroups(
true );
2762 cleanTransactionGroups(
true );
2765 cleanTransactionGroups(
false );
2769 bool tgChanged =
false;
2770 const auto constLayers =
mapLayers().values();
2773 if ( ! layer->isValid() )
2776 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
2780 switch ( mTransactionMode )
2797 mTransactionGroups.insert( qMakePair( key, connString ), tg );
2807 mEditBufferGroup.
addLayer( vlayer );
2823 context.setProjectTranslator(
this );
2825 QList<QDomNode> brokenNodes;
2826 if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
2830 const QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
2834 layer->resolveReferences(
this );
2836 if ( layer->isValid() && layer->customProperty( QStringLiteral(
"_layer_was_editable" ) ).toBool() )
2838 layer->startEditing();
2839 layer->removeCustomProperty( QStringLiteral(
"_layer_was_editable" ) );
2851 mFile.setFileName( filename );
2852 mCachedHomePath.clear();
2860 mProjectScope.reset();
2866 const QString storageFilePath { storage->filePath( mFile.fileName() ) };
2867 if ( storageFilePath.isEmpty() )
2873 const QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2874 const QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2876 if ( !zip( tmpZipFilename ) )
2879 QFile tmpZipFile( tmpZipFilename );
2880 if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2882 setError( tr(
"Unable to read file %1" ).arg( tmpZipFilename ) );
2887 if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2889 QString err = tr(
"Unable to save project to storage %1" ).arg( mFile.fileName() );
2890 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
2891 if ( !messages.isEmpty() )
2892 err += QStringLiteral(
"\n\n" ) + messages.last().message();
2898 QFile::remove( tmpZipFilename );
2905 return zip( mFile.fileName() );
2911 const bool asOk = saveAuxiliaryStorage();
2912 const bool writeOk = writeProjectFile( mFile.fileName() );
2913 bool attachmentsOk =
true;
2914 if ( !mArchive->files().isEmpty() )
2916 const QFileInfo finfo( mFile.fileName() );
2917 const QString attachmentsZip = finfo.absoluteDir().absoluteFilePath( QStringLiteral(
"%1_attachments.zip" ).arg( finfo.completeBaseName() ) );
2918 attachmentsOk = mArchive->zip( attachmentsZip );
2922 if ( ( !asOk || !attachmentsOk ) && writeOk )
2924 QStringList errorMessage;
2927 const QString err = mAuxiliaryStorage->errorString();
2928 errorMessage.append( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
2930 if ( !attachmentsOk )
2932 errorMessage.append( tr(
"Unable to save attachments archive" ) );
2934 setError( errorMessage.join(
'\n' ) );
2937 return asOk && writeOk && attachmentsOk;
2941bool QgsProject::writeProjectFile(
const QString &filename )
2945 QFile projectFile( filename );
2951 const QFileInfo myFileInfo( projectFile );
2952 if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2954 setError( tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
2955 .arg( projectFile.fileName() ) );
2963 QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2965 const QDomDocumentType documentType =
2966 QDomImplementation().createDocumentType( QStringLiteral(
"qgis" ), QStringLiteral(
"http://mrcc.com/qgis.dtd" ),
2967 QStringLiteral(
"SYSTEM" ) );
2968 std::unique_ptr<QDomDocument> doc(
new QDomDocument( documentType ) );
2970 QDomElement qgisNode = doc->createElement( QStringLiteral(
"qgis" ) );
2971 qgisNode.setAttribute( QStringLiteral(
"projectname" ),
title() );
2972 qgisNode.setAttribute( QStringLiteral(
"version" ),
Qgis::version() );
2974 if ( !mSettings.
value( QStringLiteral(
"projects/anonymize_saved_projects" ),
false,
QgsSettings::Core ).toBool() )
2978 qgisNode.setAttribute( QStringLiteral(
"saveUser" ), newSaveUser );
2979 qgisNode.setAttribute( QStringLiteral(
"saveUserFull" ), newSaveUserFull );
2980 mSaveUser = newSaveUser;
2981 mSaveUserFull = newSaveUserFull;
2982 mSaveDateTime = QDateTime::currentDateTime();
2983 qgisNode.setAttribute( QStringLiteral(
"saveDateTime" ), mSaveDateTime.toString( Qt::ISODate ) );
2988 mSaveUserFull.clear();
2989 mSaveDateTime = QDateTime();
2991 doc->appendChild( qgisNode );
2994 QDomElement homePathNode = doc->createElement( QStringLiteral(
"homePath" ) );
2995 homePathNode.setAttribute( QStringLiteral(
"path" ), mHomePath );
2996 qgisNode.appendChild( homePathNode );
2999 QDomElement titleNode = doc->createElement( QStringLiteral(
"title" ) );
3000 qgisNode.appendChild( titleNode );
3002 QDomElement transactionNode = doc->createElement( QStringLiteral(
"transaction" ) );
3003 transactionNode.setAttribute( QStringLiteral(
"mode" ),
qgsEnumValueToKey( mTransactionMode ) );
3004 qgisNode.appendChild( transactionNode );
3006 QDomElement flagsNode = doc->createElement( QStringLiteral(
"projectFlags" ) );
3008 qgisNode.appendChild( flagsNode );
3010 const QDomText titleText = doc->createTextNode(
title() );
3011 titleNode.appendChild( titleText );
3014 QDomElement srsNode = doc->createElement( QStringLiteral(
"projectCrs" ) );
3016 qgisNode.appendChild( srsNode );
3018 QDomElement elevationShadingNode = doc->createElement( QStringLiteral(
"elevation-shading-renderer" ) );
3019 mElevationShadingRenderer.
writeXml( elevationShadingNode, context );
3020 qgisNode.appendChild( elevationShadingNode );
3027 clonedRoot->
writeXml( qgisNode, context );
3031 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsMode" ),
static_cast<int>( mAvoidIntersectionsMode ) );
3039 QDomElement annotationLayerNode = doc->createElement( QStringLiteral(
"main-annotation-layer" ) );
3040 mMainAnnotationLayer->
writeLayerXml( annotationLayerNode, *doc, context );
3041 qgisNode.appendChild( annotationLayerNode );
3045 QDomElement projectLayersNode = doc->createElement( QStringLiteral(
"projectlayers" ) );
3047 QMap<QString, QgsMapLayer *>::ConstIterator li =
layers.constBegin();
3048 while ( li !=
layers.end() )
3054 const QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->
id() );
3055 if ( emIt == mEmbeddedLayers.constEnd() )
3057 QDomElement maplayerElem;
3063 maplayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
3067 maplayerElem.setAttribute( QStringLiteral(
"editable" ), QStringLiteral(
"1" ) );
3071 QDomDocument document;
3074 maplayerElem = document.firstChildElement();
3078 QgsDebugError( QStringLiteral(
"Could not restore layer properties for layer %1" ).arg( ml->
id() ) );
3084 projectLayersNode.appendChild( maplayerElem );
3090 if ( emIt.value().second )
3092 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
3093 mapLayerElem.setAttribute( QStringLiteral(
"embedded" ), 1 );
3094 mapLayerElem.setAttribute( QStringLiteral(
"project" ),
writePath( emIt.value().first ) );
3095 mapLayerElem.setAttribute( QStringLiteral(
"id" ), ml->
id() );
3096 projectLayersNode.appendChild( mapLayerElem );
3103 qgisNode.appendChild( projectLayersNode );
3105 QDomElement layerOrderNode = doc->createElement( QStringLiteral(
"layerorder" ) );
3107 for (
QgsMapLayer *layer : constCustomLayerOrder )
3109 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"layer" ) );
3110 mapLayerElem.setAttribute( QStringLiteral(
"id" ), layer->id() );
3111 layerOrderNode.appendChild( mapLayerElem );
3113 qgisNode.appendChild( layerOrderNode );
3115 mLabelingEngineSettings->writeSettingsToProject(
this );
3117 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorRedPart" ), mBackgroundColor.red() );
3118 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), mBackgroundColor.green() );
3119 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), mBackgroundColor.blue() );
3121 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorRedPart" ), mSelectionColor.red() );
3122 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), mSelectionColor.green() );
3123 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), mSelectionColor.blue() );
3124 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), mSelectionColor.alpha() );
3131 dump_( mProperties );
3134 QgsDebugMsgLevel( QStringLiteral(
"there are %1 property scopes" ).arg(
static_cast<int>( mProperties.
count() ) ), 2 );
3139 mProperties.
writeXml( QStringLiteral(
"properties" ), qgisNode, *doc );
3142 QDomElement ddElem = doc->createElement( QStringLiteral(
"dataDefinedServerProperties" ) );
3143 mDataDefinedServerProperties.
writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
3144 qgisNode.appendChild( ddElem );
3146 mMapThemeCollection->writeXml( *doc );
3148 mTransformContext.
writeXml( qgisNode, context );
3150 QDomElement metadataElem = doc->createElement( QStringLiteral(
"projectMetadata" ) );
3152 qgisNode.appendChild( metadataElem );
3155 const QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
3156 qgisNode.appendChild( annotationsElem );
3160 const QDomElement layoutElem = mLayoutManager->writeXml( *doc );
3161 qgisNode.appendChild( layoutElem );
3165 const QDomElement views3DElem = m3DViewsManager->writeXml( *doc );
3166 qgisNode.appendChild( views3DElem );
3170 const QDomElement bookmarkElem = mBookmarkManager->
writeXml( *doc );
3171 qgisNode.appendChild( bookmarkElem );
3175 const QDomElement sensorElem = mSensorManager->
writeXml( *doc );
3176 qgisNode.appendChild( sensorElem );
3180 const QDomElement viewSettingsElem = mViewSettings->
writeXml( *doc, context );
3181 qgisNode.appendChild( viewSettingsElem );
3185 const QDomElement styleSettingsElem = mStyleSettings->
writeXml( *doc, context );
3186 qgisNode.appendChild( styleSettingsElem );
3190 const QDomElement timeSettingsElement = mTimeSettings->
writeXml( *doc, context );
3191 qgisNode.appendChild( timeSettingsElement );
3195 const QDomElement elevationPropertiesElement = mElevationProperties->
writeXml( *doc, context );
3196 qgisNode.appendChild( elevationPropertiesElement );
3200 const QDomElement displaySettingsElem = mDisplaySettings->
writeXml( *doc, context );
3201 qgisNode.appendChild( displaySettingsElem );
3205 const QDomElement gpsSettingsElem = mGpsSettings->
writeXml( *doc, context );
3206 qgisNode.appendChild( gpsSettingsElem );
3215 QFile backupFile( QStringLiteral(
"%1~" ).arg( filename ) );
3217 ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
3218 ok &= projectFile.open( QIODevice::ReadOnly );
3221 while ( ok && !projectFile.atEnd() )
3223 ba = projectFile.read( 10240 );
3224 ok &= backupFile.write( ba ) == ba.size();
3227 projectFile.close();
3232 setError( tr(
"Unable to create backup file %1" ).arg( backupFile.fileName() ) );
3237 struct utimbuf tb = {
static_cast<time_t
>( fi.lastRead().toSecsSinceEpoch() ),
static_cast<time_t
>( fi.lastModified().toSecsSinceEpoch() ) };
3238 utime( backupFile.fileName().toUtf8().constData(), &tb );
3241 if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3243 projectFile.close();
3246 setError( tr(
"Unable to save to file %1" ).arg( projectFile.fileName() ) );
3250 QTemporaryFile tempFile;
3251 bool ok = tempFile.open();
3254 QTextStream projectFileStream( &tempFile );
3255 doc->save( projectFileStream, 2 );
3256 ok &= projectFileStream.pos() > -1;
3258 ok &= tempFile.seek( 0 );
3261 while ( ok && !tempFile.atEnd() )
3263 ba = tempFile.read( 10240 );
3264 ok &= projectFile.write( ba ) == ba.size();
3267 ok &= projectFile.error() == QFile::NoError;
3269 projectFile.close();
3276 setError( tr(
"Unable to save to file %1. Your project "
3277 "may be corrupted on disk. Try clearing some space on the volume and "
3278 "check file permissions before pressing save again." )
3279 .arg( projectFile.fileName() ) );
3293 bool propertiesModified;
3294 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3296 if ( propertiesModified )
3306 bool propertiesModified;
3307 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3309 if ( propertiesModified )
3319 bool propertiesModified;
3320 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3322 if ( propertiesModified )
3332 bool propertiesModified;
3333 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3335 if ( propertiesModified )
3345 bool propertiesModified;
3346 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3348 if ( propertiesModified )
3356 const QStringList &def,
3368 value =
property->value();
3370 const bool valid = QVariant::StringList == value.type();
3376 return value.toStringList();
3399 value =
property->value();
3401 const bool valid = value.canConvert( QVariant::String );
3406 return value.toString();
3425 value =
property->value();
3428 const bool valid = value.canConvert( QVariant::Int );
3437 return value.toInt();
3452 const QVariant value =
property->value();
3454 const bool valid = value.canConvert( QVariant::Double );
3459 return value.toDouble();
3476 const QVariant value =
property->value();
3478 const bool valid = value.canConvert( QVariant::Bool );
3483 return value.toBool();
3495 if (
findKey_( scope, key, mProperties ) )
3501 return !
findKey_( scope, key, mProperties );
3510 QStringList entries;
3512 if ( foundProperty )
3529 QStringList entries;
3531 if ( foundProperty )
3546 dump_( mProperties );
3566 filePath = storage->filePath( mFile.fileName() );
3593void QgsProject::setError(
const QString &errorMessage )
3597 mErrorMessage = errorMessage;
3604 return mErrorMessage;
3607void QgsProject::clearError()
3611 setError( QString() );
3618 delete mBadLayerHandler;
3619 mBadLayerHandler = handler;
3626 const QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find(
id );
3627 if ( it == mEmbeddedLayers.constEnd() )
3631 return it.value().first;
3635 bool saveFlag, Qgis::ProjectReadFlags flags )
3641 static QString sPrevProjectFilePath;
3642 static QDateTime sPrevProjectFileTimestamp;
3643 static QDomDocument sProjectDocument;
3645 QString qgsProjectFile = projectFilePath;
3647 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
3649 archive.
unzip( projectFilePath );
3653 const QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
3655 if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
3657 sPrevProjectFilePath.clear();
3659 QFile projectFile( qgsProjectFile );
3660 if ( !projectFile.open( QIODevice::ReadOnly ) )
3665 if ( !sProjectDocument.setContent( &projectFile ) )
3670 sPrevProjectFilePath = projectFilePath;
3671 sPrevProjectFileTimestamp = projectFileTimestamp;
3675 bool useAbsolutePaths =
true;
3677 const QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
3678 if ( !propertiesElem.isNull() )
3680 const QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral(
"Paths" ) ).firstChildElement( QStringLiteral(
"Absolute" ) );
3681 if ( !absElem.isNull() )
3683 useAbsolutePaths = absElem.text().compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
3688 if ( !useAbsolutePaths )
3693 const QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) );
3694 if ( projectLayersElem.isNull() )
3699 QDomElement mapLayerElem = projectLayersElem.firstChildElement( QStringLiteral(
"maplayer" ) );
3700 while ( ! mapLayerElem.isNull() )
3703 const QString
id = mapLayerElem.firstChildElement( QStringLiteral(
"id" ) ).text();
3704 if (
id == layerId )
3707 if ( mapLayerElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
3712 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
3714 if ( addLayer( mapLayerElem, brokenNodes, embeddedContext,
flags ) )
3720 mEmbeddedLayers.remove( layerId );
3724 mapLayerElem = mapLayerElem.nextSiblingElement( QStringLiteral(
"maplayer" ) );
3734 QString qgsProjectFile = projectFilePath;
3736 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
3738 archive.
unzip( projectFilePath );
3743 QFile projectFile( qgsProjectFile );
3744 if ( !projectFile.open( QIODevice::ReadOnly ) )
3749 QDomDocument projectDocument;
3750 if ( !projectDocument.setContent( &projectFile ) )
3762 QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
3763 if ( !layerTreeElem.isNull() )
3773 if ( !group || group->
customProperty( QStringLiteral(
"embedded" ) ).toBool() )
3786 newGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectFilePath );
3789 mLayerTreeRegistryBridge->
setEnabled(
false );
3790 initializeEmbeddedSubtree( projectFilePath, newGroup,
flags );
3791 mLayerTreeRegistryBridge->
setEnabled(
true );
3794 const auto constFindLayerIds = newGroup->
findLayerIds();
3795 for (
const QString &layerId : constFindLayerIds )
3808void QgsProject::initializeEmbeddedSubtree(
const QString &projectFilePath,
QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
3812 const auto constChildren = group->
children();
3816 child->setCustomProperty( QStringLiteral(
"embedded" ), 1 );
3825 QList<QDomNode> brokenNodes;
3849 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
3857 return readNumEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), 0 );
3864 if ( mDistanceUnits == unit )
3867 mDistanceUnits = unit;
3876 if ( mAreaUnits == unit )
3889 if ( !mCachedHomePath.isEmpty() )
3890 return mCachedHomePath;
3894 if ( !mHomePath.isEmpty() )
3896 const QFileInfo homeInfo( mHomePath );
3897 if ( !homeInfo.isRelative() )
3899 mCachedHomePath = mHomePath;
3909 const QString storagePath { storage->filePath(
fileName() ) };
3910 if ( ! storagePath.isEmpty() && QFileInfo::exists( storagePath ) )
3912 mCachedHomePath = QFileInfo( storagePath ).path();
3913 return mCachedHomePath;
3917 mCachedHomePath = pfi.path();
3918 return mCachedHomePath;
3921 if ( !pfi.exists() )
3923 mCachedHomePath = mHomePath;
3927 if ( !mHomePath.isEmpty() )
3930 mCachedHomePath = QDir::cleanPath( pfi.path() +
'/' + mHomePath );
3934 mCachedHomePath = pfi.canonicalPath();
3936 return mCachedHomePath;
3951 return mRelationManager;
3958 return mLayoutManager.get();
3965 return mLayoutManager.get();
3972 return m3DViewsManager.get();
3979 return m3DViewsManager.get();
3986 return mBookmarkManager;
3993 return mBookmarkManager;
4000 return mSensorManager;
4007 return mSensorManager;
4014 return mViewSettings;
4021 return mViewSettings;
4028 return mStyleSettings;
4036 return mStyleSettings;
4043 return mTimeSettings;
4050 return mTimeSettings;
4057 return mElevationProperties;
4064 return mElevationProperties;
4071 return mDisplaySettings;
4078 return mDisplaySettings;
4085 return mGpsSettings;
4092 return mGpsSettings;
4106 return mMapThemeCollection.get();
4113 return mAnnotationManager.get();
4120 return mAnnotationManager.get();
4127 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
4128 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
4133 if (
layers.contains( it.value() ) )
4134 it.value()->setFlags( it.value()->flags() &
~QgsMapLayer::Identifiable );
4150 for (
const QString &layerId : layerIds )
4168 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4202 updateTransactionGroups();
4209 return mTransactionMode;
4220 const auto constLayers =
mapLayers().values();
4223 if ( layer->isEditable() )
4225 QgsLogger::warning( tr(
"Transaction mode can be changed only if all layers are not editable." ) );
4231 updateTransactionGroups();
4239 return mTransactionGroups;
4252 return mLayerStore->count();
4259 return mLayerStore->validCount();
4267 return mLayerStore->mapLayer( layerId );
4274 return mLayerStore->mapLayersByName( layerName );
4281 QList<QgsMapLayer *>
layers;
4282 const auto constMapLayers { mLayerStore->mapLayers() };
4283 for (
const auto &l : constMapLayers )
4285 if ( ! l->shortName().isEmpty() )
4287 if ( l->shortName() == shortName )
4290 else if ( l->name() == shortName )
4298bool QgsProject::unzip(
const QString &filename, Qgis::ProjectReadFlags flags )
4306 if ( !archive->unzip( filename ) )
4308 setError( tr(
"Unable to unzip file '%1'" ).arg( filename ) );
4313 if ( archive->projectFile().isEmpty() )
4315 setError( tr(
"Zip archive does not provide a project file" ) );
4320 releaseHandlesToProjectArchive();
4321 mArchive = std::move( archive );
4338 setError( tr(
"Cannot read unzipped qgs project file" ) + QStringLiteral(
": " ) +
error() );
4348bool QgsProject::zip(
const QString &filename )
4356 const QString
baseName = QFileInfo( filename ).baseName();
4357 const QString qgsFileName = QStringLiteral(
"%1.qgs" ).arg(
baseName );
4358 QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
4360 bool writeOk =
false;
4361 if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
4363 writeOk = writeProjectFile( qgsFile.fileName() );
4370 setError( tr(
"Unable to write temporary qgs file" ) );
4375 const QFileInfo info( qgsFile );
4377 const QString asFileName = info.path() + QDir::separator() + info.completeBaseName() + asExt;
4379 bool auxiliaryStorageSavedOk =
true;
4380 if ( ! saveAuxiliaryStorage( asFileName ) )
4382 const QString err = mAuxiliaryStorage->errorString();
4383 setError( tr(
"Unable to save auxiliary storage file ('%1'). The project has been saved but the latest changes to auxiliary data cannot be recovered. It is recommended to reload the project." ).arg( err ) );
4384 auxiliaryStorageSavedOk =
false;
4387 if ( !mArchive->exists() )
4389 releaseHandlesToProjectArchive();
4391 mArchive->unzip( mFile.fileName() );
4394 const QString auxiliaryStorageFile =
static_cast<QgsProjectArchive *
>( mArchive.get() )->auxiliaryStorageFile();
4395 if ( ! auxiliaryStorageFile.isEmpty() )
4397 archive->
addFile( auxiliaryStorageFile );
4406 if ( QFile::exists( asFileName ) )
4408 archive->addFile( asFileName );
4413 archive->addFile( qgsFile.fileName() );
4416 const QStringList &
files = mArchive->files();
4417 for (
const QString &file :
files )
4419 if ( !file.endsWith( QLatin1String(
".qgs" ), Qt::CaseInsensitive ) && !file.endsWith( asExt, Qt::CaseInsensitive ) )
4421 archive->addFile( file );
4427 if ( !archive->zip( filename ) )
4429 setError( tr(
"Unable to perform zip" ) );
4433 return auxiliaryStorageSavedOk && zipOk;
4444 const QList<QgsMapLayer *> &layers,
4446 bool takeOwnership )
4450 const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers(
layers, takeOwnership ) };
4451 if ( !myResultList.isEmpty() )
4454 for (
auto &l : myResultList )
4464 if ( mAuxiliaryStorage )
4479 mProjectScope.reset();
4481 return myResultList;
4487 bool takeOwnership )
4491 QList<QgsMapLayer *> addedLayers;
4492 addedLayers =
addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
4493 return addedLayers.isEmpty() ? nullptr : addedLayers[0];
4496void QgsProject::removeAuxiliaryLayer(
const QgsMapLayer *ml )
4503 const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( ml );
4515 for (
const auto &layerId : layerIds )
4516 removeAuxiliaryLayer( mLayerStore->mapLayer( layerId ) );
4518 mProjectScope.reset();
4519 mLayerStore->removeMapLayers( layerIds );
4526 for (
const auto &layer :
layers )
4527 removeAuxiliaryLayer( layer );
4529 mProjectScope.reset();
4530 mLayerStore->removeMapLayers(
layers );
4537 removeAuxiliaryLayer( mLayerStore->mapLayer( layerId ) );
4538 mProjectScope.reset();
4539 mLayerStore->removeMapLayer( layerId );
4546 removeAuxiliaryLayer( layer );
4547 mProjectScope.reset();
4548 mLayerStore->removeMapLayer( layer );
4555 mProjectScope.reset();
4556 return mLayerStore->takeMapLayer( layer );
4563 return mMainAnnotationLayer;
4570 if ( mLayerStore->count() == 0 )
4573 ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
4574 mProjectScope.reset();
4575 mLayerStore->removeAllMapLayers();
4577 snapSingleBlocker.release();
4579 if ( !mBlockSnappingUpdates )
4587 const QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
4588 QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin();
4589 for ( ; it !=
layers.constEnd(); ++it )
4591 it.value()->reload();
4600 return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
4607 return mTransactionGroups.value( qMakePair( providerKey, connString ) );
4614 return &mEditBufferGroup;
4625 if ( mSettings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), QStringLiteral(
"NoAction" ),
QgsSettings::App ).toString() == QStringLiteral(
"UseProjectCrs" )
4626 || mSettings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), 0,
QgsSettings::App ).toString() == QLatin1String(
"2" ) )
4634 const QString layerDefaultCrs = mSettings.
value( QStringLiteral(
"/Projections/layerDefaultCrs" ),
geoEpsgCrsAuthId() ).toString();
4655bool QgsProject::saveAuxiliaryStorage(
const QString &filename )
4661 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4666 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
4674 if ( !mAuxiliaryStorage->exists( *
this ) && empty )
4678 else if ( !filename.isEmpty() )
4680 return mAuxiliaryStorage->saveAs( filename );
4684 return mAuxiliaryStorage->saveAs( *
this );
4697 return sPropertyDefinitions;
4710 return mAuxiliaryStorage.get();
4717 return mAuxiliaryStorage.get();
4724 const QDir archiveDir( mArchive->dir() );
4725 QTemporaryFile tmpFile( archiveDir.filePath(
"XXXXXX_" + nameTemplate ),
this );
4726 tmpFile.setAutoRemove(
false );
4728 mArchive->addFile( tmpFile.fileName() );
4729 return tmpFile.fileName();
4736 QStringList attachments;
4738 const QStringList files = mArchive->files();
4739 attachments.reserve( files.size() );
4740 for (
const QString &file : files )
4742 if ( QFileInfo( file ).baseName() !=
baseName )
4744 attachments.append( file );
4754 return mArchive->removeFile( path );
4761 return QStringLiteral(
"attachment:///%1" ).arg( QFileInfo( attachedFile ).
fileName() );
4768 if ( identifier.startsWith( QLatin1String(
"attachment:///" ) ) )
4770 return QDir( mArchive->dir() ).absoluteFilePath( identifier.mid( 14 ) );
4791 mProjectScope.reset();
4805 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4819 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
4820 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
4825 if (
layers.contains( it.value() ) )
4826 it.value()->setFlags( it.value()->flags() &
~QgsMapLayer::Removable );
4837 QStringList customColors;
4838 QStringList customColorLabels;
4840 QgsNamedColorList::const_iterator colorIt = colors.constBegin();
4841 for ( ; colorIt != colors.constEnd(); ++colorIt )
4844 const QString label = ( *colorIt ).second;
4845 customColors.append( color );
4846 customColorLabels.append( label );
4848 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ), customColors );
4849 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ), customColorLabels );
4850 mProjectScope.reset();
4858 if ( mBackgroundColor == color )
4861 mBackgroundColor = color;
4869 return mBackgroundColor;
4876 if ( mSelectionColor == color )
4879 mSelectionColor = color;
4887 return mSelectionColor;
4924 translationContext.setFileName( QStringLiteral(
"%1/%2.ts" ).arg(
absolutePath(),
baseName() ) );
4928 translationContext.writeTsFile( locale );
4931QString
QgsProject::translate(
const QString &context,
const QString &sourceText,
const char *disambiguation,
int n )
const
4940 QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
4942 if ( result.isEmpty() )
4956 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4961 if ( !( ( *it )->accept( visitor ) ) )
4970 if ( !mLayoutManager->accept( visitor ) )
4973 if ( !mAnnotationManager->accept( visitor ) )
4981 return mElevationShadingRenderer;
4984void QgsProject::loadProjectFlags(
const QDomDocument *doc )
4988 QDomElement element = doc->documentElement().firstChildElement( QStringLiteral(
"projectFlags" ) );
4989 Qgis::ProjectFlags
flags;
4990 if ( !element.isNull() )
4997 element = doc->documentElement().firstChildElement( QStringLiteral(
"evaluateDefaultValues" ) );
4998 if ( !element.isNull() )
5000 if ( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
5005 element = doc->documentElement().firstChildElement( QStringLiteral(
"trust" ) );
5006 if ( !element.isNull() )
5008 if ( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
5017GetNamedProjectColor::GetNamedProjectColor(
const QgsProject *project )
5024 QStringList colorStrings = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ) );
5025 const QStringList colorLabels = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ) );
5029 for ( QStringList::iterator it = colorStrings.begin();
5030 it != colorStrings.end(); ++it )
5034 if ( colorLabels.length() > colorIndex )
5036 label = colorLabels.at( colorIndex );
5039 mColors.insert( label.toLower(), color );
5044GetNamedProjectColor::GetNamedProjectColor(
const QHash<QString, QColor> &colors )
5052 const QString colorName = values.at( 0 ).toString().toLower();
5053 if ( mColors.contains( colorName ) )
5055 return QStringLiteral(
"%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
5063 return new GetNamedProjectColor( mColors );
5068GetSensorData::GetSensorData(
const QMap<QString, QgsAbstractSensor::SensorData> &sensorData )
5071 QStringLiteral(
"Sensors" ) )
5072 , mSensorData( sensorData )
5078 const QString sensorName = values.at( 0 ).toString();
5079 const int expiration = values.at( 1 ).toInt();
5080 const qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
5081 if ( mSensorData.contains( sensorName ) )
5083 if ( expiration <= 0 || ( timestamp - mSensorData[sensorName].lastTimestamp.toMSecsSinceEpoch() ) < expiration )
5085 return mSensorData[sensorName].lastValue;
5094 return new GetSensorData( mSensorData );
@ DontLoad3DViews
Skip loading 3D views (since QGIS 3.26)
@ DontStoreOriginalStyles
Skip the initial XML style storage for layers. Useful for minimising project load times in non-intera...
@ ForceReadOnlyLayers
Open layers in a read-only mode. (since QGIS 3.28)
@ TrustLayerMetadata
Trust layer metadata. Improves project read time. Do not use it if layers' extent is not fixed during...
@ DontLoadLayouts
Don't load print layouts. Improves project read time if layouts are not required, and allows projects...
@ DontResolveLayers
Don't resolve layer paths (i.e. don't load any layer content). Dramatically improves project read tim...
static QString version()
Version string.
DistanceUnit
Units of distance.
FilePathType
File path types.
TransactionMode
Transaction mode.
@ AutomaticGroups
Automatic transactional editing means that on supported datasources (postgres and geopackage database...
@ BufferedGroups
Buffered transactional editing means that all editable layers in the buffered transaction group are t...
@ Disabled
Edits are buffered locally and sent to the provider when toggling layer editing mode.
@ SquareMeters
Square meters.
@ Critical
Critical/error message.
@ Success
Used for reporting a successful operation.
AvoidIntersectionsMode
Flags which control how intersections of pre-existing feature are handled when digitizing new feature...
@ AvoidIntersectionsLayers
Overlap with features from a specified list of layers when digitizing new features not allowed.
@ AllowIntersections
Overlap with any feature allowed when digitizing new features.
ProjectFlag
Flags which control the behavior of QgsProjects.
@ RememberLayerEditStatusBetweenSessions
If set, then any layers set to be editable will be stored in the project and immediately made editabl...
@ EvaluateDefaultValuesOnProviderSide
If set, default values for fields will be evaluated on the provider side when features from the proje...
@ TrustStoredLayerStatistics
If set, then layer statistics (such as the layer extent) will be read from values stored in the proje...
LayerType
Types of layers that can be added to a map.
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Represents a map layer containing a set of georeferenced annotations, e.g.
void setTransformContext(const QgsCoordinateTransformContext &context) override
Sets the coordinate transform context to transformContext.
void reset()
Resets the annotation layer to a default state, and clears all items from it.
bool isEmpty() const
Returns true if the annotation layer is empty and contains no annotations.
Manages storage of a set of QgsAnnotation annotation objects.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
static QgsProjectStorageRegistry * projectStorageRegistry()
Returns registry of available project storage implementations.
static const QgsSettingsEntryString * settingsLocaleUserLocale
Settings entry locale user locale.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
void collectTranslatableObjects(QgsTranslationContext *translationContext)
Emits the signal to collect all the strings of .qgs to be included in ts file.
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
void requestForTranslatableObjects(QgsTranslationContext *translationContext)
Emitted when project strings which require translation are being collected for inclusion in a ....
static QString userFullName()
Returns the user's operating system login account full display name.
static QString userLoginName()
Returns the user's operating system login account name.
Class allowing to manage the zip/unzip actions.
void addFile(const QString &filename)
Add a new file to this archive.
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
This is an abstract base class for any elements of a drag and drop form.
QString name() const
Returns the name of this element.
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
bool save()
Commits changes and starts editing then.
Class providing some utility methods to manage auxiliary storage.
static QString extension()
Returns the extension used for auxiliary databases.
static bool deleteTable(const QgsDataSourceUri &uri)
Removes a table from the auxiliary storage.
Manages storage of a set of bookmarks.
bool readXml(const QDomElement &element, const QDomDocument &doc)
Reads the manager's state from a DOM element, restoring all bookmarks present in the XML document.
void clear()
Removes and deletes all bookmarks from the manager.
QDomElement writeXml(QDomDocument &doc) const
Returns a DOM element representing the state of the manager.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString toProj() const
Returns a Proj string representation of this CRS.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Qgis::DistanceUnit mapUnits
Contains information about the context in which a coordinate transform is executed.
void readSettings()
Reads the context's state from application settings.
void writeXml(QDomElement &element, const QgsReadWriteContext &context) const
Writes the context's state to a DOM element.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, QStringList &missingTransforms)
Reads the context's state from a DOM element.
Abstract base class for spatial data provider implementations.
@ ParallelThreadLoading
Skip credentials if the provided one are not valid, let the provider be invalid, avoiding to block th...
@ EvaluateDefaultValues
Evaluate default values on provider side when calling QgsVectorDataProvider::defaultValue( int index ...
Class for storing the component parts of a RDBMS data source URI (e.g.
This class can render elevation shading on an image with different methods (eye dome lighting,...
void writeXml(QDomElement &elem, const QgsReadWriteContext &context) const
Writes configuration on a DOM element.
void readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads configuration from a DOM element.
Single scope for storing variables and functions for use within a QgsExpressionContext.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
A abstract base class for defining QgsExpression functions.
An expression node for expression functions.
Class for parsing and evaluation of expressions (formerly called "search strings").
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
bool isEmpty() const
Checks whether the container is empty.
Stores global configuration for labeling engine.
Class used to work with layer dependencies stored in a XML project or layer definition file.
Layer tree group node serves as a container for layers and further groups.
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Calls resolveReferences() on child tree nodes.
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name.
QList< QgsLayerTreeGroup * > findGroups(bool recursive=false) const
Find group layer nodes.
QString name() const override
Returns the group's name.
QStringList findLayerIds() const
Find layer IDs used in all layer nodes.
void insertChildNodes(int index, const QList< QgsLayerTreeNode * > &nodes)
Insert existing nodes at specified position.
void readChildrenFromXml(QDomElement &element, const QgsReadWriteContext &context)
Read children from XML and append them to the group.
QgsLayerTreeGroup * clone() const override
Returns a clone of the group.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Layer tree node points to a map layer.
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Resolves reference to layer from stored layer ID (if it has not been resolved already)
This class is a base class for nodes in a layer tree.
QList< QgsLayerTreeNode * > abandonChildren()
Removes the childrens, disconnect all the forwarded and external signals and sets their parent to nul...
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file.
virtual void writeXml(QDomElement &parentElement, const QgsReadWriteContext &context)=0
Write layer tree to XML.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
Listens to the updates in map layer registry and does changes in layer tree.
void setEnabled(bool enabled)
static void replaceChildrenOfEmbeddedGroups(QgsLayerTreeGroup *group)
Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers.
static void storeOriginalLayersProperties(QgsLayerTreeGroup *group, const QDomDocument *doc)
Stores in a layer's originalXmlProperties the layer properties information.
static void updateEmbeddedGroupsProjectPath(QgsLayerTreeGroup *group, const QgsProject *project)
Updates an embedded group from a project.
static bool readOldLegend(QgsLayerTreeGroup *root, const QDomElement &legendElem)
Try to load layer tree from.
Namespace with helper functions for layer tree operations.
void readLayerOrderFromXml(const QDomElement &doc)
Load the layer order from an XML element.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
void clear()
Clear any information from this layer tree.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
QList< QgsMapLayer * > customLayerOrder() const
The order in which layers will be rendered on the canvas.
QgsLayerTree * clone() const override
Create a copy of the node. Returns new instance.
Manages storage of a set of layouts.
static void warning(const QString &msg)
Goes to qWarning.
static Qgis::LayerType typeFromString(const QString &string, bool &ok)
Returns the map layer type corresponding a string value.
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the store.
void layerWillBeRemoved(const QString &layerId)
Emitted when a layer is about to be removed from the store.
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the store.
void allLayersRemoved()
Emitted when all layers are removed, before layersWillBeRemoved() and layerWillBeRemoved() signals ar...
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the store.
void layerWasAdded(QgsMapLayer *layer)
Emitted when a layer was added to the store.
QgsMapLayer * mapLayer(const QString &id) const
Retrieve a pointer to a layer by layer id.
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the store.
Base class for all map layer types.
QString source() const
Returns the source for the layer.
QString providerType() const
Returns the provider type (provider key) for this layer.
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
void configChanged()
Emitted whenever the configuration is changed.
QgsCoordinateReferenceSystem crs
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QString originalXmlProperties() const
Returns the XML properties of the original layer as they were when the layer was first read from the ...
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
virtual bool isEditable() const
Returns true if the layer can be edited.
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores state in DOM node.
@ Identifiable
If the layer is identifiable using the identify map tool and as a WMS layer.
@ Removable
If the layer can be removed from the project. The layer will not be removable from the legend menu en...
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
@ FlagForceReadOnly
Force open as read only.
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags(), QgsDataProvider *preloadedProvider=nullptr)
Sets state from DOM document.
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
static QgsDataProvider::ReadFlags providerReadFlags(const QDomNode &layerNode, QgsMapLayer::ReadFlags layerReadFlags)
Returns provider read flag deduced from layer read flags layerReadFlags and a dom node layerNode that...
Container class that allows storage of map themes consisting of visible map layers and layer styles.
Manages storage of a set of views.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Resolves relative paths into absolute paths and vice versa.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Class allowing to manage the zip/unzip actions on project file.
QString projectFile() const
Returns the current .qgs project file or an empty string if there's none.
QString auxiliaryStorageFile() const
Returns the current .qgd auxiliary storage file or an empty string if there's none.
bool unzip(const QString &zipFilename) override
Clear the current content of this archive and unzip.
Interface for classes that handle missing layer files when reading project file.
virtual void handleBadLayers(const QList< QDomNode > &layers)
This method will be called whenever the project tries to load layers which cannot be accessed.
Contains settings and properties relating to how a QgsProject should display values such as map coord...
void reset()
Resets the settings to a default state.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Contains elevation properties for a QgsProject.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the property state from a DOM element.
void reset()
Resets the properties to a default state.
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns a DOM element representing the properties.
void resolveReferences(const QgsProject *project)
Resolves reference to layers from stored layer ID.
Contains settings and properties relating to how a QgsProject should interact with a GPS device.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
void reset()
Resets the settings to a default state.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
void resolveReferences(const QgsProject *project)
Resolves reference to layers from stored layer ID (if it has not been resolved already)
Project property key node.
QString name() const
The name of the property is used as identifier.
QgsProjectProperty * find(const QString &propertyName) const
Attempts to find a property with a matching sub-key name.
void removeKey(const QString &keyName)
Removes the specified key.
void dump(int tabs=0) const override
Dumps out the keys and values.
bool isEmpty() const
Returns true if this property contains no sub-keys.
virtual void clearKeys()
Deletes any sub-nodes from the property.
bool writeXml(const QString &nodeName, QDomElement &element, QDomDocument &document) override
Writes the property hierarchy to a specified DOM element.
void subkeyList(QStringList &entries) const
Returns any sub-keys contained by this property which themselves contain other keys.
void setName(const QString &name)
The name of the property is used as identifier.
QgsProjectPropertyKey * addKey(const QString &keyName)
Adds the specified property key as a sub-key.
QVariant value() const override
If this key has a value, it will be stored by its name in its properties.
QgsProjectPropertyValue * setValue(const QString &name, const QVariant &value)
Sets the value associated with this key.
void entryList(QStringList &entries) const
Returns any sub-keys contained by this property that do not contain other keys.
int count() const
Returns the number of sub-keys contained by this property.
bool readXml(const QDomNode &keyNode) override
Restores the property hierarchy from a specified DOM node.
An Abstract Base Class for QGIS project property hierarchys.
virtual bool isKey() const =0
Returns true if the property is a QgsProjectPropertyKey.
virtual bool isValue() const =0
Returns true if the property is a QgsProjectPropertyValue.
QgsProjectStorage * projectStorageFromUri(const QString &uri)
Returns storage implementation if the URI matches one. Returns nullptr otherwise (it is a normal file...
Abstract interface for project storage - to be implemented by various backends and registered in QgsP...
Contains settings and properties relating to how a QgsProject should handle styling.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
void setDefaultSymbol(Qgis::SymbolType symbolType, QgsSymbol *symbol)
Sets the project default symbol for a given type.
void reset()
Resets the settings to a default state.
void removeProjectStyle()
Removes and deletes the project style database.
void setRandomizeDefaultSymbolColor(bool randomized)
Sets whether the default symbol fill color is randomized.
void setDefaultColorRamp(QgsColorRamp *colorRamp)
Sets the project default color ramp.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Reads the settings's state from a DOM element.
void setDefaultSymbolOpacity(double opacity)
Sets the default symbol opacity.
Contains temporal settings and properties for the project, this may be used when animating maps or sh...
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
void reset()
Resets the settings to a default state.
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
A class to describe the version of a project.
QString text() const
Returns a string representation of the version.
int majorVersion() const
Returns the major version number.
Contains settings and properties relating to how a QgsProject should be displayed inside map canvas,...
bool useProjectScales() const
Returns true if project mapScales() are enabled.
void reset()
Resets the settings to a default state.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
void setMapScales(const QVector< double > &scales)
Sets the list of custom project map scales.
void setUseProjectScales(bool enabled)
Sets whether project mapScales() are enabled.
QVector< double > mapScales() const
Returns the list of custom project map scales.
void mapScalesChanged()
Emitted when the list of custom project map scales changes.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
bool isZipped() const
Returns true if the project comes from a zip archive, false otherwise.
bool removeAttachedFile(const QString &path)
Removes the attached file.
QgsRelationManager * relationManager
bool write()
Writes the project to its current associated file (see fileName() ).
QgsProject(QObject *parent=nullptr, Qgis::ProjectCapabilities capabilities=Qgis::ProjectCapability::ProjectStyles)
Create a new QgsProject.
void removeMapLayer(const QString &layerId)
Remove a layer from the registry by layer ID.
Q_DECL_DEPRECATED bool evaluateDefaultValues() const
Should default values be evaluated on provider side when requested and not when committed.
Qgis::DistanceUnit distanceUnits
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the registry.
void clear()
Clears the project, removing all settings and resetting it back to an empty, default state.
QString error() const
Returns error message from previous read/write.
Q_DECL_DEPRECATED void setUseProjectScales(bool enabled)
Sets whether project mapScales() are enabled.
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
Reads an integer from the specified scope and key.
Q_DECL_DEPRECATED void setNonIdentifiableLayers(const QList< QgsMapLayer * > &layers)
Set a list of layers which should not be taken into account on map identification.
QList< QgsMapLayer * > addMapLayers(const QList< QgsMapLayer * > &mapLayers, bool addToLegend=true, bool takeOwnership=true)
Add a list of layers to the map of loaded layers.
Qgis::ProjectFlags flags() const
Returns the project's flags, which dictate the behavior of the project.
Q_DECL_DEPRECATED QFileInfo fileInfo() const
Returns QFileInfo object for the project's associated file.
QString presetHomePath() const
Returns any manual project home path setting, or an empty string if not set.
void setBackgroundColor(const QColor &color)
Sets the default background color used by default map canvases.
void setCrs(const QgsCoordinateReferenceSystem &crs, bool adjustEllipsoid=false)
Sets the project's native coordinate reference system.
QString title() const
Returns the project's title.
bool commitChanges(QStringList &commitErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
void mapThemeCollectionChanged()
Emitted when the map theme collection changes.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Qgis::FilePathType filePathStorage() const
Returns the type of paths used when storing file paths in a QGS/QGZ project file.
QString createAttachedFile(const QString &nameTemplate)
Attaches a file to the project.
Q_DECL_DEPRECATED void mapScalesChanged()
Emitted when the list of custom project map scales changes.
void readVersionMismatchOccurred(const QString &fileVersion)
Emitted when a project is read and the version of QGIS used to save the project differs from the curr...
void fileNameChanged()
Emitted when the file name of the project changes.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
void writeMapLayer(QgsMapLayer *mapLayer, QDomElement &layerElem, QDomDocument &doc)
Emitted when a layer is being saved.
const QgsSensorManager * sensorManager() const
Returns the project's sensor manager, which manages sensors within the project.
void setSnappingConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration for this project.
void areaUnitsChanged()
Emitted when the default area units changes.
QgsPropertyCollection dataDefinedServerProperties() const
Returns the data defined properties used for overrides in user defined server parameters.
Q_DECL_DEPRECATED void nonIdentifiableLayersChanged(QStringList nonIdentifiableLayers)
Emitted when the list of layer which are excluded from map identification changes.
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QString attachmentIdentifier(const QString &attachedFile) const
Returns an identifier for an attachment file path An attachment identifier is a string which does not...
QgsVectorLayerEditBufferGroup * editBufferGroup()
Returns the edit buffer group.
void setSelectionColor(const QColor &color)
Sets the color used to highlight selected features.
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Stops a current editing operation on vectorLayer and discards any uncommitted edits.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
void setBadLayerHandler(QgsProjectBadLayerHandler *handler)
Change handler for missing layers.
Q_DECL_DEPRECATED void setEvaluateDefaultValues(bool evaluateDefaultValues)
Defines if default values should be evaluated on provider side when requested and not when committed.