76 #include <QApplication>
80 #include <QTextStream>
81 #include <QTemporaryFile>
84 #include <QStandardPaths>
86 #include <QRegularExpression>
89 #include <sys/utime.h>
107 QStringList keyTokens = QStringList( scope );
108 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
109 keyTokens += key.split(
'/', QString::SkipEmptyParts );
111 keyTokens += key.split(
'/', Qt::SkipEmptyParts );
115 keyTokens.push_front( QStringLiteral(
"properties" ) );
118 for (
int i = 0; i < keyTokens.size(); ++i )
120 const QString keyToken = keyTokens.at( i );
124 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}])" ) );
125 if ( keyToken.contains( sInvalidRegexp ) )
127 const QString errorString = QObject::tr(
"Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
155 while ( !keySequence.isEmpty() )
159 if ( keySequence.first() == currentProperty->
name() )
162 keySequence.pop_front();
164 if ( 1 == keySequence.count() )
167 return currentProperty->
find( keySequence.front() );
169 else if ( keySequence.isEmpty() )
174 return currentProperty;
176 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
178 if ( nextProperty->
isKey() )
182 else if ( nextProperty->
isValue() && 1 == keySequence.count() )
188 return currentProperty;
226 const QVariant &value,
227 bool &propertiesModified )
236 propertiesModified =
false;
237 while ( ! keySequence.isEmpty() )
241 if ( keySequence.first() == currentProperty->
name() )
244 keySequence.pop_front();
248 if ( 1 == keySequence.count() )
251 if ( !property || property->value() != value )
253 currentProperty->
setValue( keySequence.front(), value );
254 propertiesModified =
true;
257 return currentProperty;
261 else if ( keySequence.isEmpty() )
263 if ( currentProperty->
value() != value )
266 propertiesModified =
true;
269 return currentProperty;
271 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
275 if ( currentProperty )
286 if ( ( newPropertyKey = currentProperty->
addKey( keySequence.first() ) ) )
288 currentProperty = newPropertyKey;
320 while ( ! keySequence.isEmpty() )
324 if ( keySequence.first() == currentProperty->
name() )
327 keySequence.pop_front();
331 if ( 1 == keySequence.count() )
333 currentProperty->
removeKey( keySequence.front() );
338 else if ( keySequence.isEmpty() )
340 previousQgsPropertyKey->
removeKey( currentProperty->
name() );
342 else if ( ( nextProperty = currentProperty->
find( keySequence.first() ) ) )
344 previousQgsPropertyKey = currentProperty;
347 if ( currentProperty )
371 , mCapabilities( capabilities )
374 , mSnappingConfig( this )
390 mProperties.
setName( QStringLiteral(
"properties" ) );
393 mMainAnnotationLayer->setParent(
this );
407 this, [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
409 this, [ = ](
const QList<QgsMapLayer *> &
layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
411 this, [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
413 this, [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
415 [ = ](
const QStringList &
layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
417 [ = ](
const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
419 [ = ]() { mProjectScope.reset(); emit removeAll(); } );
421 [ = ](
const QList< QgsMapLayer * > &
layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
423 [ = ](
QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
431 [ = ](
const QList<QgsMapLayer *> &
layers )
433 for ( const auto &layer : layers )
435 disconnect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
440 [ = ](
const QList<QgsMapLayer *> &layers )
442 for ( const auto &layer : layers )
444 connect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
453 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
454 mStyleSettings->combinedStyleModel()->addDefaultStyle();
461 mIsBeingDeleted =
true;
464 delete mBadLayerHandler;
465 delete mRelationManager;
466 delete mLayerTreeRegistryBridge;
468 if (
this == sProject )
497 mProjectScope.reset();
505 return mMetadata.
title();
512 if ( oldEvaluateDefaultValues != newEvaluateDefaultValues )
515 for (
auto layerIt =
layers.constBegin(); layerIt !=
layers.constEnd(); ++layerIt )
517 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
526 if ( oldTrustLayerMetadata != newTrustLayerMetadata )
529 for (
auto layerIt =
layers.constBegin(); layerIt !=
layers.constEnd(); ++layerIt )
531 if (
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
533 vl->setReadExtentFromXml( newTrustLayerMetadata );
543 Qgis::ProjectFlags newFlags = mFlags;
547 newFlags &= ~(
static_cast< int >( flag ) );
558 return mSaveUserFull;
563 return mSaveDateTime;
578 if ( dirty && mDirtyBlockCount > 0 )
584 if ( mDirty == dirty )
593 if ( path == mHomePath )
597 mCachedHomePath.clear();
598 mProjectScope.reset();
607 const QList<QgsAttributeEditorElement *> elements = parent->
children();
615 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:formcontainers" ).arg( layerId ), container->
name() );
617 if ( !container->
children().empty() )
630 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1" ).arg( layer->layerId() ), layer->name() );
647 translationContext->
registerTranslation( QStringLiteral(
"project:layers:%1:fieldaliases" ).arg( vlayer->
id() ), fieldName );
662 const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->
findGroups();
665 translationContext->
registerTranslation( QStringLiteral(
"project:layergroups" ), groupLayer->name() );
669 const QList<QgsRelation> &relations = mRelationManager->
relations().values();
672 translationContext->
registerTranslation( QStringLiteral(
"project:relations" ), relation.name() );
678 mDataDefinedServerProperties = properties;
683 return mDataDefinedServerProperties;
688 switch ( mTransactionMode )
707 switch ( mTransactionMode )
714 commitErrors.append( tr(
"Trying to commit changes without a layer specified. This only works if the transaction mode is buffered" ) );
723 return mEditBufferGroup.
commitChanges( commitErrors, stopEditing );
731 switch ( mTransactionMode )
738 rollbackErrors.append( tr(
"Trying to roll back changes without a layer specified. This only works if the transaction mode is buffered" ) );
741 bool success = vectorLayer->
rollBack( stopEditing );
747 return mEditBufferGroup.
rollBack( rollbackErrors, stopEditing );
755 if ( name == mFile.fileName() )
758 const QString oldHomePath =
homePath();
760 mFile.setFileName( name );
761 mCachedHomePath.clear();
762 mProjectScope.reset();
766 const QString newHomePath =
homePath();
767 if ( newHomePath != oldHomePath )
775 return mFile.fileName();
780 mOriginalPath = path;
785 return mOriginalPath;
790 return QFileInfo( mFile );
803 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
808 return QFileInfo( mFile.fileName() ).lastModified();
817 if ( mFile.fileName().isEmpty() )
820 return QFileInfo( mFile.fileName() ).absolutePath();
828 if ( mFile.fileName().isEmpty() )
831 return QFileInfo( mFile.fileName() ).absoluteFilePath();
839 storage->readProjectStorageMetadata( mFile.fileName(),
metadata );
844 return QFileInfo( mFile.fileName() ).completeBaseName();
850 const bool absolutePaths =
readBoolEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
859 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
true );
862 writeEntry( QStringLiteral(
"Paths" ), QStringLiteral(
"/Absolute" ),
false );
877 writeEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ),
crs.
isValid() ? 1 : 0 );
878 mProjectScope.reset();
889 if ( adjustEllipsoid )
895 if ( !
crs().isValid() )
898 return readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ),
geoNone() );
903 if (
ellipsoid ==
readEntry( QStringLiteral(
"Measure" ), QStringLiteral(
"/Ellipsoid" ) ) )
906 mProjectScope.reset();
913 return mTransformContext;
918 if ( context == mTransformContext )
921 mTransformContext = context;
922 mProjectScope.reset();
925 for (
auto &layer : mLayerStore.get()->mapLayers() )
927 layer->setTransformContext( context );
934 ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
936 mProjectScope.reset();
937 mFile.setFileName( QString() );
940 mSaveUserFull.clear();
941 mSaveDateTime = QDateTime();
944 mCachedHomePath.clear();
946 mFlags = Qgis::ProjectFlags();
948 mCustomVariables.clear();
951 if ( !mSettings.
value( QStringLiteral(
"projects/anonymize_new_projects" ),
false,
QgsSettings::Core ).toBool() )
962 mEmbeddedLayers.clear();
963 mRelationManager->
clear();
964 mAnnotationManager->clear();
965 mLayoutManager->clear();
966 m3DViewsManager->clear();
967 mBookmarkManager->
clear();
968 mViewSettings->
reset();
969 mTimeSettings->
reset();
970 mElevationProperties->
reset();
971 mDisplaySettings->
reset();
972 mSnappingConfig.
reset();
980 mLabelingEngineSettings->clear();
986 mStyleSettings->
reset();
990 if ( !mIsBeingDeleted )
998 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/Automatic" ),
true );
999 writeEntry( QStringLiteral(
"PositionPrecision" ), QStringLiteral(
"/DecimalPlaces" ), 2 );
1001 const bool defaultRelativePaths = mSettings.
value( QStringLiteral(
"/qgis/defaultProjectPathsRelative" ),
true ).toBool();
1005 writeEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), mSettings.
value( QStringLiteral(
"/qgis/measure/displayunits" ) ).toString() );
1006 writeEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), mSettings.
value( QStringLiteral(
"/qgis/measure/areaunits" ) ).toString() );
1008 int red = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_red" ), 255 ).toInt();
1009 int green = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_green" ), 255 ).toInt();
1010 int blue = mSettings.
value( QStringLiteral(
"qgis/default_canvas_color_blue" ), 255 ).toInt();
1013 red = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_red" ), 255 ).toInt();
1014 green = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_green" ), 255 ).toInt();
1015 blue = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_blue" ), 0 ).toInt();
1016 const int alpha = mSettings.
value( QStringLiteral(
"qgis/default_selection_color_alpha" ), 255 ).toInt();
1022 mRootGroup->
clear();
1023 if ( mMainAnnotationLayer )
1024 mMainAnnotationLayer->
reset();
1026 snapSingleBlocker.release();
1028 if ( !mBlockSnappingUpdates )
1040 topQgsPropertyKey.
dump();
1073 const QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
1075 if ( propertiesElem.isNull() )
1080 const QDomNodeList scopes = propertiesElem.childNodes();
1082 if ( propertiesElem.firstChild().isNull() )
1084 QgsDebugMsg( QStringLiteral(
"empty ``properties'' XML tag ... bailing" ) );
1088 if ( ! project_properties.
readXml( propertiesElem ) )
1090 QgsDebugMsg( QStringLiteral(
"Project_properties.readXml() failed" ) );
1104 const QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral(
"dataDefinedServerProperties" ) );
1105 if ( !ddElem.isNull() )
1107 if ( !ddServerProperties.
readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
1109 QgsDebugMsg( QStringLiteral(
"dataDefinedServerProperties.readXml() failed" ) );
1112 return ddServerProperties;
1119 static void _getTitle(
const QDomDocument &doc, QString &title )
1121 const QDomElement titleNode = doc.documentElement().firstChildElement( QStringLiteral(
"title" ) );
1125 if ( titleNode.isNull() )
1131 if ( !titleNode.hasChildNodes() )
1137 const QDomNode titleTextNode = titleNode.firstChild();
1139 if ( !titleTextNode.isText() )
1145 const QDomText titleText = titleTextNode.toText();
1147 title = titleText.data();
1151 static void readProjectFileMetadata(
const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
1153 const QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1157 QgsDebugMsg( QStringLiteral(
"unable to find qgis element" ) );
1161 const QDomNode qgisNode = nl.item( 0 );
1163 const QDomElement qgisElement = qgisNode.toElement();
1164 lastUser = qgisElement.attribute( QStringLiteral(
"saveUser" ), QString() );
1165 lastUserFull = qgisElement.attribute( QStringLiteral(
"saveUserFull" ), QString() );
1166 lastSaveDateTime = QDateTime::fromString( qgisElement.attribute( QStringLiteral(
"saveDateTime" ), QString() ), Qt::ISODate );
1172 const QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"qgis" ) );
1176 QgsDebugMsg( QStringLiteral(
" unable to find qgis element in project file" ) );
1180 const QDomNode qgisNode = nl.item( 0 );
1182 const QDomElement qgisElement = qgisNode.toElement();
1183 QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral(
"version" ) ) );
1184 return projectVersion;
1190 return mSnappingConfig;
1205 if ( mAvoidIntersectionsMode == mode )
1208 mAvoidIntersectionsMode = mode;
1212 bool QgsProject::_getMapLayers(
const QDomDocument &doc, QList<QDomNode> &brokenNodes, Qgis::ProjectReadFlags flags )
1217 QDomElement layerElement = doc.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) ).firstChildElement( QStringLiteral(
"maplayer" ) );
1221 if ( layerElement.isNull() )
1231 bool returnStatus =
true;
1234 while ( ! layerElement.isNull() )
1237 layerElement = layerElement.nextSiblingElement( QStringLiteral(
"maplayer" ) );
1243 if ( depSorter.hasCycle() )
1247 if ( depSorter.hasMissingDependency() )
1248 returnStatus =
false;
1252 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1253 const int totalLayerCount = sortedLayerNodes.count();
1256 for (
const QDomNode &node : sortedLayerNodes )
1258 const QDomElement element = node.toElement();
1260 const QString name =
translate( QStringLiteral(
"project:layers:%1" ).arg( node.namedItem( QStringLiteral(
"id" ) ).toElement().text() ), node.namedItem( QStringLiteral(
"layername" ) ).toElement().text() );
1261 if ( !name.isNull() )
1262 emit
loadingLayer( tr(
"Loading layer %1" ).arg( name ) );
1264 profile.switchTask( name );
1266 if ( element.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
1268 createEmbeddedLayer( element.attribute( QStringLiteral(
"id" ) ),
readPath( element.attribute( QStringLiteral(
"project" ) ) ), brokenNodes,
true,
flags );
1277 if ( !addLayer( element, brokenNodes, context,
flags ) )
1279 returnStatus =
false;
1282 if ( !messages.isEmpty() )
1291 return returnStatus;
1294 bool QgsProject::addLayer(
const QDomElement &layerElem, QList<QDomNode> &brokenNodes,
QgsReadWriteContext &context, Qgis::ProjectReadFlags flags )
1296 const QString type = layerElem.attribute( QStringLiteral(
"type" ) );
1298 std::unique_ptr<QgsMapLayer>
mapLayer;
1306 QgsDebugMsg( QStringLiteral(
"Unknown layer type \"%1\"" ).arg( type ) );
1310 switch ( layerType )
1314 mapLayer = std::make_unique<QgsVectorLayer>();
1324 mapLayer = std::make_unique<QgsRasterLayer>();
1328 mapLayer = std::make_unique<QgsMeshLayer>();
1332 mapLayer = std::make_unique<QgsVectorTileLayer>();
1336 mapLayer = std::make_unique<QgsPointCloudLayer>();
1341 const QString
typeName = layerElem.attribute( QStringLiteral(
"name" ) );
1349 mapLayer = std::make_unique<QgsAnnotationLayer>( QString(), options );
1356 mapLayer = std::make_unique<QgsGroupLayer>( QString(), options );
1363 QgsDebugMsg( QStringLiteral(
"Unable to create layer" ) );
1371 const QString layerId { layerElem.namedItem( QStringLiteral(
"id" ) ).toElement().text() };
1372 Q_ASSERT( ! layerId.isEmpty() );
1376 QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1377 if (
flags & Qgis::ProjectReadFlag::DontResolveLayers )
1383 profile.switchTask( tr(
"Load layer source" ) );
1386 profile.switchTask( tr(
"Add layer to project" ) );
1387 QList<QgsMapLayer *> newLayers;
1389 if ( layerIsValid ||
flags & Qgis::ProjectReadFlag::DontResolveLayers )
1399 vLayer->joinBuffer()->resolveReferences(
this );
1407 QgsDebugMsg(
"Unable to load " + type +
" layer" );
1408 brokenNodes.push_back( layerElem );
1411 const bool wasEditable = layerElem.attribute( QStringLiteral(
"editable" ), QStringLiteral(
"0" ) ).toInt();
1423 if ( ! layerWasStored )
1428 return layerIsValid;
1433 mFile.setFileName( filename );
1434 mCachedHomePath.clear();
1435 mProjectScope.reset();
1442 const QString filename = mFile.fileName();
1447 QTemporaryFile inDevice;
1448 if ( !inDevice.open() )
1450 setError( tr(
"Unable to open %1" ).arg( inDevice.fileName() ) );
1456 if ( !storage->readProject( filename, &inDevice, context ) )
1458 QString err = tr(
"Unable to open %1" ).arg( filename );
1459 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
1460 if ( !messages.isEmpty() )
1461 err += QStringLiteral(
"\n\n" ) + messages.last().message();
1465 returnValue = unzip( inDevice.fileName(),
flags );
1471 returnValue = unzip( mFile.fileName(),
flags );
1476 const QFileInfo finfo( mFile.fileName() );
1477 const QString attachmentsZip = finfo.absoluteDir().absoluteFilePath( QStringLiteral(
"%1_attachments.zip" ).arg( finfo.completeBaseName() ) );
1478 if ( QFile( attachmentsZip ).exists() )
1480 std::unique_ptr<QgsArchive> archive(
new QgsArchive() );
1481 if ( archive->unzip( attachmentsZip ) )
1483 mArchive = std::move( archive );
1486 returnValue = readProjectFile( mFile.fileName(),
flags );
1492 mFile.setFileName( filename );
1493 mCachedHomePath.clear();
1494 mProjectScope.reset();
1499 mTranslator.reset(
nullptr );
1506 bool QgsProject::readProjectFile(
const QString &filename, Qgis::ProjectReadFlags flags )
1509 ScopedIntIncrementor snapSignalBlock( &mBlockSnappingUpdates );
1511 QFile projectFile( filename );
1519 if ( QFile( QStringLiteral(
"%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1521 mTranslator.reset(
new QTranslator() );
1522 ( void )mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1525 profile.switchTask( tr(
"Reading project file" ) );
1526 std::unique_ptr<QDomDocument> doc(
new QDomDocument( QStringLiteral(
"qgis" ) ) );
1528 if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1530 projectFile.close();
1532 setError( tr(
"Unable to open %1" ).arg( projectFile.fileName() ) );
1541 if ( !doc->setContent( &projectFile, &errorMsg, &line, &column ) )
1543 const QString errorString = tr(
"Project file read error in file %1: %2 at line %3 column %4" )
1544 .arg( projectFile.fileName(), errorMsg ).arg( line ).arg( column );
1548 projectFile.close();
1550 setError( tr(
"%1 for file %2" ).arg( errorString, projectFile.fileName() ) );
1555 projectFile.close();
1563 profile.switchTask( tr(
"Updating project file" ) );
1564 if ( thisVersion > fileVersion )
1566 const bool isOlderMajorVersion = fileVersion.
majorVersion() < thisVersion.majorVersion();
1568 if ( isOlderMajorVersion )
1571 "version of qgis (saved in " + fileVersion.
text() +
1573 "). Problems may occur." );
1584 projectFile.updateRevision( thisVersion );
1586 else if ( fileVersion > thisVersion )
1589 "version of qgis (saved in " + fileVersion.
text() +
1591 "). Problems may occur." );
1597 profile.switchTask( tr(
"Creating auxiliary storage" ) );
1598 const QString
fileName = mFile.fileName();
1599 std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
1600 std::unique_ptr<QgsArchive> archive = std::move( mArchive );
1602 mAuxiliaryStorage = std::move( aStorage );
1603 mArchive = std::move( archive );
1605 mCachedHomePath.clear();
1606 mProjectScope.reset();
1607 mSaveVersion = fileVersion;
1610 profile.switchTask( tr(
"Reading properties" ) );
1619 dump_( mProperties );
1624 _getTitle( *doc, oldTitle );
1626 readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1628 const QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral(
"homePath" ) );
1629 if ( homePathNl.count() > 0 )
1631 const QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1632 const QString
homePath = homePathElement.attribute( QStringLiteral(
"path" ) );
1642 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), 255 ),
1643 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), 255 ) );
1646 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), 255 ),
1647 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), 255 ),
1648 readNumEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), 255 ) );
1657 if (
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectionsEnabled" ), 0 ) )
1660 const QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral(
"projectCrs" ) );
1661 if ( !srsNode.isNull() )
1663 projectCrs.
readXml( srsNode );
1668 const QString projCrsString =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSProj4String" ) );
1669 const long currentCRS =
readNumEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCRSID" ), -1 );
1670 const QString authid =
readEntry( QStringLiteral(
"SpatialRefSys" ), QStringLiteral(
"/ProjectCrs" ) );
1673 const bool isUserAuthId = authid.startsWith( QLatin1String(
"USER:" ), Qt::CaseInsensitive );
1674 if ( !authid.isEmpty() && !isUserAuthId )
1678 if ( !projectCrs.
isValid() && currentCRS >= 0 )
1684 if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.
isValid() || projectCrs.
toProj() != projCrsString ) )
1698 QStringList datumErrors;
1699 if ( !mTransformContext.
readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
1707 const QStringList variableNames =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ) );
1708 const QStringList variableValues =
readListEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ) );
1710 mCustomVariables.clear();
1711 if ( variableNames.length() == variableValues.length() )
1713 for (
int i = 0; i < variableNames.length(); ++i )
1715 mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
1720 QgsMessageLog::logMessage( tr(
"Project Variables Invalid" ), tr(
"The project contains invalid variable settings." ) );
1723 QDomElement element = doc->documentElement().firstChildElement( QStringLiteral(
"projectMetadata" ) );
1725 if ( !element.isNull() )
1734 if ( mMetadata.
title().isEmpty() && !oldTitle.isEmpty() )
1742 element = doc->documentElement().firstChildElement( QStringLiteral(
"transaction" ) );
1743 if ( !element.isNull() )
1750 element = doc->documentElement().firstChildElement( QStringLiteral(
"autotransaction" ) );
1751 if ( ! element.isNull() )
1753 mTransactionMode =
static_cast<Qgis::TransactionMode>( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() );
1757 element = doc->documentElement().firstChildElement( QStringLiteral(
"projectFlags" ) );
1758 if ( !element.isNull() )
1760 mFlags =
qgsFlagKeysToValue( element.attribute( QStringLiteral(
"set" ) ), Qgis::ProjectFlags() );
1765 element = doc->documentElement().firstChildElement( QStringLiteral(
"evaluateDefaultValues" ) );
1766 if ( !element.isNull() )
1768 if ( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1773 element = doc->documentElement().firstChildElement( QStringLiteral(
"trust" ) );
1774 if ( !element.isNull() )
1776 if ( element.attribute( QStringLiteral(
"active" ), QStringLiteral(
"0" ) ).toInt() == 1 )
1782 profile.switchTask( tr(
"Loading layer tree" ) );
1785 QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
1786 if ( !layerTreeElem.isNull() )
1798 mLayerTreeRegistryBridge->
setEnabled(
false );
1801 profile.switchTask( tr(
"Reading map layers" ) );
1803 QList<QDomNode> brokenNodes;
1804 const bool clean = _getMapLayers( *doc, brokenNodes,
flags );
1807 if ( !clean && !(
flags & Qgis::ProjectReadFlag::DontResolveLayers ) )
1809 QgsDebugMsg( QStringLiteral(
"Unable to get map layers from project file." ) );
1811 if ( !brokenNodes.isEmpty() )
1813 QgsDebugMsg(
"there are " + QString::number( brokenNodes.size() ) +
" broken layers" );
1821 mMainAnnotationLayer->
readLayerXml( doc->documentElement().firstChildElement( QStringLiteral(
"main-annotation-layer" ) ), context );
1825 profile.switchTask( tr(
"Loading embedded layers" ) );
1826 loadEmbeddedNodes( mRootGroup,
flags );
1830 profile.switchTask( tr(
"Resolving layer references" ) );
1831 QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
1832 for ( QMap<QString, QgsMapLayer *>::iterator it =
layers.begin(); it !=
layers.end(); ++it )
1834 it.value()->resolveReferences(
this );
1837 mLayerTreeRegistryBridge->
setEnabled(
true );
1840 profile.switchTask( tr(
"Resolving references" ) );
1843 if ( !layerTreeElem.isNull() )
1849 const QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral(
"layer-tree-canvas" ) );
1850 if ( !layerTreeCanvasElem.isNull( ) )
1858 const QStringList requiredLayerIds =
readListEntry( QStringLiteral(
"RequiredLayers" ), QStringLiteral(
"Layers" ) );
1859 for (
const QString &layerId : requiredLayerIds )
1866 const QStringList disabledLayerIds =
readListEntry( QStringLiteral(
"Identify" ), QStringLiteral(
"/disabledLayers" ) );
1867 for (
const QString &layerId : disabledLayerIds )
1880 QString styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Marker" ) );
1881 if ( !styleName.isEmpty() )
1886 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Line" ) );
1887 if ( !styleName.isEmpty() )
1892 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Fill" ) );
1893 if ( !styleName.isEmpty() )
1898 styleName =
readEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/ColorRamp" ) );
1899 if ( !styleName.isEmpty() )
1909 double opacity = 1.0;
1912 double alpha =
readDoubleEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/AlphaInt" ), 255, &ok );
1914 opacity = alpha / 255.0;
1915 double newOpacity =
readDoubleEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Opacity" ), 1.0, &ok );
1917 opacity = newOpacity;
1921 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Marker" ) );
1922 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Line" ) );
1923 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Fill" ) );
1924 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/ColorRamp" ) );
1925 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/RandomColors" ) );
1926 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/AlphaInt" ) );
1927 removeEntry( QStringLiteral(
"DefaultStyles" ), QStringLiteral(
"/Opacity" ) );
1933 if ( !(
flags & Qgis::ProjectReadFlag::DontStoreOriginalStyles ) )
1935 profile.switchTask( tr(
"Storing original layer properties" ) );
1941 profile.switchTask( tr(
"Loading map themes" ) );
1944 mMapThemeCollection->readXml( *doc );
1946 profile.switchTask( tr(
"Loading label settings" ) );
1947 mLabelingEngineSettings->readSettingsFromProject(
this );
1950 profile.switchTask( tr(
"Loading annotations" ) );
1951 mAnnotationManager->readXml( doc->documentElement(), context );
1952 if ( !(
flags & Qgis::ProjectReadFlag::DontLoadLayouts ) )
1954 profile.switchTask( tr(
"Loading layouts" ) );
1955 mLayoutManager->readXml( doc->documentElement(), *doc );
1958 if ( !(
flags & Qgis::ProjectReadFlag::DontLoad3DViews ) )
1960 profile.switchTask( tr(
"Loading 3D Views" ) );
1961 m3DViewsManager->readXml( doc->documentElement(), *doc );
1964 profile.switchTask( tr(
"Loading bookmarks" ) );
1965 mBookmarkManager->
readXml( doc->documentElement(), *doc );
1968 QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
1969 for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
1971 it.value()->setDependencies( it.value()->dependencies() );
1974 profile.switchTask( tr(
"Loading snapping settings" ) );
1978 profile.switchTask( tr(
"Loading view settings" ) );
1981 const QStringList scales =
readListEntry( QStringLiteral(
"Scales" ), QStringLiteral(
"/ScalesList" ) );
1982 QVector<double> res;
1983 for (
const QString &scale : scales )
1985 const QStringList parts = scale.split(
':' );
1986 if ( parts.size() != 2 )
1990 const double denominator = QLocale().toDouble( parts[1], &ok );
1997 const QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectViewSettings" ) );
1998 if ( !viewSettingsElement.isNull() )
1999 mViewSettings->
readXml( viewSettingsElement, context );
2002 profile.switchTask( tr(
"Loading style properties" ) );
2003 const QDomElement styleSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectStyleSettings" ) );
2004 if ( !styleSettingsElement.isNull() )
2005 mStyleSettings->
readXml( styleSettingsElement, context,
flags );
2008 profile.switchTask( tr(
"Loading temporal settings" ) );
2009 const QDomElement timeSettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectTimeSettings" ) );
2010 if ( !timeSettingsElement.isNull() )
2011 mTimeSettings->
readXml( timeSettingsElement, context );
2014 profile.switchTask( tr(
"Loading elevation properties" ) );
2015 const QDomElement elevationPropertiesElement = doc->documentElement().firstChildElement( QStringLiteral(
"ElevationProperties" ) );
2016 if ( !elevationPropertiesElement.isNull() )
2017 mElevationProperties->
readXml( elevationPropertiesElement, context );
2020 profile.switchTask( tr(
"Loading display settings" ) );
2021 const QDomElement displaySettingsElement = doc->documentElement().firstChildElement( QStringLiteral(
"ProjectDisplaySettings" ) );
2022 if ( !displaySettingsElement.isNull() )
2023 mDisplaySettings->
readXml( displaySettingsElement, context );
2025 profile.switchTask( tr(
"Updating variables" ) );
2027 profile.switchTask( tr(
"Updating CRS" ) );
2032 profile.switchTask( tr(
"Reading external settings" ) );
2036 profile.switchTask( tr(
"Updating interface" ) );
2038 snapSignalBlock.release();
2039 if ( !mBlockSnappingUpdates )
2050 QgsDebugMsgLevel( QStringLiteral(
"Project save user: %1" ).arg( mSaveUser ), 2 );
2051 QgsDebugMsgLevel( QStringLiteral(
"Project save user: %1" ).arg( mSaveUserFull ), 2 );
2060 const QString newFileName( QStringLiteral(
"%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
2066 QgsMessageLog::logMessage( tr(
"Translated project saved with locale prefix %1" ).arg( newFileName ), QObject::tr(
"Project translation" ), Qgis::MessageLevel::Success );
2070 QgsMessageLog::logMessage( tr(
"Error saving translated project with locale prefix %1" ).arg( newFileName ), QObject::tr(
"Project translation" ), Qgis::MessageLevel::Critical );
2075 const QMap<QString, QgsMapLayer *> loadedLayers =
mapLayers();
2076 for (
auto it = loadedLayers.constBegin(); it != loadedLayers.constEnd(); ++it )
2078 if ( it.value()->isValid() && it.value()->customProperty( QStringLiteral(
"_layer_was_editable" ) ).toBool() )
2080 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( it.value() ) )
2082 it.value()->removeCustomProperty( QStringLiteral(
"_layer_was_editable" ) );
2090 bool QgsProject::loadEmbeddedNodes(
QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
2093 const auto constChildren = group->
children();
2099 if ( childGroup->
customProperty( QStringLiteral(
"embedded" ) ).toInt() )
2102 const QString projectPath =
readPath( childGroup->
customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
2103 childGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectPath );
2107 QList<QgsLayerTreeNode *> clonedChildren;
2108 const QList<QgsLayerTreeNode *> constChildren = newGroup->
children();
2109 clonedChildren.reserve( constChildren.size() );
2111 clonedChildren << newGroupChild->clone();
2119 loadEmbeddedNodes( childGroup,
flags );
2124 if ( child->customProperty( QStringLiteral(
"embedded" ) ).toInt() )
2126 QList<QDomNode> brokenNodes;
2129 valid = valid &&
false;
2141 return mCustomVariables;
2146 if ( variables == mCustomVariables )
2150 QStringList variableNames;
2151 QStringList variableValues;
2153 QVariantMap::const_iterator it = variables.constBegin();
2154 for ( ; it != variables.constEnd(); ++it )
2156 variableNames << it.key();
2157 variableValues << it.value().toString();
2160 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableNames" ), variableNames );
2161 writeEntry( QStringLiteral(
"Variables" ), QStringLiteral(
"/variableValues" ), variableValues );
2163 mCustomVariables = variables;
2164 mProjectScope.reset();
2171 *mLabelingEngineSettings = settings;
2177 return *mLabelingEngineSettings;
2182 mProjectScope.reset();
2183 return mLayerStore.get();
2188 return mLayerStore.get();
2193 QList<QgsVectorLayer *>
layers;
2194 const QStringList layerIds =
readListEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), QStringList() );
2195 const auto constLayerIds = layerIds;
2196 for (
const QString &layerId : constLayerIds )
2207 list.reserve(
layers.size() );
2209 list << layer->id();
2210 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsList" ), list );
2227 if ( mProjectScope )
2229 std::unique_ptr< QgsExpressionContextScope > projectScope = std::make_unique< QgsExpressionContextScope >( *mProjectScope );
2233 return projectScope.release();
2236 mProjectScope = std::make_unique< QgsExpressionContextScope >( QObject::tr(
"Project" ) );
2240 QVariantMap::const_iterator it = vars.constBegin();
2242 for ( ; it != vars.constEnd(); ++it )
2244 mProjectScope->setVariable( it.key(), it.value(),
true );
2248 if ( projectPath.isEmpty() )
2249 projectPath = mOriginalPath;
2250 const QString projectFolder = QFileInfo( projectPath ).path();
2251 const QString projectFilename = QFileInfo( projectPath ).fileName();
2252 const QString projectBasename =
baseName();
2281 QVariantMap keywords;
2283 for (
auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
2285 keywords.insert( it.key(), it.value() );
2290 QVariantList layersIds;
2292 const QMap<QString, QgsMapLayer *> layersInProject = mLayerStore->mapLayers();
2293 layersIds.reserve( layersInProject.count() );
2294 layers.reserve( layersInProject.count() );
2295 for (
auto it = layersInProject.constBegin(); it != layersInProject.constEnd(); ++it )
2297 layersIds << it.value()->id();
2303 mProjectScope->addFunction( QStringLiteral(
"project_color" ),
new GetNamedProjectColor(
this ) );
2308 void QgsProject::onMapLayersAdded(
const QList<QgsMapLayer *> &layers )
2310 const QMap<QString, QgsMapLayer *> existingMaps =
mapLayers();
2312 const auto constLayers =
layers;
2315 if ( ! layer->isValid() )
2321 for ( QMap<QString, QgsMapLayer *>::const_iterator it = existingMaps.cbegin(); it != existingMaps.cend(); ++it )
2323 const QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
2324 if ( deps.contains( layer->id() ) )
2327 it.value()->setDependencies( deps );
2332 updateTransactionGroups();
2338 void QgsProject::onMapLayersRemoved(
const QList<QgsMapLayer *> &layers )
2344 void QgsProject::cleanTransactionGroups(
bool force )
2346 bool changed =
false;
2347 for ( QMap< QPair< QString, QString>,
QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
2349 if ( tg.value()->isEmpty() || force )
2352 tg = mTransactionGroups.erase( tg );
2364 void QgsProject::updateTransactionGroups()
2366 mEditBufferGroup.
clear();
2368 switch ( mTransactionMode )
2372 cleanTransactionGroups(
true );
2377 cleanTransactionGroups(
true );
2380 cleanTransactionGroups(
false );
2384 bool tgChanged =
false;
2385 const auto constLayers =
mapLayers().values();
2388 if ( ! layer->isValid() )
2391 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
2395 switch ( mTransactionMode )
2412 mTransactionGroups.insert( qMakePair( key, connString ), tg );
2422 mEditBufferGroup.
addLayer( vlayer );
2438 QList<QDomNode> brokenNodes;
2439 if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
2443 const QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
2447 layer->resolveReferences(
this );
2449 if ( layer->isValid() && layer->customProperty( QStringLiteral(
"_layer_was_editable" ) ).toBool() )
2451 layer->startEditing();
2452 layer->removeCustomProperty( QStringLiteral(
"_layer_was_editable" ) );
2462 mFile.setFileName( filename );
2463 mCachedHomePath.clear();
2469 mProjectScope.reset();
2475 const QString storageFilePath { storage->filePath( mFile.fileName() ) };
2476 if ( storageFilePath.isEmpty() )
2482 const QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2483 const QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2485 if ( !zip( tmpZipFilename ) )
2488 QFile tmpZipFile( tmpZipFilename );
2489 if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2491 setError( tr(
"Unable to read file %1" ).arg( tmpZipFilename ) );
2496 if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2498 QString err = tr(
"Unable to save project to storage %1" ).arg( mFile.fileName() );
2499 QList<QgsReadWriteContext::ReadWriteMessage> messages = context.
takeMessages();
2500 if ( !messages.isEmpty() )
2501 err += QStringLiteral(
"\n\n" ) + messages.last().message();
2507 QFile::remove( tmpZipFilename );
2514 return zip( mFile.fileName() );
2520 const bool asOk = saveAuxiliaryStorage();
2521 const bool writeOk = writeProjectFile( mFile.fileName() );
2522 bool attachmentsOk =
true;
2523 if ( !mArchive->files().isEmpty() )
2525 const QFileInfo finfo( mFile.fileName() );
2526 const QString attachmentsZip = finfo.absoluteDir().absoluteFilePath( QStringLiteral(
"%1_attachments.zip" ).arg( finfo.completeBaseName() ) );
2527 attachmentsOk = mArchive->zip( attachmentsZip );
2531 if ( ( !asOk || !attachmentsOk ) && writeOk )
2533 QStringList errorMessage;
2536 const QString err = mAuxiliaryStorage->errorString();
2537 errorMessage.append( tr(
"Unable to save auxiliary storage ('%1')" ).arg( err ) );
2539 if ( !attachmentsOk )
2541 errorMessage.append( tr(
"Unable to save attachments archive" ) );
2543 setError( errorMessage.join(
'\n' ) );
2546 return asOk && writeOk && attachmentsOk;
2550 bool QgsProject::writeProjectFile(
const QString &filename )
2552 QFile projectFile( filename );
2558 const QFileInfo myFileInfo( projectFile );
2559 if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2561 setError( tr(
"%1 is not writable. Please adjust permissions (if possible) and try again." )
2562 .arg( projectFile.fileName() ) );
2570 QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2572 const QDomDocumentType documentType =
2573 QDomImplementation().createDocumentType( QStringLiteral(
"qgis" ), QStringLiteral(
"http://mrcc.com/qgis.dtd" ),
2574 QStringLiteral(
"SYSTEM" ) );
2575 std::unique_ptr<QDomDocument> doc(
new QDomDocument( documentType ) );
2577 QDomElement qgisNode = doc->createElement( QStringLiteral(
"qgis" ) );
2578 qgisNode.setAttribute( QStringLiteral(
"projectname" ),
title() );
2579 qgisNode.setAttribute( QStringLiteral(
"version" ),
Qgis::version() );
2581 if ( !mSettings.
value( QStringLiteral(
"projects/anonymize_saved_projects" ),
false,
QgsSettings::Core ).toBool() )
2585 qgisNode.setAttribute( QStringLiteral(
"saveUser" ), newSaveUser );
2586 qgisNode.setAttribute( QStringLiteral(
"saveUserFull" ), newSaveUserFull );
2587 mSaveUser = newSaveUser;
2588 mSaveUserFull = newSaveUserFull;
2589 mSaveDateTime = QDateTime::currentDateTime();
2590 qgisNode.setAttribute( QStringLiteral(
"saveDateTime" ), mSaveDateTime.toString( Qt::ISODate ) );
2595 mSaveUserFull.clear();
2596 mSaveDateTime = QDateTime();
2598 doc->appendChild( qgisNode );
2601 QDomElement homePathNode = doc->createElement( QStringLiteral(
"homePath" ) );
2602 homePathNode.setAttribute( QStringLiteral(
"path" ), mHomePath );
2603 qgisNode.appendChild( homePathNode );
2606 QDomElement titleNode = doc->createElement( QStringLiteral(
"title" ) );
2607 qgisNode.appendChild( titleNode );
2609 QDomElement transactionNode = doc->createElement( QStringLiteral(
"transaction" ) );
2610 transactionNode.setAttribute( QStringLiteral(
"mode" ),
qgsEnumValueToKey( mTransactionMode ) );
2611 qgisNode.appendChild( transactionNode );
2613 QDomElement flagsNode = doc->createElement( QStringLiteral(
"projectFlags" ) );
2615 qgisNode.appendChild( flagsNode );
2617 const QDomText titleText = doc->createTextNode(
title() );
2618 titleNode.appendChild( titleText );
2621 QDomElement srsNode = doc->createElement( QStringLiteral(
"projectCrs" ) );
2623 qgisNode.appendChild( srsNode );
2630 clonedRoot->
writeXml( qgisNode, context );
2634 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/AvoidIntersectionsMode" ),
static_cast<int>( mAvoidIntersectionsMode ) );
2642 QDomElement annotationLayerNode = doc->createElement( QStringLiteral(
"main-annotation-layer" ) );
2643 mMainAnnotationLayer->
writeLayerXml( annotationLayerNode, *doc, context );
2644 qgisNode.appendChild( annotationLayerNode );
2648 QDomElement projectLayersNode = doc->createElement( QStringLiteral(
"projectlayers" ) );
2650 QMap<QString, QgsMapLayer *>::ConstIterator li =
layers.constBegin();
2651 while ( li !=
layers.end() )
2657 const QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->
id() );
2658 if ( emIt == mEmbeddedLayers.constEnd() )
2660 QDomElement maplayerElem;
2666 maplayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2670 maplayerElem.setAttribute( QStringLiteral(
"editable" ), QStringLiteral(
"1" ) );
2674 QDomDocument document;
2677 maplayerElem = document.firstChildElement();
2681 QgsDebugMsg( QStringLiteral(
"Could not restore layer properties for layer %1" ).arg( ml->
id() ) );
2687 projectLayersNode.appendChild( maplayerElem );
2693 if ( emIt.value().second )
2695 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"maplayer" ) );
2696 mapLayerElem.setAttribute( QStringLiteral(
"embedded" ), 1 );
2697 mapLayerElem.setAttribute( QStringLiteral(
"project" ),
writePath( emIt.value().first ) );
2698 mapLayerElem.setAttribute( QStringLiteral(
"id" ), ml->
id() );
2699 projectLayersNode.appendChild( mapLayerElem );
2706 qgisNode.appendChild( projectLayersNode );
2708 QDomElement layerOrderNode = doc->createElement( QStringLiteral(
"layerorder" ) );
2710 for (
QgsMapLayer *layer : constCustomLayerOrder )
2712 QDomElement mapLayerElem = doc->createElement( QStringLiteral(
"layer" ) );
2713 mapLayerElem.setAttribute( QStringLiteral(
"id" ), layer->id() );
2714 layerOrderNode.appendChild( mapLayerElem );
2716 qgisNode.appendChild( layerOrderNode );
2718 mLabelingEngineSettings->writeSettingsToProject(
this );
2720 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorRedPart" ), mBackgroundColor.red() );
2721 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorGreenPart" ), mBackgroundColor.green() );
2722 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/CanvasColorBluePart" ), mBackgroundColor.blue() );
2724 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorRedPart" ), mSelectionColor.red() );
2725 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorGreenPart" ), mSelectionColor.green() );
2726 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorBluePart" ), mSelectionColor.blue() );
2727 writeEntry( QStringLiteral(
"Gui" ), QStringLiteral(
"/SelectionColorAlphaPart" ), mSelectionColor.alpha() );
2731 dump_( mProperties );
2734 QgsDebugMsgLevel( QStringLiteral(
"there are %1 property scopes" ).arg(
static_cast<int>( mProperties.
count() ) ), 2 );
2739 mProperties.
writeXml( QStringLiteral(
"properties" ), qgisNode, *doc );
2742 QDomElement ddElem = doc->createElement( QStringLiteral(
"dataDefinedServerProperties" ) );
2743 mDataDefinedServerProperties.
writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
2744 qgisNode.appendChild( ddElem );
2746 mMapThemeCollection->writeXml( *doc );
2748 mTransformContext.
writeXml( qgisNode, context );
2750 QDomElement metadataElem = doc->createElement( QStringLiteral(
"projectMetadata" ) );
2752 qgisNode.appendChild( metadataElem );
2754 const QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
2755 qgisNode.appendChild( annotationsElem );
2757 const QDomElement layoutElem = mLayoutManager->writeXml( *doc );
2758 qgisNode.appendChild( layoutElem );
2760 const QDomElement views3DElem = m3DViewsManager->writeXml( *doc );
2761 qgisNode.appendChild( views3DElem );
2763 const QDomElement bookmarkElem = mBookmarkManager->
writeXml( *doc );
2764 qgisNode.appendChild( bookmarkElem );
2766 const QDomElement viewSettingsElem = mViewSettings->
writeXml( *doc, context );
2767 qgisNode.appendChild( viewSettingsElem );
2769 const QDomElement styleSettingsElem = mStyleSettings->
writeXml( *doc, context );
2770 qgisNode.appendChild( styleSettingsElem );
2772 const QDomElement timeSettingsElement = mTimeSettings->
writeXml( *doc, context );
2773 qgisNode.appendChild( timeSettingsElement );
2775 const QDomElement elevationPropertiesElement = mElevationProperties->
writeXml( *doc, context );
2776 qgisNode.appendChild( elevationPropertiesElement );
2778 const QDomElement displaySettingsElem = mDisplaySettings->
writeXml( *doc, context );
2779 qgisNode.appendChild( displaySettingsElem );
2787 QFile backupFile( QStringLiteral(
"%1~" ).arg( filename ) );
2789 ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
2790 ok &= projectFile.open( QIODevice::ReadOnly );
2793 while ( ok && !projectFile.atEnd() )
2795 ba = projectFile.read( 10240 );
2796 ok &= backupFile.write( ba ) == ba.size();
2799 projectFile.close();
2804 setError( tr(
"Unable to create backup file %1" ).arg( backupFile.fileName() ) );
2809 struct utimbuf tb = {
static_cast<time_t
>( fi.lastRead().toSecsSinceEpoch() ),
static_cast<time_t
>( fi.lastModified().toSecsSinceEpoch() ) };
2810 utime( backupFile.fileName().toUtf8().constData(), &tb );
2813 if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
2815 projectFile.close();
2818 setError( tr(
"Unable to save to file %1" ).arg( projectFile.fileName() ) );
2822 QTemporaryFile tempFile;
2823 bool ok = tempFile.open();
2826 QTextStream projectFileStream( &tempFile );
2827 doc->save( projectFileStream, 2 );
2828 ok &= projectFileStream.pos() > -1;
2830 ok &= tempFile.seek( 0 );
2833 while ( ok && !tempFile.atEnd() )
2835 ba = tempFile.read( 10240 );
2836 ok &= projectFile.write( ba ) == ba.size();
2839 ok &= projectFile.error() == QFile::NoError;
2841 projectFile.close();
2848 setError( tr(
"Unable to save to file %1. Your project "
2849 "may be corrupted on disk. Try clearing some space on the volume and "
2850 "check file permissions before pressing save again." )
2851 .arg( projectFile.fileName() ) );
2863 bool propertiesModified;
2864 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2866 if ( propertiesModified )
2874 bool propertiesModified;
2875 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2877 if ( propertiesModified )
2885 bool propertiesModified;
2886 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2888 if ( propertiesModified )
2896 bool propertiesModified;
2897 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2899 if ( propertiesModified )
2907 bool propertiesModified;
2908 const bool success =
addKey_( scope, key, &mProperties, value, propertiesModified );
2910 if ( propertiesModified )
2918 const QStringList &def,
2927 value =
property->value();
2929 const bool valid = QVariant::StringList == value.type();
2935 return value.toStringList();
2957 value =
property->value();
2959 const bool valid = value.canConvert( QVariant::String );
2964 return value.toString();
2981 value =
property->value();
2984 const bool valid = value.canConvert( QVariant::Int );
2993 return value.toInt();
3006 const QVariant value =
property->value();
3008 const bool valid = value.canConvert( QVariant::Double );
3013 return value.toDouble();
3028 const QVariant value =
property->value();
3030 const bool valid = value.canConvert( QVariant::Bool );
3035 return value.toBool();
3045 if (
findKey_( scope, key, mProperties ) )
3051 return !
findKey_( scope, key, mProperties );
3059 QStringList entries;
3061 if ( foundProperty )
3076 QStringList entries;
3078 if ( foundProperty )
3091 dump_( mProperties );
3109 filePath = storage->filePath( mFile.fileName() );
3132 void QgsProject::setError(
const QString &errorMessage )
3134 mErrorMessage = errorMessage;
3139 return mErrorMessage;
3142 void QgsProject::clearError()
3144 setError( QString() );
3149 delete mBadLayerHandler;
3150 mBadLayerHandler = handler;
3155 const QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find(
id );
3156 if ( it == mEmbeddedLayers.constEnd() )
3160 return it.value().first;
3164 bool saveFlag, Qgis::ProjectReadFlags flags )
3168 static QString sPrevProjectFilePath;
3169 static QDateTime sPrevProjectFileTimestamp;
3170 static QDomDocument sProjectDocument;
3172 QString qgsProjectFile = projectFilePath;
3174 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
3176 archive.
unzip( projectFilePath );
3180 const QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
3182 if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
3184 sPrevProjectFilePath.clear();
3186 QFile projectFile( qgsProjectFile );
3187 if ( !projectFile.open( QIODevice::ReadOnly ) )
3192 if ( !sProjectDocument.setContent( &projectFile ) )
3197 sPrevProjectFilePath = projectFilePath;
3198 sPrevProjectFileTimestamp = projectFileTimestamp;
3202 bool useAbsolutePaths =
true;
3204 const QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"properties" ) );
3205 if ( !propertiesElem.isNull() )
3207 const QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral(
"Paths" ) ).firstChildElement( QStringLiteral(
"Absolute" ) );
3208 if ( !absElem.isNull() )
3210 useAbsolutePaths = absElem.text().compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
3215 if ( !useAbsolutePaths )
3220 const QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) );
3221 if ( projectLayersElem.isNull() )
3226 QDomElement mapLayerElem = projectLayersElem.firstChildElement( QStringLiteral(
"maplayer" ) );
3227 while ( ! mapLayerElem.isNull() )
3230 const QString
id = mapLayerElem.firstChildElement( QStringLiteral(
"id" ) ).text();
3231 if (
id == layerId )
3234 if ( mapLayerElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
3239 mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
3241 if ( addLayer( mapLayerElem, brokenNodes, embeddedContext,
flags ) )
3247 mEmbeddedLayers.remove( layerId );
3251 mapLayerElem = mapLayerElem.nextSiblingElement( QStringLiteral(
"maplayer" ) );
3260 QString qgsProjectFile = projectFilePath;
3262 if ( projectFilePath.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
3264 archive.
unzip( projectFilePath );
3269 QFile projectFile( qgsProjectFile );
3270 if ( !projectFile.open( QIODevice::ReadOnly ) )
3275 QDomDocument projectDocument;
3276 if ( !projectDocument.setContent( &projectFile ) )
3288 QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
3289 if ( !layerTreeElem.isNull() )
3299 if ( !group || group->
customProperty( QStringLiteral(
"embedded" ) ).toBool() )
3312 newGroup->
setCustomProperty( QStringLiteral(
"embedded_project" ), projectFilePath );
3315 mLayerTreeRegistryBridge->
setEnabled(
false );
3316 initializeEmbeddedSubtree( projectFilePath, newGroup,
flags );
3317 mLayerTreeRegistryBridge->
setEnabled(
true );
3320 const auto constFindLayerIds = newGroup->
findLayerIds();
3321 for (
const QString &layerId : constFindLayerIds )
3334 void QgsProject::initializeEmbeddedSubtree(
const QString &projectFilePath,
QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
3336 const auto constChildren = group->
children();
3340 child->setCustomProperty( QStringLiteral(
"embedded" ), 1 );
3349 QList<QDomNode> brokenNodes;
3367 writeEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
3373 return readNumEntry( QStringLiteral(
"Digitizing" ), QStringLiteral(
"/TopologicalEditing" ), 0 );
3378 const QString distanceUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/DistanceUnits" ), QString() );
3379 if ( !distanceUnitString.isEmpty() )
3395 const QString areaUnitString =
readEntry( QStringLiteral(
"Measurement" ), QStringLiteral(
"/AreaUnits" ), QString() );
3396 if ( !areaUnitString.isEmpty() )
3412 if ( !mCachedHomePath.isEmpty() )
3413 return mCachedHomePath;
3417 if ( !mHomePath.isEmpty() )
3419 const QFileInfo homeInfo( mHomePath );
3420 if ( !homeInfo.isRelative() )
3422 mCachedHomePath = mHomePath;
3428 mCachedHomePath = pfi.path();
3430 return mCachedHomePath;
3433 if ( !pfi.exists() )
3435 mCachedHomePath = mHomePath;
3439 if ( !mHomePath.isEmpty() )
3442 mCachedHomePath = QDir::cleanPath( pfi.path() +
'/' + mHomePath );
3446 mCachedHomePath = pfi.canonicalPath();
3448 return mCachedHomePath;
3458 return mRelationManager;
3463 return mLayoutManager.get();
3468 return mLayoutManager.get();
3473 return m3DViewsManager.get();
3478 return m3DViewsManager.get();
3483 return mBookmarkManager;
3488 return mBookmarkManager;
3493 return mViewSettings;
3498 return mViewSettings;
3503 return mStyleSettings;
3508 return mStyleSettings;
3513 return mTimeSettings;
3518 return mTimeSettings;
3523 return mElevationProperties;
3528 return mElevationProperties;
3533 return mDisplaySettings;
3538 return mDisplaySettings;
3548 return mMapThemeCollection.get();
3553 return mAnnotationManager.get();
3558 return mAnnotationManager.get();
3563 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
3564 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3569 if (
layers.contains( it.value() ) )
3584 for (
const QString &layerId : layerIds )
3600 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
3630 updateTransactionGroups();
3635 return mTransactionMode;
3644 const auto constLayers =
mapLayers().values();
3647 if ( layer->isEditable() )
3649 QgsLogger::warning( tr(
"Transaction mode can be changed only if all layers are not editable." ) );
3655 updateTransactionGroups();
3661 return mTransactionGroups;
3672 return mLayerStore->count();
3677 return mLayerStore->validCount();
3682 return mLayerStore->mapLayer( layerId );
3687 return mLayerStore->mapLayersByName( layerName );
3692 QList<QgsMapLayer *>
layers;
3693 const auto constMapLayers { mLayerStore->mapLayers() };
3694 for (
const auto &l : constMapLayers )
3696 if ( ! l->shortName().isEmpty() )
3698 if ( l->shortName() == shortName )
3701 else if ( l->name() == shortName )
3709 bool QgsProject::unzip(
const QString &filename, Qgis::ProjectReadFlags flags )
3715 if ( !archive->unzip( filename ) )
3717 setError( tr(
"Unable to unzip file '%1'" ).arg( filename ) );
3722 if ( archive->projectFile().isEmpty() )
3724 setError( tr(
"Zip archive does not provide a project file" ) );
3729 mArchive = std::move( archive );
3746 setError( tr(
"Cannot read unzipped qgs project file" ) );
3756 bool QgsProject::zip(
const QString &filename )
3762 const QString
baseName = QFileInfo( filename ).baseName();
3763 const QString qgsFileName = QStringLiteral(
"%1.qgs" ).arg(
baseName );
3764 QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
3766 bool writeOk =
false;
3767 if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3769 writeOk = writeProjectFile( qgsFile.fileName() );
3776 setError( tr(
"Unable to write temporary qgs file" ) );
3781 const QFileInfo info( qgsFile );
3783 const QString asFileName = info.path() + QDir::separator() + info.completeBaseName() + asExt;
3785 bool auxiliaryStorageSavedOk =
true;
3786 if ( ! saveAuxiliaryStorage( asFileName ) )
3788 const QString err = mAuxiliaryStorage->errorString();
3789 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 ) );
3790 auxiliaryStorageSavedOk =
false;
3793 if ( !mArchive->exists() )
3796 mArchive->unzip( mFile.fileName() );
3799 const QString auxiliaryStorageFile =
static_cast<QgsProjectArchive *
>( mArchive.get() )->auxiliaryStorageFile();
3800 if ( ! auxiliaryStorageFile.isEmpty() )
3802 archive->
addFile( auxiliaryStorageFile );
3811 if ( QFile::exists( asFileName ) )
3813 archive->addFile( asFileName );
3818 archive->addFile( qgsFile.fileName() );
3821 const QStringList &files = mArchive->files();
3822 for (
const QString &file : files )
3824 if ( !file.endsWith( QLatin1String(
".qgs" ), Qt::CaseInsensitive ) && !file.endsWith( asExt, Qt::CaseInsensitive ) )
3826 archive->addFile( file );
3832 if ( !archive->zip( filename ) )
3834 setError( tr(
"Unable to perform zip" ) );
3838 return auxiliaryStorageSavedOk && zipOk;
3847 const QList<QgsMapLayer *> &layers,
3849 bool takeOwnership )
3851 const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers(
layers, takeOwnership ) };
3852 if ( !myResultList.isEmpty() )
3855 for (
auto &l : myResultList )
3865 if ( mAuxiliaryStorage )
3880 mProjectScope.reset();
3882 return myResultList;
3888 bool takeOwnership )
3890 QList<QgsMapLayer *> addedLayers;
3891 addedLayers =
addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
3892 return addedLayers.isEmpty() ? nullptr : addedLayers[0];
3897 mProjectScope.reset();
3898 mLayerStore->removeMapLayers( layerIds );
3903 mProjectScope.reset();
3904 mLayerStore->removeMapLayers(
layers );
3909 mProjectScope.reset();
3910 mLayerStore->removeMapLayer( layerId );
3915 mProjectScope.reset();
3916 mLayerStore->removeMapLayer( layer );
3921 mProjectScope.reset();
3922 return mLayerStore->takeMapLayer( layer );
3927 return mMainAnnotationLayer;
3932 if ( mLayerStore->count() == 0 )
3935 ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
3936 mProjectScope.reset();
3937 mLayerStore->removeAllMapLayers();
3939 snapSingleBlocker.release();
3941 if ( !mBlockSnappingUpdates )
3947 const QMap<QString, QgsMapLayer *>
layers = mLayerStore->mapLayers();
3948 QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin();
3949 for ( ; it !=
layers.constEnd(); ++it )
3951 it.value()->reload();
3957 return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
3962 return mTransactionGroups.value( qMakePair( providerKey, connString ) );
3967 return &mEditBufferGroup;
3976 if ( mSettings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), QStringLiteral(
"NoAction" ),
QgsSettings::App ).toString() == QStringLiteral(
"UseProjectCrs" )
3977 || mSettings.
value( QStringLiteral(
"/projections/unknownCrsBehavior" ), 0,
QgsSettings::App ).toString() == QLatin1String(
"2" ) )
3985 const QString layerDefaultCrs = mSettings.
value( QStringLiteral(
"/Projections/layerDefaultCrs" ),
geoEpsgCrsAuthId() ).toString();
4002 bool QgsProject::saveAuxiliaryStorage(
const QString &filename )
4006 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4011 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
4019 if ( !mAuxiliaryStorage->exists( *
this ) && empty )
4023 else if ( !filename.isEmpty() )
4025 return mAuxiliaryStorage->saveAs( filename );
4029 return mAuxiliaryStorage->saveAs( *
this );
4038 QgsProject::DataDefinedServerProperty::WMSOnlineResource,
4042 return sPropertyDefinitions;
4047 return mAuxiliaryStorage.get();
4052 return mAuxiliaryStorage.get();
4057 const QDir archiveDir( mArchive->dir() );
4058 QTemporaryFile tmpFile( archiveDir.filePath(
"XXXXXX_" + nameTemplate ),
this );
4059 tmpFile.setAutoRemove(
false );
4061 mArchive->addFile( tmpFile.fileName() );
4062 return tmpFile.fileName();
4067 QStringList attachments;
4069 const QStringList files = mArchive->files();
4070 attachments.reserve( files.size() );
4071 for (
const QString &file : files )
4075 attachments.append( file );
4083 return mArchive->removeFile( path );
4088 return QStringLiteral(
"attachment:///%1" ).arg( QFileInfo( attachedFile ).
fileName() );
4093 if ( identifier.startsWith( QLatin1String(
"attachment:///" ) ) )
4095 return QDir( mArchive->dir() ).absoluteFilePath( identifier.mid( 14 ) );
4111 mProjectScope.reset();
4123 for ( QMap<QString, QgsMapLayer *>::const_iterator it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4135 const QMap<QString, QgsMapLayer *> &projectLayers =
mapLayers();
4136 for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
4141 if (
layers.contains( it.value() ) )
4151 QStringList customColors;
4152 QStringList customColorLabels;
4154 QgsNamedColorList::const_iterator colorIt = colors.constBegin();
4155 for ( ; colorIt != colors.constEnd(); ++colorIt )
4158 const QString label = ( *colorIt ).second;
4159 customColors.append( color );
4160 customColorLabels.append( label );
4162 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ), customColors );
4163 writeEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ), customColorLabels );
4164 mProjectScope.reset();
4170 if ( mBackgroundColor == color )
4173 mBackgroundColor = color;
4179 return mBackgroundColor;
4184 if ( mSelectionColor == color )
4187 mSelectionColor = color;
4193 return mSelectionColor;
4227 QString
QgsProject::translate(
const QString &context,
const QString &sourceText,
const char *disambiguation,
int n )
const
4234 QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
4236 if ( result.isEmpty() )
4248 for (
auto it =
layers.constBegin(); it !=
layers.constEnd(); ++it )
4253 if ( !( ( *it )->accept( visitor ) ) )
4262 if ( !mLayoutManager->accept( visitor ) )
4265 if ( !mAnnotationManager->accept( visitor ) )
4272 GetNamedProjectColor::GetNamedProjectColor(
const QgsProject *project )
4279 QStringList colorStrings = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Colors" ) );
4280 const QStringList colorLabels = project->
readListEntry( QStringLiteral(
"Palette" ), QStringLiteral(
"/Labels" ) );
4284 for ( QStringList::iterator it = colorStrings.begin();
4285 it != colorStrings.end(); ++it )
4289 if ( colorLabels.length() > colorIndex )
4291 label = colorLabels.at( colorIndex );
4294 mColors.insert( label.toLower(), color );
4299 GetNamedProjectColor::GetNamedProjectColor(
const QHash<QString, QColor> &colors )
4307 const QString colorName = values.at( 0 ).toString().toLower();
4308 if ( mColors.contains( colorName ) )
4310 return QStringLiteral(
"%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
4318 return new GetNamedProjectColor( mColors );