78#include <QApplication>
83#include <QTemporaryFile>
86#include <QStandardPaths>
88#include <QRegularExpression>
110 QStringList keyTokens = QStringList( scope );
111#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
112 keyTokens += key.split(
'/', QString::SkipEmptyParts );
114 keyTokens += key.split(
'/', Qt::SkipEmptyParts );
118 keyTokens.push_front( QStringLiteral(
"properties" ) );
121 for (
int i = 0; i < keyTokens.size(); ++i )
123 const QString keyToken = keyTokens.at( i );
127 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}])" ) );
128 if ( keyToken.contains( sInvalidRegexp ) )
130 const QString errorString = QObject::tr(
"Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
158 while ( !keySequence.isEmpty() )
162 if ( keySequence.first() == currentProperty->
name() )
165 keySequence.pop_front();
167 if ( 1 == keySequence.count() )
170 return currentProperty->
find( keySequence.front() );
172 else if ( keySequence.isEmpty() )
177 return currentProperty;
179 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
181 if ( nextProperty->
isKey() )
185 else if ( nextProperty->
isValue() && 1 == keySequence.count() )
191 return currentProperty;
229 const QVariant &value,
230 bool &propertiesModified )
239 propertiesModified =
false;
240 while ( ! keySequence.isEmpty() )
244 if ( keySequence.first() == currentProperty->
name() )
247 keySequence.pop_front();
251 if ( 1 == keySequence.count() )
254 if ( !property || property->value() != value )
256 currentProperty->
setValue( keySequence.front(), value );
257 propertiesModified =
true;
260 return currentProperty;
264 else if ( keySequence.isEmpty() )
266 if ( currentProperty->
value() != value )
269 propertiesModified =
true;
272 return currentProperty;
274 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
278 if ( currentProperty )
289 if ( ( newPropertyKey = currentProperty->
addKey( keySequence.first() ) ) )
291 currentProperty = newPropertyKey;
323 while ( ! keySequence.isEmpty() )
327 if ( keySequence.first() == currentProperty->
name() )
330 keySequence.pop_front();
334 if ( 1 == keySequence.count() )
336 currentProperty->
removeKey( keySequence.front() );
341 else if ( keySequence.isEmpty() )
343 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
345 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
347 previousQgsPropertyKey = currentProperty;
350 if ( currentProperty )
374 , mCapabilities( capabilities )
377 , mSnappingConfig( this )
395 mProperties.
setName( QStringLiteral(
"properties" ) );
398 mMainAnnotationLayer->setParent(
this );
412 this, [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
414 this, [ = ](
const QList<QgsMapLayer *> &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
416 this, [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
418 this, [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
420 [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
422 [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
424 [ = ]() { mProjectScope.reset(); emit removeAll(); } );
426 [ = ](
const QList< QgsMapLayer * > &
layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
428 [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
436 [ = ](
const QList<QgsMapLayer *> &
layers )
438 for ( const auto &layer : layers )
440 disconnect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
445 [ = ](
const QList<QgsMapLayer *> &layers )
447 for ( const auto &layer : layers )
449 connect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
458 mStyleSettings->combinedStyleModel()->addDefaultStyle();
464 mIsBeingDeleted =
true;
467 delete mBadLayerHandler;
468 delete mRelationManager;
469 delete mLayerTreeRegistryBridge;
471 if (
this == sProject )
502 mProjectScope.reset();
513 return mMetadata.
title();
522 if ( oldEvaluateDefaultValues != newEvaluateDefaultValues )
525 for (
auto layerIt =
layers.constBegin(); layerIt !=
layers.constEnd(); ++layerIt )
527 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
536 if ( oldTrustLayerMetadata != newTrustLayerMetadata )
539 for (
auto layerIt =
layers.constBegin(); layerIt !=
layers.constEnd(); ++layerIt )
541 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
543 vl->setReadExtentFromXml( newTrustLayerMetadata );
548 if ( mFlags !=
flags )
559 Qgis::ProjectFlags newFlags = mFlags;
563 newFlags &= ~(
static_cast< int >( flag ) );
578 return mSaveUserFull;
585 return mSaveDateTime;
606 if ( dirty && mDirtyBlockCount > 0 )
612 if ( mDirty == dirty )
623 if ( path == mHomePath )
627 mCachedHomePath.clear();
628 mProjectScope.reset();
639 const QList<QgsAttributeEditorElement *> elements = parent->
children();
643 if ( element->type() == Qgis::AttributeEditorType::Container )
647 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:formcontainers" ).arg( layerId ), container->
name() );
649 if ( !container->
children().empty() )
664 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1" ).arg( layer->layerId() ), layer->name() );
681 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fieldaliases" ).arg( vlayer->
id() ), fieldName );
696 const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->
findGroups();
699 translationContext->
registerTranslation( QStringLiteral(
"project:layergroups" ), groupLayer->name() );
703 const QList<QgsRelation> &relations = mRelationManager->
relations().values();
706 translationContext->
registerTranslation( QStringLiteral(
"project:relations" ), relation.name() );
714 mDataDefinedServerProperties = properties;
721 return mDataDefinedServerProperties;
728 switch ( mTransactionMode )
749 switch ( mTransactionMode )
756 commitErrors.append( tr(
"Trying to commit changes without a layer specified. This only works if the transaction mode is buffered" ) );
765 return mEditBufferGroup.
commitChanges( commitErrors, stopEditing );
775 switch ( mTransactionMode )
782 rollbackErrors.append( tr(
"Trying to roll back changes without a layer specified. This only works if the transaction mode is buffered" ) );
785 bool success = vectorLayer->
rollBack( stopEditing );
791 return mEditBufferGroup.
rollBack( rollbackErrors, stopEditing );
801 if ( name == mFile.fileName() )
804 const QString oldHomePath =
homePath();
806 mFile.setFileName( name );
807 mCachedHomePath.clear();
808 mProjectScope.reset();
812 const QString newHomePath =
homePath();
813 if ( newHomePath != oldHomePath )
824 return mFile.fileName();
831 mOriginalPath = path;
838 return mOriginalPath;
845 return QFileInfo( mFile );
863 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
868 return QFileInfo( mFile.fileName() ).lastModified();
879 if ( mFile.fileName().isEmpty() )
882 return QFileInfo( mFile.fileName() ).absolutePath();
893 if ( mFile.fileName().isEmpty() )
896 return QFileInfo( mFile.fileName() ).absoluteFilePath();
907 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
912 return QFileInfo( mFile.fileName() ).completeBaseName();
920 const bool absolutePaths =
readBoolEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
931 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
true );
934 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
954 writeEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ),
crs.
isValid() ? 1 : 0 );
955 mProjectScope.reset();
966 if ( adjustEllipsoid )
975 if ( !
crs().isValid() )
978 return readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ),
geoNone() );
985 if (
ellipsoid ==
readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ) ) )
988 mProjectScope.reset();
998 return mTransformContext;
1005 if ( context == mTransformContext )
1008 mTransformContext = context;
1009 mProjectScope.reset();
1012 for (
auto &layer : mLayerStore.get()->mapLayers() )
1014 layer->setTransformContext( context );
1023 ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
1025 mProjectScope.reset();
1026 mFile.setFileName( QString() );
1029 mSaveUserFull.clear();
1030 mSaveDateTime = QDateTime();
1033 mCachedHomePath.clear();
1035 mFlags = Qgis::ProjectFlags();
1037 mCustomVariables.clear();
1041 if ( !mSettings.
value( QStringLiteral(
"projects/anonymize_new_projects" ),
false,
QgsSettings::Core ).toBool() )
1060 mEmbeddedLayers.clear();
1061 mRelationManager->
clear();
1062 mAnnotationManager->clear();
1063 mLayoutManager->clear();
1064 m3DViewsManager->clear();
1065 mBookmarkManager->
clear();
1066 mSensorManager->
clear();
1067 mViewSettings->
reset();
1068 mTimeSettings->
reset();
1069 mElevationProperties->
reset();
1070 mDisplaySettings->
reset();
1071 mGpsSettings->
reset();
1072 mSnappingConfig.
reset();
1080 mLabelingEngineSettings->clear();
1086 mStyleSettings->
reset();
1090 if ( !mIsBeingDeleted )
1098 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/Automatic" ),
true );
1099 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/DecimalPlaces" ), 2 );
1101 const bool defaultRelativePaths = mSettings.
value( QStringLiteral(
"/qgis/defaultProjectPathsRelative" ),
true ).toBool();
1104 int red = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_red" ), 255 ).toInt();
1105 int green = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_green" ), 255 ).toInt();
1106 int blue = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_blue" ), 255 ).toInt();
1109 red = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_red" ), 255 ).toInt();
1110 green = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_green" ), 255 ).toInt();
1111 blue = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_blue" ), 0 ).toInt();
1112 const int alpha = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_alpha" ), 255 ).toInt();
1118 mRootGroup->
clear();
1119 if ( mMainAnnotationLayer )
1120 mMainAnnotationLayer->
reset();
1122 snapSingleBlocker.release();
1124 if ( !mBlockSnappingUpdates )
1136 topQgsPropertyKey.
dump();
1169 const QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
1171 if ( propertiesElem.isNull() )
1176 const QDomNodeList scopes = propertiesElem.childNodes();
1178 if ( propertiesElem.firstChild().isNull() )
1180 QgsDebugError( QStringLiteral(
"empty ``properties'' XML tag ... bailing" ) );
1184 if ( ! project_properties.
readXml( propertiesElem ) )
1186 QgsDebugError( QStringLiteral(
"Project_properties.readXml() failed" ) );
1200 const QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral(
"dataDefinedServerProperties" ) );
1201 if ( !ddElem.isNull() )
1203 if ( !ddServerProperties.
readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
1205 QgsDebugError( QStringLiteral(
"dataDefinedServerProperties.readXml() failed" ) );
1208 return ddServerProperties;
1215static void _getTitle(
const QDomDocument &doc, QString &title )
1217 const QDomElement titleNode = doc.documentElement().firstChildElement( QStringLiteral(
"title" ) );
1221 if ( titleNode.isNull() )
1227 if ( !titleNode.hasChildNodes() )
1233 const QDomNode titleTextNode = titleNode.firstChild();
1235 if ( !titleTextNode.isText() )
1241 const QDomText titleText = titleTextNode.toText();
1243 title = titleText.data();
1247static void readProjectFileMetadata(
const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
1249 const QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1253 QgsDebugError( QStringLiteral(
"unable to find qgis element" ) );
1257 const QDomNode qgisNode = nl.item( 0 );
1259 const QDomElement qgisElement = qgisNode.toElement();
1260 lastUser = qgisElement.attribute( QStringLiteral(
"saveUser" ), QString() );
1261 lastUserFull = qgisElement.attribute( QStringLiteral(
"saveUserFull" ), QString() );
1262 lastSaveDateTime = QDateTime::fromString( qgisElement.attribute( QStringLiteral(
"saveDateTime" ), QString() ), Qt::ISODate );
1267 const QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1271 QgsDebugError( QStringLiteral(
" unable to find qgis element in project file" ) );
1275 const QDomNode qgisNode = nl.item( 0 );
1277 const QDomElement qgisElement = qgisNode.toElement();
1278 QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral(
"version" ) ) );
1279 return projectVersion;
1286 return mSnappingConfig;
1305 if ( mAvoidIntersectionsMode == mode )
1308 mAvoidIntersectionsMode = mode;
1312static QgsMapLayer::ReadFlags projectFlagsToLayerReadFlags( Qgis::ProjectReadFlags projectReadFlags, Qgis::ProjectFlags projectFlags )
1314 QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1315 if ( projectReadFlags & Qgis::ProjectReadFlag::DontResolveLayers )
1327void QgsProject::preloadProviders(
const QVector<QDomNode> ¶llelLayerNodes,
1329 QMap<QString, QgsDataProvider *> &loadedProviders,
1330 QgsMapLayer::ReadFlags layerReadFlags,
1331 int totalProviderCount )
1334 QVector<QgsRunnableProviderCreator *> runnables;
1335 QThreadPool threadPool;
1340 int validLayerCount = 0;
1342 for (
const QDomNode &node : parallelLayerNodes )
1344 const QDomElement layerElement = node.toElement();
1345 QString layerId = layerElement.namedItem( QStringLiteral(
"id" ) ).toElement().text();
1346 QString provider = layerElement.namedItem( QStringLiteral(
"provider" ) ).toElement().text();
1347 QString dataSource = layerElement.namedItem( QStringLiteral(
"datasource" ) ).toElement().text();
1358 runnables.append( run );
1365 emit
layerLoaded( validLayerCount, totalProviderCount );
1367 if ( i == parallelLayerNodes.count() )
1370 threadPool.start( run );
1372 if ( !parallelLayerNodes.isEmpty() )
1378 std::unique_ptr<QgsDataProvider> provider( run->
dataProvider() );
1379 if ( provider->isValid() )
1380 loadedProviders.insert( run->
layerId(), provider.release() );
1383 qDeleteAll( runnables );
1386bool QgsProject::_getMapLayers(
const QDomDocument &doc, QList<QDomNode> &brokenNodes, Qgis::ProjectReadFlags flags )
1393 QDomElement layerElement = doc.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) ).firstChildElement( QStringLiteral(
"maplayer" ) );
1397 if ( layerElement.isNull() )
1407 bool returnStatus =
true;
1410 while ( ! layerElement.isNull() )
1413 layerElement = layerElement.nextSiblingElement( QStringLiteral(
"maplayer" ) );
1419 if ( depSorter.hasCycle() )
1423 if ( depSorter.hasMissingDependency() )
1424 returnStatus =
false;
1428 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1429 const int totalLayerCount = sortedLayerNodes.count();
1431 QVector<QDomNode> parallelLoading;
1432 QMap<QString, QgsDataProvider *> loadedProviders;
1436 profile.switchTask( tr(
"Load providers in parallel" ) );
1437 for (
const QDomNode &node : sortedLayerNodes )
1439 const QDomElement element = node.toElement();
1440 if ( element.attribute( QStringLiteral(
"embedded" ) ) != QLatin1String(
"1" ) )
1442 const QString layerId = node.namedItem( QStringLiteral(
"id" ) ).toElement().text();
1443 if ( !depSorter.isLayerDependent( layerId ) )
1445 const QDomNode mnl = element.namedItem( QStringLiteral(
"provider" ) );
1446 const QDomElement mne = mnl.toElement();
1447 const QString provider = mne.text();
1451 parallelLoading.append( node );
1460 if ( !parallelLoading.isEmpty() )
1461 preloadProviders( parallelLoading, context, loadedProviders, projectFlagsToLayerReadFlags(
flags, mFlags ), sortedLayerNodes.count() );
1464 int i = loadedProviders.count();
1465 for (
const QDomNode &node : std::as_const( sortedLayerNodes ) )
1467 const QDomElement element = node.toElement();
1468 const QString name =
translate( QStringLiteral(
"project:layers:%1" ).arg( node.namedItem( QStringLiteral(
"id" ) ).toElement().text() ), node.namedItem( QStringLiteral(
"layername" ) ).toElement().text() );
1469 if ( !name.isNull() )
1470 emit
loadingLayer( tr(
"Loading layer %1" ).arg( name ) );
1472 profile.switchTask( name );
1473 if ( element.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
1475 createEmbeddedLayer( element.attribute( QStringLiteral(
"id" ) ),
readPath( element.attribute( QStringLiteral(
"project" ) ) ), brokenNodes,
true,
flags );
1483 QString layerId = element.namedItem( QStringLiteral(
"id" ) ).toElement().text();
1485 if ( !addLayer( element, brokenNodes, context,
flags, loadedProviders.take( layerId ) ) )
1487 returnStatus =
false;
1490 if ( !messages.isEmpty() )
1499 return returnStatus;
1502bool QgsProject::addLayer(
const QDomElement &layerElem,
1503 QList<QDomNode> &brokenNodes,
1505 Qgis::ProjectReadFlags flags,
1510 const QString type = layerElem.attribute( QStringLiteral(
"type" ) );
1512 std::unique_ptr<QgsMapLayer>
mapLayer;
1520 QgsDebugError( QStringLiteral(
"Unknown layer type \"%1\"" ).arg( type ) );
1524 switch ( layerType )
1526 case Qgis::LayerType::Vector:
1527 mapLayer = std::make_unique<QgsVectorLayer>();
1530 case Qgis::LayerType::Raster:
1531 mapLayer = std::make_unique<QgsRasterLayer>();
1534 case Qgis::LayerType::Mesh:
1535 mapLayer = std::make_unique<QgsMeshLayer>();
1538 case Qgis::LayerType::VectorTile:
1539 mapLayer = std::make_unique<QgsVectorTileLayer>();
1542 case Qgis::LayerType::PointCloud:
1543 mapLayer = std::make_unique<QgsPointCloudLayer>();
1546 case Qgis::LayerType::Plugin:
1548 const QString
typeName = layerElem.attribute( QStringLiteral(
"name" ) );
1553 case Qgis::LayerType::Annotation:
1556 mapLayer = std::make_unique<QgsAnnotationLayer>( QString(), options );
1560 case Qgis::LayerType::Group:
1563 mapLayer = std::make_unique<QgsGroupLayer>( QString(), options );
1570 QgsDebugError( QStringLiteral(
"Unable to create layer" ) );
1578 const QString layerId { layerElem.namedItem( QStringLiteral(
"id" ) ).toElement().text() };
1579 Q_ASSERT( ! layerId.isEmpty() );
1583 QgsMapLayer::ReadFlags layerFlags = projectFlagsToLayerReadFlags(
flags, mFlags );
1585 profile.switchTask( tr(
"Load layer source" ) );
1592 if ( vl->dataProvider() )
1599 profile.switchTask( tr(
"Add layer to project" ) );
1600 QList<QgsMapLayer *> newLayers;
1602 if ( layerIsValid ||
flags & Qgis::ProjectReadFlag::DontResolveLayers )
1612 vLayer->joinBuffer()->resolveReferences(
this );
1621 brokenNodes.push_back( layerElem );
1624 const bool wasEditable = layerElem.attribute( QStringLiteral(
"editable" ), QStringLiteral(
"0" ) ).toInt();
1636 if ( ! layerWasStored )
1641 return layerIsValid;
1648 mFile.setFileName( filename );
1649 mCachedHomePath.clear();
1650 mProjectScope.reset();
1659 const QString filename = mFile.fileName();
1664 QTemporaryFile inDevice;
1665 if ( !inDevice.open() )
1667 setError( tr(
"Unable to open %1" ).arg( inDevice.fileName() ) );
1673 if ( !storage->readProject( filename, &inDevice, context ) )
1675 QString err = tr(
"Unable to open %1" ).arg( filename );
1676 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
1677 if ( !messages.isEmpty() )
1678 err += QStringLiteral(
"\n\n" ) + messages.last().message();
1682 returnValue = unzip( inDevice.fileName(),
flags );
1688 returnValue = unzip( mFile.fileName(),
flags );
1693 const QFileInfo finfo( mFile.fileName() );
1694 const QString attachmentsZip = finfo.absoluteDir().absoluteFilePath( QStringLiteral(
"%1_attachments.zip" ).arg( finfo.completeBaseName() ) );
1695 if ( QFile( attachmentsZip ).exists() )
1697 std::unique_ptr<QgsArchive> archive(
new QgsArchive() );
1698 if ( archive->unzip( attachmentsZip ) )
1700 mArchive = std::move( archive );
1703 returnValue = readProjectFile( mFile.fileName(),
flags );
1709 mFile.setFileName( filename );
1710 mCachedHomePath.clear();
1711 mProjectScope.reset();
1716 mTranslator.reset(
nullptr );
1723bool QgsProject::readProjectFile(
const QString &filename, Qgis::ProjectReadFlags flags )
1728 ScopedIntIncrementor snapSignalBlock( &mBlockSnappingUpdates );
1730 QFile projectFile( filename );
1738 if ( QFile( QStringLiteral(
"%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1740 mTranslator.reset(
new QTranslator() );
1741 ( void )mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1744 profile.switchTask( tr(
"Reading project file" ) );
1745 std::unique_ptr<QDomDocument> doc(
new QDomDocument( QStringLiteral(
"qgis" ) ) );
1747 if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1749 projectFile.close();
1751 setError( tr(
"Unable to open %1" ).arg( projectFile.fileName() ) );
1760 if ( !doc->setContent( &projectFile, &errorMsg, &line, &column ) )
1762 const QString errorString = tr(
"Project file read error in file %1: %2 at line %3 column %4" )
1763 .arg( projectFile.fileName(), errorMsg ).arg( line ).arg( column );
1767 projectFile.close();
1769 setError( errorString );
1774 projectFile.close();
1782 profile.switchTask( tr(
"Updating project file" ) );
1783 if ( thisVersion > fileVersion )
1785 const bool isOlderMajorVersion = fileVersion.
majorVersion() < thisVersion.majorVersion();
1787 if ( isOlderMajorVersion )
1790 "version of qgis (saved in " + fileVersion.
text() +
1792 "). Problems may occur." );
1803 projectFile.updateRevision( thisVersion );
1805 else if ( fileVersion > thisVersion )
1808 "version of qgis (saved in " + fileVersion.
text() +
1810 "). Problems may occur." );
1816 profile.switchTask( tr(
"Creating auxiliary storage" ) );
1817 const QString
fileName = mFile.fileName();
1818 std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
1819 std::unique_ptr<QgsArchive> archive = std::move( mArchive );
1821 mAuxiliaryStorage = std::move( aStorage );
1822 mArchive = std::move( archive );
1824 mCachedHomePath.clear();
1825 mProjectScope.reset();
1826 mSaveVersion = fileVersion;
1829 profile.switchTask( tr(
"Reading properties" ) );
1838 dump_( mProperties );
1843 _getTitle( *doc, oldTitle );
1845 readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1847 const QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral(
"homePath" ) );
1848 if ( homePathNl.count() > 0 )
1850 const QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1851 const QString
homePath = homePathElement.attribute( QStringLiteral(
"path" ) );
1861 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), 255 ),
1862 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), 255 ) );
1865 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), 255 ),
1866 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), 255 ),
1867 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), 255 ) );
1871 const QString distanceUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), QString() );
1872 if ( !distanceUnitString.isEmpty() )
1875 const QString areaUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), QString() );
1876 if ( !areaUnitString.isEmpty() )
1885 if (
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ), 0 ) )
1888 const QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral(
"projectCrs" ) );
1889 if ( !srsNode.isNull() )
1891 projectCrs.
readXml( srsNode );
1896 const QString projCrsString =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSProj4String" ) );
1897 const long currentCRS =
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSID" ), -1 );
1898 const QString authid =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCrs" ) );
1901 const bool isUserAuthId = authid.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive );
1902 if ( !authid.isEmpty() && !isUserAuthId )
1906 if ( !projectCrs.
isValid() && currentCRS >= 0 )
1912 if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.
isValid() || projectCrs.
toProj() != projCrsString ) )
1926 QStringList datumErrors;
1927 if ( !mTransformContext.
readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
1934 const QDomNode elevationShadingNode = doc->documentElement().namedItem( QStringLiteral(
"elevation-shading-renderer" ) );
1935 if ( !elevationShadingNode.isNull() )
1937 mElevationShadingRenderer.
readXml( elevationShadingNode.toElement(), context );
1944 const QStringList variableNames =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ) );
1945 const QStringList variableValues =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ) );
1947 mCustomVariables.clear();
1948 if ( variableNames.length() == variableValues.length() )
1950 for (
int i = 0; i < variableNames.length(); ++i )
1952 mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
1957 QgsMessageLog::logMessage( tr(
"Project Variables Invalid" ), tr(
"The project contains invalid variable settings." ) );
1960 QDomElement element = doc->documentElement().firstChildElement( QStringLiteral(
"projectMetadata" ) );
1962 if ( !element.isNull() )
1971 if ( mMetadata.
title().isEmpty() && !oldTitle.isEmpty() )
1979 element = doc->documentElement().firstChildElement( QStringLiteral(
"transaction" ) );
1980 if ( !element.isNull() )
1987 element = doc->documentElement().firstChildElement( QStringLiteral(
"autotransaction" ) );
1988 if ( ! element.isNull() )
1990 mTransactionMode =
static_cast<Qgis::TransactionMode>( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() );
1995 profile.switchTask( tr(
"Loading layer tree" ) );
1998 QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
1999 if ( !layerTreeElem.isNull() )
2011 mLayerTreeRegistryBridge->
setEnabled(
false );
2014 profile.switchTask( tr(
"Reading map layers" ) );
2016 loadProjectFlags( doc.get() );
2018 QList<QDomNode> brokenNodes;
2019 const bool clean = _getMapLayers( *doc, brokenNodes,
flags );
2022 if ( !clean && !(
flags & Qgis::ProjectReadFlag::DontResolveLayers ) )
2024 QgsDebugError( QStringLiteral(
"Unable to get map layers from project file." ) );
2026 if ( !brokenNodes.isEmpty() )
2028 QgsDebugError(
"there are " + QString::number( brokenNodes.size() ) +
" broken layers" );
2036 mMainAnnotationLayer->
readLayerXml( doc->documentElement().firstChildElement( QStringLiteral(
"main-annotation-layer" ) ), context );
2040 profile.switchTask( tr(
"Loading embedded layers" ) );
2041 loadEmbeddedNodes( mRootGroup,
flags );
2045 profile.switchTask( tr(
"Resolving layer references" ) );
2046 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
2047 for ( QMap<QString, QgsMapLayer *>::iterator it =
layers.begin(); it !=
layers.end(); ++it )
2049 it.value()->resolveReferences(
this );
2052 mLayerTreeRegistryBridge->
setEnabled(
true );
2055 profile.switchTask( tr(
"Resolving references" ) );
2066 if ( !layerTreeElem.isNull() )
2072 const QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-canvas" ) );
2073 if ( !layerTreeCanvasElem.isNull( ) )
2081 const QStringList requiredLayerIds =
readListEntry( QStringLiteral(
"RequiredLayers" ), QStringLiteral(
"Layers" ) );
2082 for (
const QString &layerId : requiredLayerIds )
2089 const QStringList disabledLayerIds =
readListEntry( QStringLiteral(
"Identify" ), QStringLiteral(
"/disabledLayers" ) );
2090 for (
const QString &layerId : disabledLayerIds )
2103 QString styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Marker" ) );
2104 if ( !styleName.isEmpty() )
2109 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Line" ) );
2110 if ( !styleName.isEmpty() )
2115 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Fill" ) );
2116 if ( !styleName.isEmpty() )
2121 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/ColorRamp" ) );
2122 if ( !styleName.isEmpty() )
2132 double opacity = 1.0;
2135 double alpha =
readDoubleEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/AlphaInt" ), 255, &ok );
2137 opacity = alpha / 255.0;
2138 double newOpacity =
readDoubleEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Opacity" ), 1.0, &ok );
2140 opacity = newOpacity;
2144 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Marker" ) );
2145 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Line" ) );
2146 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Fill" ) );
2147 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/ColorRamp" ) );
2148 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/RandomColors" ) );
2149 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/AlphaInt" ) );
2150 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Opacity" ) );
2156 if ( !(
flags & Qgis::ProjectReadFlag::DontStoreOriginalStyles ) )
2158 profile.switchTask( tr(
"Storing original layer properties" ) );
2164 profile.switchTask( tr(
"Loading map themes" ) );
2167 mMapThemeCollection->readXml( *doc );
2169 profile.switchTask( tr(
"Loading label settings" ) );
2170 mLabelingEngineSettings->readSettingsFromProject(
this );
2173 profile.switchTask( tr(
"Loading annotations" ) );
2174 mAnnotationManager->readXml( doc->documentElement(), context );
2175 if ( !(
flags & Qgis::ProjectReadFlag::DontLoadLayouts ) )
2177 profile.switchTask( tr(
"Loading layouts" ) );
2178 mLayoutManager->readXml( doc->documentElement(), *doc );
2181 if ( !(
flags & Qgis::ProjectReadFlag::DontLoad3DViews ) )
2183 profile.switchTask( tr(
"Loading 3D Views" ) );
2184 m3DViewsManager->readXml( doc->documentElement(), *doc );
2187 profile.switchTask( tr(
"Loading bookmarks" ) );
2188 mBookmarkManager->
readXml( doc->documentElement(), *doc );
2190 profile.switchTask( tr(
"Loading sensors" ) );
2191 mSensorManager->
readXml( doc->documentElement(), *doc );
2194 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
2195 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
2197 it.value()->setDependencies( it.value()->dependencies() );
2200 profile.switchTask( tr(
"Loading snapping settings" ) );
2204 profile.switchTask( tr(
"Loading view settings" ) );
2207 const QStringList scales =
readListEntry( QStringLiteral(
"Scales" ), QStringLiteral(
"/ScalesList" ) );
2208 QVector<double> res;
2209 for (
const QString &scale : scales )
2211 const QStringList parts = scale.split(
':' );
2212 if ( parts.size() != 2 )
2216 const double denominator = QLocale().toDouble( parts[1], &ok );
2223 const QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectViewSettings" ) );
2224 if ( !viewSettingsElement.isNull() )
2225 mViewSettings->
readXml( viewSettingsElement, context );
2228 profile.switchTask( tr(
"Loading style properties" ) );
2229 const QDomElement styleSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectStyleSettings" ) );
2230 if ( !styleSettingsElement.isNull() )
2231 mStyleSettings->
readXml( styleSettingsElement, context,
flags );
2234 profile.switchTask( tr(
"Loading temporal settings" ) );
2235 const QDomElement timeSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectTimeSettings" ) );
2236 if ( !timeSettingsElement.isNull() )
2237 mTimeSettings->
readXml( timeSettingsElement, context );
2240 profile.switchTask( tr(
"Loading elevation properties" ) );
2241 const QDomElement elevationPropertiesElement = doc->documentElement().firstChildElement( QStringLiteral(
"ElevationProperties" ) );
2242 if ( !elevationPropertiesElement.isNull() )
2243 mElevationProperties->
readXml( elevationPropertiesElement, context );
2246 profile.switchTask( tr(
"Loading display settings" ) );
2248 const QDomElement displaySettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectDisplaySettings" ) );
2249 if ( !displaySettingsElement.isNull() )
2250 mDisplaySettings->
readXml( displaySettingsElement, context );
2253 profile.switchTask( tr(
"Loading GPS settings" ) );
2255 const QDomElement gpsSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectGpsSettings" ) );
2256 if ( !gpsSettingsElement.isNull() )
2257 mGpsSettings->
readXml( gpsSettingsElement, context );
2261 profile.switchTask( tr(
"Updating variables" ) );
2263 profile.switchTask( tr(
"Updating CRS" ) );
2268 profile.switchTask( tr(
"Reading external settings" ) );
2272 profile.switchTask( tr(
"Updating interface" ) );
2274 snapSignalBlock.release();
2275 if ( !mBlockSnappingUpdates )
2286 QgsDebugMsgLevel( QStringLiteral(
"Project save user: %1" ).arg( mSaveUser ), 2 );
2287 QgsDebugMsgLevel( QStringLiteral(
"Project save user: %1" ).arg( mSaveUserFull ), 2 );
2296 const QString newFileName( QStringLiteral(
"%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
2302 QgsMessageLog::logMessage( tr(
"Translated project saved with locale prefix %1" ).arg( newFileName ), QObject::tr(
"Project translation" ), Qgis::MessageLevel::Success );
2306 QgsMessageLog::logMessage( tr(
"Error saving translated project with locale prefix %1" ).arg( newFileName ), QObject::tr(
"Project translation" ), Qgis::MessageLevel::Critical );
2311 const QMap<QString, QgsMapLayer *> loadedLayers =
mapLayers();
2312 for (
auto it = loadedLayers.constBegin(); it != loadedLayers.constEnd(); ++it )
2314 if ( it.value()->isValid() && it.value()->customProperty( QStringLiteral(
"_layer_was_editable" ) ).toBool() )
2316 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( it.value() ) )
2318 it.value()->removeCustomProperty( QStringLiteral(
"_layer_was_editable" ) );
2325bool QgsProject::loadEmbeddedNodes(
QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
2330 const auto constChildren = group->
children();
2336 if ( childGroup->
customProperty( QStringLiteral(
"embedded" ) ).toInt() )
2339 const QString projectPath =
readPath( childGroup->
customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
2340 childGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectPath );
2344 QList<QgsLayerTreeNode *> clonedChildren;
2345 const QList<QgsLayerTreeNode *> constChildren = newGroup->
children();
2346 clonedChildren.reserve( constChildren.size() );
2348 clonedChildren << newGroupChild->clone();
2356 loadEmbeddedNodes( childGroup,
flags );
2361 if ( child->customProperty( QStringLiteral(
"embedded" ) ).toInt() )
2363 QList<QDomNode> brokenNodes;
2366 valid = valid &&
false;
2381 return mCustomVariables;
2388 if ( variables == mCustomVariables )
2392 QStringList variableNames;
2393 QStringList variableValues;
2395 QVariantMap::const_iterator it = variables.constBegin();
2396 for ( ; it != variables.constEnd(); ++it )
2398 variableNames << it.key();
2399 variableValues << it.value().toString();
2402 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ), variableNames );
2403 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ), variableValues );
2405 mCustomVariables = variables;
2406 mProjectScope.reset();
2415 *mLabelingEngineSettings = settings;
2423 return *mLabelingEngineSettings;
2430 mProjectScope.reset();
2431 return mLayerStore.get();
2438 return mLayerStore.get();
2445 QList<QgsVectorLayer *>
layers;
2446 const QStringList layerIds =
readListEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), QStringList() );
2447 const auto constLayerIds = layerIds;
2448 for (
const QString &layerId : constLayerIds )
2461 list.reserve(
layers.size() );
2463 list << layer->id();
2464 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), list );
2486 if ( mProjectScope )
2488 std::unique_ptr< QgsExpressionContextScope > projectScope = std::make_unique< QgsExpressionContextScope >( *mProjectScope );
2495 projectScope->addFunction( QStringLiteral(
"sensor_data" ),
new GetSensorData(
sensorManager()->sensorsData() ) );
2497 return projectScope.release();
2500 mProjectScope = std::make_unique< QgsExpressionContextScope >( QObject::tr(
"Project" ) );
2504 QVariantMap::const_iterator it = vars.constBegin();
2506 for ( ; it != vars.constEnd(); ++it )
2508 mProjectScope->setVariable( it.key(), it.value(),
true );
2512 if ( projectPath.isEmpty() )
2513 projectPath = mOriginalPath;
2514 const QString projectFolder = QFileInfo( projectPath ).path();
2515 const QString projectFilename = QFileInfo( projectPath ).fileName();
2516 const QString projectBasename =
baseName();
2545 QVariantMap keywords;
2547 for (
auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
2549 keywords.insert( it.key(), it.value() );
2554 QVariantList layersIds;
2556 const QMap<QString, QgsMapLayer *> layersInProject = mLayerStore->mapLayers();
2557 layersIds.reserve( layersInProject.count() );
2558 layers.reserve( layersInProject.count() );
2559 for (
auto it = layersInProject.constBegin(); it != layersInProject.constEnd(); ++it )
2561 layersIds << it.value()->id();
2567 mProjectScope->addFunction( QStringLiteral(
"project_color" ),
new GetNamedProjectColor(
this ) );
2572void QgsProject::onMapLayersAdded(
const QList<QgsMapLayer *> &layers )
2576 const QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
2578 const auto constLayers =
layers;
2581 if ( ! layer->isValid() )
2587 for ( QMap<QString, QgsMapLayer *>::const_iterator it = existingMaps.cbegin(); it != existingMaps.cend(); ++it )
2589 const QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
2590 if ( deps.contains( layer->id() ) )
2593 it.value()->setDependencies( deps );
2598 updateTransactionGroups();
2604void QgsProject::onMapLayersRemoved(
const QList<QgsMapLayer *> &layers )
2612void QgsProject::cleanTransactionGroups(
bool force )
2616 bool changed =
false;
2617 for ( QMap< QPair< QString, QString>,
QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
2619 if ( tg.value()->isEmpty() || force )
2622 tg = mTransactionGroups.erase( tg );
2634void QgsProject::updateTransactionGroups()
2638 mEditBufferGroup.
clear();
2640 switch ( mTransactionMode )
2644 cleanTransactionGroups(
true );
2649 cleanTransactionGroups(
true );
2652 cleanTransactionGroups(
false );
2656 bool tgChanged =
false;
2657 const auto constLayers =
mapLayers().values();
2660 if ( ! layer->isValid() )
2663 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
2667 switch ( mTransactionMode )
2684 mTransactionGroups.insert( qMakePair( key, connString ), tg );
2694 mEditBufferGroup.
addLayer( vlayer );
2710 context.setProjectTranslator(
this );
2712 QList<QDomNode> brokenNodes;
2713 if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
2717 const QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
2721 layer->resolveReferences(
this );
2723 if ( layer->isValid() && layer->customProperty( QStringLiteral(
"_layer_was_editable" ) ).toBool() )
2725 layer->startEditing();
2726 layer->removeCustomProperty( QStringLiteral(
"_layer_was_editable" ) );
2738 mFile.setFileName( filename );
2739 mCachedHomePath.clear();
2747 mProjectScope.reset();
2753 const QString storageFilePath { storage->filePath( mFile.fileName() ) };
2754 if ( storageFilePath.isEmpty() )
2760 const QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2761 const QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2763 if ( !zip( tmpZipFilename ) )
2766 QFile tmpZipFile( tmpZipFilename );
2767 if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2769 setError( tr(
"Unable to read file %1" ).arg( tmpZipFilename ) );
2774 if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2776 QString err = tr(
"Unable to save project to storage %1" ).arg( mFile.fileName() );
2777 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
2778 if ( !messages.isEmpty() )
2779 err += QStringLiteral(
"\n\n" ) + messages.last().message();
2785 QFile::remove( tmpZipFilename );
2792 return zip( mFile.fileName() );
2798 const bool asOk = saveAuxiliaryStorage();
2799 const bool writeOk = writeProjectFile( mFile.fileName() );
2800 bool attachmentsOk =
true;
2801 if ( !mArchive->files().isEmpty() )
2803 const QFileInfo finfo( mFile.fileName() );
2804 const QString attachmentsZip = finfo.absoluteDir().absoluteFilePath( QStringLiteral(
"%1_attachments.zip" ).arg( finfo.completeBaseName() ) );
2805 attachmentsOk = mArchive->zip( attachmentsZip );
2809 if ( ( !asOk || !attachmentsOk ) && writeOk )
2811 QStringList errorMessage;
2814 const QString err = mAuxiliaryStorage->errorString();
2815 errorMessage.append( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
2817 if ( !attachmentsOk )
2819 errorMessage.append( tr(
"Unable to save attachments archive" ) );
2821 setError( errorMessage.join(
'\n' ) );
2824 return asOk && writeOk && attachmentsOk;
2828bool QgsProject::writeProjectFile(
const QString &filename )
2832 QFile projectFile( filename );
2838 const QFileInfo myFileInfo( projectFile );
2839 if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2841 setError( tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
2842 .arg( projectFile.fileName() ) );
2850 QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2852 const QDomDocumentType documentType =
2853 QDomImplementation().createDocumentType( QStringLiteral(
"qgis" ), QStringLiteral(
"http://mrcc.com/qgis.dtd" ),
2854 QStringLiteral(
"SYSTEM" ) );
2855 std::unique_ptr<QDomDocument> doc(
new QDomDocument( documentType ) );
2857 QDomElement qgisNode = doc->createElement( QStringLiteral(
"qgis" ) );
2858 qgisNode.setAttribute( QStringLiteral(
"projectname" ),
title() );
2859 qgisNode.setAttribute( QStringLiteral(
"version" ),
Qgis::version() );
2861 if ( !mSettings.
value( QStringLiteral(
"projects/anonymize_saved_projects" ),
false,
QgsSettings::Core ).toBool() )
2865 qgisNode.setAttribute( QStringLiteral(
"saveUser" ), newSaveUser );
2866 qgisNode.setAttribute( QStringLiteral(
"saveUserFull" ), newSaveUserFull );
2867 mSaveUser = newSaveUser;
2868 mSaveUserFull = newSaveUserFull;
2869 mSaveDateTime = QDateTime::currentDateTime();
2870 qgisNode.setAttribute( QStringLiteral(
"saveDateTime" ), mSaveDateTime.toString( Qt::ISODate ) );
2875 mSaveUserFull.clear();
2876 mSaveDateTime = QDateTime();
2878 doc->appendChild( qgisNode );
2881 QDomElement homePathNode = doc->createElement( QStringLiteral(
"homePath" ) );
2882 homePathNode.setAttribute( QStringLiteral(
"path" ), mHomePath );
2883 qgisNode.appendChild( homePathNode );
2886 QDomElement titleNode = doc->createElement( QStringLiteral(
"title" ) );
2887 qgisNode.appendChild( titleNode );
2889 QDomElement transactionNode = doc->createElement( QStringLiteral(
"transaction" ) );
2890 transactionNode.setAttribute( QStringLiteral(
"mode" ),
qgsEnumValueToKey( mTransactionMode ) );
2891 qgisNode.appendChild( transactionNode );
2893 QDomElement flagsNode = doc->createElement( QStringLiteral(
"projectFlags" ) );
2895 qgisNode.appendChild( flagsNode );
2897 const QDomText titleText = doc->createTextNode(
title() );
2898 titleNode.appendChild( titleText );
2901 QDomElement srsNode = doc->createElement( QStringLiteral(
"projectCrs" ) );
2903 qgisNode.appendChild( srsNode );
2905 QDomElement elevationShadingNode = doc->createElement( QStringLiteral(
"elevation-shading-renderer" ) );
2906 mElevationShadingRenderer.
writeXml( elevationShadingNode, context );
2907 qgisNode.appendChild( elevationShadingNode );
2914 clonedRoot->
writeXml( qgisNode, context );
2918 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsMode" ),
static_cast<int>( mAvoidIntersectionsMode ) );
2926 QDomElement annotationLayerNode = doc->createElement( QStringLiteral(
"main-annotation-layer" ) );
2927 mMainAnnotationLayer->
writeLayerXml( annotationLayerNode, *doc, context );
2928 qgisNode.appendChild( annotationLayerNode );
2932 QDomElement projectLayersNode = doc->createElement( QStringLiteral(
"projectlayers" ) );
2934 QMap<QString, QgsMapLayer *>::ConstIterator li =
layers.constBegin();
2935 while ( li !=
layers.end() )
2941 const QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->
id() );
2942 if ( emIt == mEmbeddedLayers.constEnd() )
2944 QDomElement maplayerElem;
2950 maplayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2954 maplayerElem.setAttribute( QStringLiteral(
"editable" ), QStringLiteral(
"1" ) );
2958 QDomDocument document;
2961 maplayerElem = document.firstChildElement();
2965 QgsDebugError( QStringLiteral(
"Could not restore layer properties for layer %1" ).arg( ml->
id() ) );
2971 projectLayersNode.appendChild( maplayerElem );
2977 if ( emIt.value().second )
2979 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2980 mapLayerElem.setAttribute( QStringLiteral(
"embedded" ), 1 );
2981 mapLayerElem.setAttribute( QStringLiteral(
"project" ),
writePath( emIt.value().first ) );
2982 mapLayerElem.setAttribute( QStringLiteral(
"id" ), ml->
id() );
2983 projectLayersNode.appendChild( mapLayerElem );
2990 qgisNode.appendChild( projectLayersNode );
2992 QDomElement layerOrderNode = doc->createElement( QStringLiteral(
"layerorder" ) );
2994 for (
QgsMapLayer *layer : constCustomLayerOrder )
2996 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"layer" ) );
2997 mapLayerElem.setAttribute( QStringLiteral(
"id" ), layer->id() );
2998 layerOrderNode.appendChild( mapLayerElem );
3000 qgisNode.appendChild( layerOrderNode );
3002 mLabelingEngineSettings->writeSettingsToProject(
this );
3004 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorRedPart" ), mBackgroundColor.red() );
3005 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), mBackgroundColor.green() );
3006 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), mBackgroundColor.blue() );
3008 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorRedPart" ), mSelectionColor.red() );
3009 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), mSelectionColor.green() );
3010 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), mSelectionColor.blue() );
3011 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), mSelectionColor.alpha() );
3018 dump_( mProperties );
3021 QgsDebugMsgLevel( QStringLiteral(
"there are %1 property scopes" ).arg(
static_cast<int>( mProperties.
count() ) ), 2 );
3026 mProperties.
writeXml( QStringLiteral(
"properties" ), qgisNode, *doc );
3029 QDomElement ddElem = doc->createElement( QStringLiteral(
"dataDefinedServerProperties" ) );
3030 mDataDefinedServerProperties.
writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
3031 qgisNode.appendChild( ddElem );
3033 mMapThemeCollection->writeXml( *doc );
3035 mTransformContext.
writeXml( qgisNode, context );
3037 QDomElement metadataElem = doc->createElement( QStringLiteral(
"projectMetadata" ) );
3039 qgisNode.appendChild( metadataElem );
3042 const QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
3043 qgisNode.appendChild( annotationsElem );
3047 const QDomElement layoutElem = mLayoutManager->writeXml( *doc );
3048 qgisNode.appendChild( layoutElem );
3052 const QDomElement views3DElem = m3DViewsManager->writeXml( *doc );
3053 qgisNode.appendChild( views3DElem );
3057 const QDomElement bookmarkElem = mBookmarkManager->
writeXml( *doc );
3058 qgisNode.appendChild( bookmarkElem );
3062 const QDomElement sensorElem = mSensorManager->
writeXml( *doc );
3063 qgisNode.appendChild( sensorElem );
3067 const QDomElement viewSettingsElem = mViewSettings->
writeXml( *doc, context );
3068 qgisNode.appendChild( viewSettingsElem );
3072 const QDomElement styleSettingsElem = mStyleSettings->
writeXml( *doc, context );
3073 qgisNode.appendChild( styleSettingsElem );
3077 const QDomElement timeSettingsElement = mTimeSettings->
writeXml( *doc, context );
3078 qgisNode.appendChild( timeSettingsElement );
3082 const QDomElement elevationPropertiesElement = mElevationProperties->
writeXml( *doc, context );
3083 qgisNode.appendChild( elevationPropertiesElement );
3087 const QDomElement displaySettingsElem = mDisplaySettings->
writeXml( *doc, context );
3088 qgisNode.appendChild( displaySettingsElem );
3092 const QDomElement gpsSettingsElem = mGpsSettings->
writeXml( *doc, context );
3093 qgisNode.appendChild( gpsSettingsElem );
3102 QFile backupFile( QStringLiteral(
"%1~" ).arg( filename ) );
3104 ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
3105 ok &= projectFile.open( QIODevice::ReadOnly );
3108 while ( ok && !projectFile.atEnd() )
3110 ba = projectFile.read( 10240 );
3111 ok &= backupFile.write( ba ) == ba.size();
3114 projectFile.close();
3119 setError( tr(
"Unable to create backup file %1" ).arg( backupFile.fileName() ) );
3124 struct utimbuf tb = {
static_cast<time_t
>( fi.lastRead().toSecsSinceEpoch() ),
static_cast<time_t
>( fi.lastModified().toSecsSinceEpoch() ) };
3125 utime( backupFile.fileName().toUtf8().constData(), &tb );
3128 if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3130 projectFile.close();
3133 setError( tr(
"Unable to save to file %1" ).arg( projectFile.fileName() ) );
3137 QTemporaryFile tempFile;
3138 bool ok = tempFile.open();
3141 QTextStream projectFileStream( &tempFile );
3142 doc->save( projectFileStream, 2 );
3143 ok &= projectFileStream.pos() > -1;
3145 ok &= tempFile.seek( 0 );
3148 while ( ok && !tempFile.atEnd() )
3150 ba = tempFile.read( 10240 );
3151 ok &= projectFile.write( ba ) == ba.size();
3154 ok &= projectFile.error() == QFile::NoError;
3156 projectFile.close();
3163 setError( tr(
"Unable to save to file %1. Your project "
3164 "may be corrupted on disk. Try clearing some space on the volume and "
3165 "check file permissions before pressing save again." )
3166 .arg( projectFile.fileName() ) );
3180 bool propertiesModified;
3181 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3183 if ( propertiesModified )
3193 bool propertiesModified;
3194 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3196 if ( propertiesModified )
3206 bool propertiesModified;
3207 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3209 if ( propertiesModified )
3219 bool propertiesModified;
3220 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3222 if ( propertiesModified )
3232 bool propertiesModified;
3233 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
3235 if ( propertiesModified )
3243 const QStringList &def,
3255 value =
property->value();
3257 const bool valid = QVariant::StringList == value.type();
3263 return value.toStringList();
3286 value =
property->value();
3288 const bool valid = value.canConvert( QVariant::String );
3293 return value.toString();
3312 value =
property->value();
3315 const bool valid = value.canConvert( QVariant::Int );
3324 return value.toInt();
3339 const QVariant value =
property->value();
3341 const bool valid = value.canConvert( QVariant::Double );
3346 return value.toDouble();
3363 const QVariant value =
property->value();
3365 const bool valid = value.canConvert( QVariant::Bool );
3370 return value.toBool();
3382 if (
findKey_( scope, key, mProperties ) )
3388 return !
findKey_( scope, key, mProperties );
3397 QStringList entries;
3399 if ( foundProperty )
3416 QStringList entries;
3418 if ( foundProperty )
3433 dump_( mProperties );
3453 filePath = storage->filePath( mFile.fileName() );
3480void QgsProject::setError(
const QString &errorMessage )
3484 mErrorMessage = errorMessage;
3491 return mErrorMessage;
3494void QgsProject::clearError()
3498 setError( QString() );
3505 delete mBadLayerHandler;
3506 mBadLayerHandler = handler;
3513 const QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find(
id );
3514 if ( it == mEmbeddedLayers.constEnd() )
3518 return it.value().first;
3522 bool saveFlag, Qgis::ProjectReadFlags flags )
3528 static QString sPrevProjectFilePath;
3529 static QDateTime sPrevProjectFileTimestamp;
3530 static QDomDocument sProjectDocument;
3532 QString qgsProjectFile = projectFilePath;
3534 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
3536 archive.
unzip( projectFilePath );
3540 const QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
3542 if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
3544 sPrevProjectFilePath.clear();
3546 QFile projectFile( qgsProjectFile );
3547 if ( !projectFile.open( QIODevice::ReadOnly ) )
3552 if ( !sProjectDocument.setContent( &projectFile ) )
3557 sPrevProjectFilePath = projectFilePath;
3558 sPrevProjectFileTimestamp = projectFileTimestamp;
3562 bool useAbsolutePaths =
true;
3564 const QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
3565 if ( !propertiesElem.isNull() )
3567 const QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral(
"Paths" ) ).firstChildElement( QStringLiteral(
"Absolute" ) );
3568 if ( !absElem.isNull() )
3570 useAbsolutePaths = absElem.text().compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
3575 if ( !useAbsolutePaths )
3580 const QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) );
3581 if ( projectLayersElem.isNull() )
3586 QDomElement mapLayerElem = projectLayersElem.firstChildElement( QStringLiteral(
"maplayer" ) );
3587 while ( ! mapLayerElem.isNull() )
3590 const QString
id = mapLayerElem.firstChildElement( QStringLiteral(
"id" ) ).text();
3591 if (
id == layerId )
3594 if ( mapLayerElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
3599 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
3601 if ( addLayer( mapLayerElem, brokenNodes, embeddedContext,
flags ) )
3607 mEmbeddedLayers.remove( layerId );
3611 mapLayerElem = mapLayerElem.nextSiblingElement( QStringLiteral(
"maplayer" ) );
3621 QString qgsProjectFile = projectFilePath;
3623 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
3625 archive.
unzip( projectFilePath );
3630 QFile projectFile( qgsProjectFile );
3631 if ( !projectFile.open( QIODevice::ReadOnly ) )
3636 QDomDocument projectDocument;
3637 if ( !projectDocument.setContent( &projectFile ) )
3649 QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
3650 if ( !layerTreeElem.isNull() )
3660 if ( !group || group->
customProperty( QStringLiteral(
"embedded" ) ).toBool() )
3673 newGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectFilePath );
3676 mLayerTreeRegistryBridge->
setEnabled(
false );
3677 initializeEmbeddedSubtree( projectFilePath, newGroup,
flags );
3678 mLayerTreeRegistryBridge->
setEnabled(
true );
3681 const auto constFindLayerIds = newGroup->
findLayerIds();
3682 for (
const QString &layerId : constFindLayerIds )
3695void QgsProject::initializeEmbeddedSubtree(
const QString &projectFilePath,
QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
3699 const auto constChildren = group->
children();
3703 child->setCustomProperty( QStringLiteral(
"embedded" ), 1 );
3712 QList<QDomNode> brokenNodes;
3736 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
3744 return readNumEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), 0 );
3751 if ( mDistanceUnits == unit )
3754 mDistanceUnits = unit;
3763 if ( mAreaUnits == unit )
3776 if ( !mCachedHomePath.isEmpty() )
3777 return mCachedHomePath;
3781 if ( !mHomePath.isEmpty() )
3783 const QFileInfo homeInfo( mHomePath );
3784 if ( !homeInfo.isRelative() )
3786 mCachedHomePath = mHomePath;
3792 mCachedHomePath = pfi.path();
3794 return mCachedHomePath;
3797 if ( !pfi.exists() )
3799 mCachedHomePath = mHomePath;
3803 if ( !mHomePath.isEmpty() )
3806 mCachedHomePath = QDir::cleanPath( pfi.path() +
'/' + mHomePath );
3810 mCachedHomePath = pfi.canonicalPath();
3812 return mCachedHomePath;
3827 return mRelationManager;
3834 return mLayoutManager.get();
3841 return mLayoutManager.get();
3848 return m3DViewsManager.get();
3855 return m3DViewsManager.get();
3862 return mBookmarkManager;
3869 return mBookmarkManager;
3876 return mSensorManager;
3883 return mSensorManager;
3890 return mViewSettings;
3897 return mViewSettings;
3904 return mStyleSettings;
3912 return mStyleSettings;
3919 return mTimeSettings;
3926 return mTimeSettings;
3933 return mElevationProperties;
3940 return mElevationProperties;
3947 return mDisplaySettings;
3954 return mDisplaySettings;
3961 return mGpsSettings;
3968 return mGpsSettings;
3982 return mMapThemeCollection.get();
3989 return mAnnotationManager.get();
3996 return mAnnotationManager.get();
4003 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
4004 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
4009 if (
layers.contains( it.value() ) )
4026 for (
const QString &layerId : layerIds )
4044 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4078 updateTransactionGroups();
4085 return mTransactionMode;
4096 const auto constLayers =
mapLayers().values();
4099 if ( layer->isEditable() )
4101 QgsLogger::warning( tr(
"Transaction mode can be changed only if all layers are not editable." ) );
4107 updateTransactionGroups();
4115 return mTransactionGroups;
4128 return mLayerStore->count();
4135 return mLayerStore->validCount();
4143 return mLayerStore->mapLayer( layerId );
4150 return mLayerStore->mapLayersByName( layerName );
4157 QList<QgsMapLayer *>
layers;
4158 const auto constMapLayers { mLayerStore->mapLayers() };
4159 for (
const auto &l : constMapLayers )
4161 if ( ! l->shortName().isEmpty() )
4163 if ( l->shortName() == shortName )
4166 else if ( l->name() == shortName )
4174bool QgsProject::unzip(
const QString &filename, Qgis::ProjectReadFlags flags )
4182 if ( !archive->unzip( filename ) )
4184 setError( tr(
"Unable to unzip file '%1'" ).arg( filename ) );
4189 if ( archive->projectFile().isEmpty() )
4191 setError( tr(
"Zip archive does not provide a project file" ) );
4196 mArchive = std::move( archive );
4213 setError( tr(
"Cannot read unzipped qgs project file" ) + QStringLiteral(
": " ) +
error() );
4223bool QgsProject::zip(
const QString &filename )
4231 const QString
baseName = QFileInfo( filename ).baseName();
4232 const QString qgsFileName = QStringLiteral(
"%1.qgs" ).arg(
baseName );
4233 QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
4235 bool writeOk =
false;
4236 if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
4238 writeOk = writeProjectFile( qgsFile.fileName() );
4245 setError( tr(
"Unable to write temporary qgs file" ) );
4250 const QFileInfo info( qgsFile );
4252 const QString asFileName = info.path() + QDir::separator() + info.completeBaseName() + asExt;
4254 bool auxiliaryStorageSavedOk =
true;
4255 if ( ! saveAuxiliaryStorage( asFileName ) )
4257 const QString err = mAuxiliaryStorage->errorString();
4258 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 ) );
4259 auxiliaryStorageSavedOk =
false;
4262 if ( !mArchive->exists() )
4265 mArchive->unzip( mFile.fileName() );
4268 const QString auxiliaryStorageFile =
static_cast<QgsProjectArchive *
>( mArchive.get() )->auxiliaryStorageFile();
4269 if ( ! auxiliaryStorageFile.isEmpty() )
4271 archive->
addFile( auxiliaryStorageFile );
4280 if ( QFile::exists( asFileName ) )
4282 archive->addFile( asFileName );
4287 archive->addFile( qgsFile.fileName() );
4290 const QStringList &
files = mArchive->files();
4291 for (
const QString &file :
files )
4293 if ( !file.endsWith( QLatin1String(
".qgs" ), Qt::CaseInsensitive ) && !file.endsWith( asExt, Qt::CaseInsensitive ) )
4295 archive->addFile( file );
4301 if ( !archive->zip( filename ) )
4303 setError( tr(
"Unable to perform zip" ) );
4307 return auxiliaryStorageSavedOk && zipOk;
4318 const QList<QgsMapLayer *> &layers,
4320 bool takeOwnership )
4324 const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers(
layers, takeOwnership ) };
4325 if ( !myResultList.isEmpty() )
4328 for (
auto &l : myResultList )
4338 if ( mAuxiliaryStorage )
4342 if ( mlayer->type() != Qgis::LayerType::Vector )
4353 mProjectScope.reset();
4355 return myResultList;
4361 bool takeOwnership )
4365 QList<QgsMapLayer *> addedLayers;
4366 addedLayers =
addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
4367 return addedLayers.isEmpty() ? nullptr : addedLayers[0];
4370void QgsProject::removeAuxiliaryLayer(
const QgsMapLayer *ml )
4374 if ( ! ml || ml->
type() != Qgis::LayerType::Vector )
4377 const QgsVectorLayer *vl = qobject_cast<const QgsVectorLayer *>( ml );
4389 for (
const auto &layerId : layerIds )
4390 removeAuxiliaryLayer( mLayerStore->mapLayer( layerId ) );
4392 mProjectScope.reset();
4393 mLayerStore->removeMapLayers( layerIds );
4400 for (
const auto &layer :
layers )
4401 removeAuxiliaryLayer( layer );
4403 mProjectScope.reset();
4404 mLayerStore->removeMapLayers(
layers );
4411 removeAuxiliaryLayer( mLayerStore->mapLayer( layerId ) );
4412 mProjectScope.reset();
4413 mLayerStore->removeMapLayer( layerId );
4420 removeAuxiliaryLayer( layer );
4421 mProjectScope.reset();
4422 mLayerStore->removeMapLayer( layer );
4429 mProjectScope.reset();
4430 return mLayerStore->takeMapLayer( layer );
4437 return mMainAnnotationLayer;
4444 if ( mLayerStore->count() == 0 )
4447 ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
4448 mProjectScope.reset();
4449 mLayerStore->removeAllMapLayers();
4451 snapSingleBlocker.release();
4453 if ( !mBlockSnappingUpdates )
4461 const QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
4462 QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin();
4463 for ( ; it !=
layers.constEnd(); ++it )
4465 it.value()->reload();
4474 return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
4481 return mTransactionGroups.value( qMakePair( providerKey, connString ) );
4488 return &mEditBufferGroup;
4499 if ( mSettings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), QStringLiteral(
"NoAction" ),
QgsSettings::App ).toString() == QStringLiteral(
"UseProjectCrs" )
4500 || mSettings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), 0,
QgsSettings::App ).toString() == QLatin1String(
"2" ) )
4508 const QString layerDefaultCrs = mSettings.
value( QStringLiteral(
"/Projections/layerDefaultCrs" ),
geoEpsgCrsAuthId() ).toString();
4529bool QgsProject::saveAuxiliaryStorage(
const QString &filename )
4535 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4537 if ( it.value()->type() != Qgis::LayerType::Vector )
4540 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
4548 if ( !mAuxiliaryStorage->exists( *
this ) && empty )
4552 else if ( !filename.isEmpty() )
4554 return mAuxiliaryStorage->saveAs( filename );
4558 return mAuxiliaryStorage->saveAs( *
this );
4567 QgsProject::DataDefinedServerProperty::WMSOnlineResource,
4571 return sPropertyDefinitions;
4584 return mAuxiliaryStorage.get();
4591 return mAuxiliaryStorage.get();
4598 const QDir archiveDir( mArchive->dir() );
4599 QTemporaryFile tmpFile( archiveDir.filePath(
"XXXXXX_" + nameTemplate ),
this );
4600 tmpFile.setAutoRemove(
false );
4602 mArchive->addFile( tmpFile.fileName() );
4603 return tmpFile.fileName();
4610 QStringList attachments;
4612 const QStringList
files = mArchive->files();
4613 attachments.reserve(
files.size() );
4614 for (
const QString &file :
files )
4618 attachments.append( file );
4628 return mArchive->removeFile( path );
4635 return QStringLiteral(
"attachment:///%1" ).arg( QFileInfo( attachedFile ).
fileName() );
4642 if ( identifier.startsWith( QLatin1String(
"attachment:///" ) ) )
4644 return QDir( mArchive->dir() ).absoluteFilePath( identifier.mid( 14 ) );
4665 mProjectScope.reset();
4679 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4693 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
4694 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
4699 if (
layers.contains( it.value() ) )
4711 QStringList customColors;
4712 QStringList customColorLabels;
4714 QgsNamedColorList::const_iterator colorIt = colors.constBegin();
4715 for ( ; colorIt != colors.constEnd(); ++colorIt )
4718 const QString label = ( *colorIt ).second;
4719 customColors.append( color );
4720 customColorLabels.append( label );
4722 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ), customColors );
4723 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ), customColorLabels );
4724 mProjectScope.reset();
4732 if ( mBackgroundColor == color )
4735 mBackgroundColor = color;
4743 return mBackgroundColor;
4750 if ( mSelectionColor == color )
4753 mSelectionColor = color;
4761 return mSelectionColor;
4798 translationContext.setFileName( QStringLiteral(
"%1/%2.ts" ).arg(
absolutePath(),
baseName() ) );
4802 translationContext.writeTsFile( locale );
4805QString
QgsProject::translate(
const QString &context,
const QString &sourceText,
const char *disambiguation,
int n )
const
4814 QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
4816 if ( result.isEmpty() )
4830 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4835 if ( !( ( *it )->accept( visitor ) ) )
4844 if ( !mLayoutManager->accept( visitor ) )
4847 if ( !mAnnotationManager->accept( visitor ) )
4855 return mElevationShadingRenderer;
4858void QgsProject::loadProjectFlags(
const QDomDocument *doc )
4862 QDomElement element = doc->documentElement().firstChildElement( QStringLiteral(
"projectFlags" ) );
4863 Qgis::ProjectFlags
flags;
4864 if ( !element.isNull() )
4871 element = doc->documentElement().firstChildElement( QStringLiteral(
"evaluateDefaultValues" ) );
4872 if ( !element.isNull() )
4874 if ( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
4879 element = doc->documentElement().firstChildElement( QStringLiteral(
"trust" ) );
4880 if ( !element.isNull() )
4882 if ( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
4891GetNamedProjectColor::GetNamedProjectColor(
const QgsProject *project )
4898 QStringList colorStrings = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ) );
4899 const QStringList colorLabels = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ) );
4903 for ( QStringList::iterator it = colorStrings.begin();
4904 it != colorStrings.end(); ++it )
4908 if ( colorLabels.length() > colorIndex )
4910 label = colorLabels.at( colorIndex );
4913 mColors.insert( label.toLower(), color );
4918GetNamedProjectColor::GetNamedProjectColor(
const QHash<QString, QColor> &colors )
4926 const QString colorName = values.at( 0 ).toString().toLower();
4927 if ( mColors.contains( colorName ) )
4929 return QStringLiteral(
"%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
4937 return new GetNamedProjectColor( mColors );
4942GetSensorData::GetSensorData(
const QMap<QString, QgsAbstractSensor::SensorData> &sensorData )
4945 QStringLiteral(
"Sensors" ) )
4946 , mSensorData( sensorData )
4952 const QString sensorName = values.at( 0 ).toString();
4953 const int expiration = values.at( 1 ).toInt();
4954 const qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
4955 if ( mSensorData.contains( sensorName ) )
4957 if ( expiration <= 0 || ( timestamp - mSensorData[sensorName].lastTimestamp.toMSecsSinceEpoch() ) < expiration )
4959 return mSensorData[sensorName].lastValue;
4968 return new GetSensorData( mSensorData );
@ ForceReadOnlyLayers
Open layers in a read-only mode. (since QGIS 3.28)
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.
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.
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.
Q_GADGET Qgis::DistanceUnit mapUnits
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.
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.
@ 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.
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
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 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.
void crsChanged()
Emitted when the CRS of the project has changed.
QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const override
Translates the project with QTranslator and qm file.
const QgsProjectStyleSettings * styleSettings() const
Returns the project's style settings, which contains settings and properties relating to how a QgsPro...
QgsSnappingConfig snappingConfig
const QgsProjectGpsSettings * gpsSettings() const
Returns the project's GPS settings, which contains settings and properties relating to how a QgsProje...
void setFileName(const QString &name)
Sets the file name associated with the project.
void avoidIntersectionsLayersChanged()
Emitted whenever avoidIntersectionsLayers has changed.
void setDataDefinedServerProperties(const QgsPropertyCollection &properties)
Sets the data defined properties used for overrides in user defined server parameters to properties.
void registerTranslatableObjects(QgsTranslationContext *translationContext)
Registers the objects that require translation into the translationContext.
void distanceUnitsChanged()
Emitted when the default distance units changes.
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
const QgsBookmarkManager * bookmarkManager() const
Returns the project's bookmark manager, which manages bookmarks within the project.
void readMapLayer(QgsMapLayer *mapLayer, const QDomElement &layerNode)
Emitted after the basic initialization of a layer from the project file is done.
Q_DECL_DEPRECATED void setAutoTransaction(bool autoTransaction)
Transactional editing means that on supported datasources (postgres databases) the edit state of all ...
bool startEditing(QgsVectorLayer *vectorLayer=nullptr)
Makes the layer editable.
Q_DECL_DEPRECATED void setTrustLayerMetadata(bool trust)
Sets the trust option allowing to indicate if the extent has to be read from the XML document when da...
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
Q_DECL_DEPRECATED void oldProjectVersionWarning(const QString &)
Emitted when an old project file is read.
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets project's global labeling engine settings.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void metadataChanged()
Emitted when the project's metadata is changed.
QString resolveAttachmentIdentifier(const QString &identifier) const
Resolves an attachment identifier to a attachment file path.
const QgsProjectElevationProperties * elevationProperties() const
Returns the project's elevation properties, which contains the project's elevation related settings.
QString absolutePath() const
Returns full absolute path to the project folder if the project is stored in a file system - derived ...
void removeMapLayers(const QStringList &layerIds)
Remove a set of layers from the registry by layer ID.
Q_DECL_DEPRECATED void setRequiredLayers(const QSet< QgsMapLayer * > &layers)
Configures a set of map layers that are required in the project and therefore they should not get rem...
bool createEmbeddedLayer(const QString &layerId, const QString &projectFilePath, QList< QDomNode > &brokenNodes, bool saveFlag=true, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Creates a maplayer instance defined in an arbitrary project file.
QList< QgsVectorLayer * > avoidIntersectionsLayers
QString readEntry(const QString &scope, const QString &key, const QString &def=QString(), bool *ok=nullptr) const
Reads a string from the specified scope and key.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
void ellipsoidChanged(const QString &ellipsoid)
Emitted when the project ellipsoid is changed.
QgsMapThemeCollection * mapThemeCollection
void generateTsFile(const QString &locale)
Triggers the collection strings of .qgs to be included in ts file and calls writeTsFile()
QStringList entryList(const QString &scope, const QString &key) const
Returns a list of child keys with values which exist within the the specified scope and key.
QgsAnnotationManager * annotationManager()
Returns pointer to the project's annotation manager.
QgsProjectDisplaySettings * displaySettings
Qgis::TransactionMode transactionMode() const
Returns the transaction mode.
QgsProjectMetadata metadata
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
QString saveUser() const
Returns the user name that did the last save.
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
void setProjectColors(const QgsNamedColorList &colors)
Sets the colors for the project's color scheme (see QgsProjectColorScheme).
bool setTransactionMode(Qgis::TransactionMode transactionMode)
Set transaction mode.
QgsCoordinateTransformContext transformContext
void labelingEngineSettingsChanged()
Emitted when global configuration of the labeling engine changes.
void customVariablesChanged()
Emitted whenever the expression variables stored in the project have been changed.
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
bool readBoolEntry(const QString &scope, const QString &key, bool def=false, bool *ok=nullptr) const
Reads a boolean from the specified scope and key.
QgsMapLayerStore * layerStore()
Returns a pointer to the project's internal layer store.
void readProject(const QDomDocument &)
Emitted when a project is being read.
QString originalPath() const
Returns the original path associated with the project.
void setOriginalPath(const QString &path)
Sets the original path associated with the project.
void dumpProperties() const
Dump out current project properties to stderr.
QgsElevationShadingRenderer elevationShadingRenderer() const
Returns the elevation shading renderer used for map shading.
const QgsMapViewsManager * viewsManager() const
Returns the project's views manager, which manages map views (including 3d maps) in the project.
static void setInstance(QgsProject *project)
Set the current project singleton instance to project.
int validCount() const
Returns the number of registered valid layers.
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
void elevationShadingRendererChanged()
Emitted when the map shading renderer changes.
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
Q_DECL_DEPRECATED bool autoTransaction() const
Transactional editing means that on supported datasources (postgres databases) the edit state of all ...
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
QStringList attachedFiles() const
Returns a map of all attached files with identifier and real paths.
void setMetadata(const QgsProjectMetadata &metadata)
Sets the project's metadata store.
void missingDatumTransforms(const QStringList &missingTransforms)
Emitted when datum transforms stored in the project are not available locally.
QgsTransactionGroup * transactionGroup(const QString &providerKey, const QString &connString)
Returns the matching transaction group from a provider key and connection string.
QgsCoordinateReferenceSystem crs
void readProjectWithContext(const QDomDocument &, QgsReadWriteContext &context)
Emitted when a project is being read.
QgsMapLayer * addMapLayer(QgsMapLayer *mapLayer, bool addToLegend=true, bool takeOwnership=true)
Add a layer to the map of loaded layers.
QStringList nonIdentifiableLayers
void setAvoidIntersectionsMode(const Qgis::AvoidIntersectionsMode mode)
Sets the avoid intersections mode.
void transactionGroupsChanged()
Emitted whenever a new transaction group has been created or a transaction group has been removed.
const QgsAuxiliaryStorage * auxiliaryStorage() const
Returns the current const auxiliary storage.
void reloadAllLayers()
Reload all registered layer's provider data caches, synchronising the layer with any changes in the d...
int count() const
Returns the number of registered layers.
void loadingLayerMessageReceived(const QString &layerName, const QList< QgsReadWriteContext::ReadWriteMessage > &messages)
Emitted when loading layers has produced some messages.
void setAreaUnits(Qgis::AreaUnit unit)
Sets the default area measurement units for the project.
void setTitle(const QString &title)
Sets the project's title.
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
void writeProject(QDomDocument &)
Emitted when the project is being written.
void setFlag(Qgis::ProjectFlag flag, bool enabled=true)
Sets whether a project flag is enabled.
QDateTime lastModified() const
Returns last modified time of the project file as returned by the file system (or other project stora...
bool readLayer(const QDomNode &layerNode)
Reads the layer described in the associated DOM node.
double readDoubleEntry(const QString &scope, const QString &key, double def=0, bool *ok=nullptr) const
Reads a double from the specified scope and key.
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean value to the project file.
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
QDateTime lastSaveDateTime() const
Returns the date and time when the project was last saved.
void projectSaved()
Emitted when the project file has been written and closed.
Q_DECL_DEPRECATED bool trustLayerMetadata() const
Returns true if the trust option is activated, false otherwise.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
void setEllipsoid(const QString &ellipsoid)
Sets the project's ellipsoid from a proj string representation, e.g., "WGS84".
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the project's coordinate transform context, which stores various information regarding which dat...