QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsproject.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsproject.cpp - description
3  -------------------
4  begin : July 23, 2004
5  copyright : (C) 2004 by Mark Coletti
6  email : mcoletti at gmail.com
7 ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsproject.h"
19 
20 #include "qgsdatasourceuri.h"
22 #include "qgslayertree.h"
23 #include "qgslayertreeutils.h"
25 #include "qgslogger.h"
26 #include "qgsmessagelog.h"
27 #include "qgsmaplayerfactory.h"
28 #include "qgspluginlayer.h"
29 #include "qgspluginlayerregistry.h"
31 #include "qgssnappingconfig.h"
32 #include "qgspathresolver.h"
33 #include "qgsprojectstorage.h"
35 #include "qgsprojectversion.h"
36 #include "qgsrasterlayer.h"
37 #include "qgsreadwritecontext.h"
38 #include "qgsrectangle.h"
39 #include "qgsrelationmanager.h"
40 #include "qgsannotationmanager.h"
41 #include "qgsvectorlayerjoininfo.h"
43 #include "qgsmapthemecollection.h"
44 #include "qgslayerdefinition.h"
45 #include "qgsunittypes.h"
46 #include "qgstransaction.h"
47 #include "qgstransactiongroup.h"
48 #include "qgsvectordataprovider.h"
50 #include "qgsmaplayerlistutils_p.h"
51 #include "qgsmeshlayer.h"
52 #include "qgslayoutmanager.h"
53 #include "qgsbookmarkmanager.h"
54 #include "qgsmaplayerstore.h"
55 #include "qgsziputils.h"
56 #include "qgsauxiliarystorage.h"
57 #include "qgssymbollayerutils.h"
58 #include "qgsapplication.h"
60 #include "qgsstyleentityvisitor.h"
61 #include "qgsprojectviewsettings.h"
64 #include "qgsprojecttimesettings.h"
65 #include "qgsvectortilelayer.h"
66 #include "qgsruntimeprofiler.h"
67 #include "qgsannotationlayer.h"
68 #include "qgspointcloudlayer.h"
70 #include "qgsgrouplayer.h"
71 #include "qgsmapviewsmanager.h"
73 #include "qgscombinedstylemodel.h"
74 
75 #include <algorithm>
76 #include <QApplication>
77 #include <QFileInfo>
78 #include <QDomNode>
79 #include <QObject>
80 #include <QTextStream>
81 #include <QTemporaryFile>
82 #include <QDir>
83 #include <QUrl>
84 #include <QStandardPaths>
85 #include <QUuid>
86 #include <QRegularExpression>
87 
88 #ifdef _MSC_VER
89 #include <sys/utime.h>
90 #else
91 #include <utime.h>
92 #endif
93 
94 // canonical project instance
95 QgsProject *QgsProject::sProject = nullptr;
96 
105 QStringList makeKeyTokens_( const QString &scope, const QString &key )
106 {
107  QStringList keyTokens = QStringList( scope );
108 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
109  keyTokens += key.split( '/', QString::SkipEmptyParts );
110 #else
111  keyTokens += key.split( '/', Qt::SkipEmptyParts );
112 #endif
113 
114  // be sure to include the canonical root node
115  keyTokens.push_front( QStringLiteral( "properties" ) );
116 
117  //check validy of keys since an invalid xml name will will be dropped upon saving the xml file. If not valid, we print a message to the console.
118  for ( int i = 0; i < keyTokens.size(); ++i )
119  {
120  const QString keyToken = keyTokens.at( i );
121 
122  //invalid chars in XML are found at http://www.w3.org/TR/REC-xml/#NT-NameChar
123  //note : it seems \x10000-\xEFFFF is valid, but it when added to the regexp, a lot of unwanted characters remain
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 ) )
126  {
127  const QString errorString = QObject::tr( "Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
128  QgsMessageLog::logMessage( errorString, QString(), Qgis::MessageLevel::Critical );
129  }
130  }
131 
132  return keyTokens;
133 }
134 
135 
136 
146 QgsProjectProperty *findKey_( const QString &scope,
147  const QString &key,
148  QgsProjectPropertyKey &rootProperty )
149 {
150  QgsProjectPropertyKey *currentProperty = &rootProperty;
151  QgsProjectProperty *nextProperty; // link to next property down hierarchy
152 
153  QStringList keySequence = makeKeyTokens_( scope, key );
154 
155  while ( !keySequence.isEmpty() )
156  {
157  // if the current head of the sequence list matches the property name,
158  // then traverse down the property hierarchy
159  if ( keySequence.first() == currentProperty->name() )
160  {
161  // remove front key since we're traversing down a level
162  keySequence.pop_front();
163 
164  if ( 1 == keySequence.count() )
165  {
166  // if we have only one key name left, then return the key found
167  return currentProperty->find( keySequence.front() );
168  }
169  else if ( keySequence.isEmpty() )
170  {
171  // if we're out of keys then the current property is the one we
172  // want; i.e., we're in the rate case of being at the top-most
173  // property node
174  return currentProperty;
175  }
176  else if ( ( nextProperty = currentProperty->find( keySequence.first() ) ) )
177  {
178  if ( nextProperty->isKey() )
179  {
180  currentProperty = static_cast<QgsProjectPropertyKey *>( nextProperty );
181  }
182  else if ( nextProperty->isValue() && 1 == keySequence.count() )
183  {
184  // it may be that this may be one of several property value
185  // nodes keyed by QDict string; if this is the last remaining
186  // key token and the next property is a value node, then
187  // that's the situation, so return the currentProperty
188  return currentProperty;
189  }
190  else
191  {
192  // QgsProjectPropertyValue not Key, so return null
193  return nullptr;
194  }
195  }
196  else
197  {
198  // if the next key down isn't found
199  // then the overall key sequence doesn't exist
200  return nullptr;
201  }
202  }
203  else
204  {
205  return nullptr;
206  }
207  }
208 
209  return nullptr;
210 }
211 
212 
213 
223 QgsProjectProperty *addKey_( const QString &scope,
224  const QString &key,
225  QgsProjectPropertyKey *rootProperty,
226  const QVariant &value,
227  bool &propertiesModified )
228 {
229  QStringList keySequence = makeKeyTokens_( scope, key );
230 
231  // cursor through property key/value hierarchy
232  QgsProjectPropertyKey *currentProperty = rootProperty;
233  QgsProjectProperty *nextProperty; // link to next property down hierarchy
234  QgsProjectPropertyKey *newPropertyKey = nullptr;
235 
236  propertiesModified = false;
237  while ( ! keySequence.isEmpty() )
238  {
239  // if the current head of the sequence list matches the property name,
240  // then traverse down the property hierarchy
241  if ( keySequence.first() == currentProperty->name() )
242  {
243  // remove front key since we're traversing down a level
244  keySequence.pop_front();
245 
246  // if key sequence has one last element, then we use that as the
247  // name to store the value
248  if ( 1 == keySequence.count() )
249  {
250  QgsProjectProperty *property = currentProperty->find( keySequence.front() );
251  if ( !property || property->value() != value )
252  {
253  currentProperty->setValue( keySequence.front(), value );
254  propertiesModified = true;
255  }
256 
257  return currentProperty;
258  }
259  // we're at the top element if popping the keySequence element
260  // will leave it empty; in that case, just add the key
261  else if ( keySequence.isEmpty() )
262  {
263  if ( currentProperty->value() != value )
264  {
265  currentProperty->setValue( value );
266  propertiesModified = true;
267  }
268 
269  return currentProperty;
270  }
271  else if ( ( nextProperty = currentProperty->find( keySequence.first() ) ) )
272  {
273  currentProperty = dynamic_cast<QgsProjectPropertyKey *>( nextProperty );
274 
275  if ( currentProperty )
276  {
277  continue;
278  }
279  else // QgsProjectPropertyValue not Key, so return null
280  {
281  return nullptr;
282  }
283  }
284  else // the next subkey doesn't exist, so add it
285  {
286  if ( ( newPropertyKey = currentProperty->addKey( keySequence.first() ) ) )
287  {
288  currentProperty = newPropertyKey;
289  }
290  continue;
291  }
292  }
293  else
294  {
295  return nullptr;
296  }
297  }
298 
299  return nullptr;
300 }
301 
309 void removeKey_( const QString &scope,
310  const QString &key,
311  QgsProjectPropertyKey &rootProperty )
312 {
313  QgsProjectPropertyKey *currentProperty = &rootProperty;
314 
315  QgsProjectProperty *nextProperty = nullptr; // link to next property down hierarchy
316  QgsProjectPropertyKey *previousQgsPropertyKey = nullptr; // link to previous property up hierarchy
317 
318  QStringList keySequence = makeKeyTokens_( scope, key );
319 
320  while ( ! keySequence.isEmpty() )
321  {
322  // if the current head of the sequence list matches the property name,
323  // then traverse down the property hierarchy
324  if ( keySequence.first() == currentProperty->name() )
325  {
326  // remove front key since we're traversing down a level
327  keySequence.pop_front();
328 
329  // if we have only one key name left, then try to remove the key
330  // with that name
331  if ( 1 == keySequence.count() )
332  {
333  currentProperty->removeKey( keySequence.front() );
334  }
335  // if we're out of keys then the current property is the one we
336  // want to remove, but we can't delete it directly; we need to
337  // delete it from the parent property key container
338  else if ( keySequence.isEmpty() )
339  {
340  previousQgsPropertyKey->removeKey( currentProperty->name() );
341  }
342  else if ( ( nextProperty = currentProperty->find( keySequence.first() ) ) )
343  {
344  previousQgsPropertyKey = currentProperty;
345  currentProperty = dynamic_cast<QgsProjectPropertyKey *>( nextProperty );
346 
347  if ( currentProperty )
348  {
349  continue;
350  }
351  else // QgsProjectPropertyValue not Key, so return null
352  {
353  return;
354  }
355  }
356  else // if the next key down isn't found
357  {
358  // then the overall key sequence doesn't exist
359  return;
360  }
361  }
362  else
363  {
364  return;
365  }
366  }
367 }
368 
369 QgsProject::QgsProject( QObject *parent, Qgis::ProjectCapabilities capabilities )
370  : QObject( parent )
371  , mCapabilities( capabilities )
372  , mLayerStore( new QgsMapLayerStore( this ) )
373  , mBadLayerHandler( new QgsProjectBadLayerHandler() )
374  , mSnappingConfig( this )
375  , mRelationManager( new QgsRelationManager( this ) )
376  , mAnnotationManager( new QgsAnnotationManager( this ) )
377  , mLayoutManager( new QgsLayoutManager( this ) )
378  , m3DViewsManager( new QgsMapViewsManager( this ) )
379  , mBookmarkManager( QgsBookmarkManager::createProjectBasedManager( this ) )
380  , mViewSettings( new QgsProjectViewSettings( this ) )
381  , mStyleSettings( new QgsProjectStyleSettings( this ) )
382  , mTimeSettings( new QgsProjectTimeSettings( this ) )
383  , mElevationProperties( new QgsProjectElevationProperties( this ) )
384  , mDisplaySettings( new QgsProjectDisplaySettings( this ) )
385  , mRootGroup( new QgsLayerTree )
386  , mLabelingEngineSettings( new QgsLabelingEngineSettings )
387  , mArchive( new QgsArchive() )
388  , mAuxiliaryStorage( new QgsAuxiliaryStorage() )
389 {
390  mProperties.setName( QStringLiteral( "properties" ) );
391 
392  mMainAnnotationLayer = new QgsAnnotationLayer( QObject::tr( "Annotations" ), QgsAnnotationLayer::LayerOptions( mTransformContext ) );
393  mMainAnnotationLayer->setParent( this );
394 
395  clear();
396 
397  // bind the layer tree to the map layer registry.
398  // whenever layers are added to or removed from the registry,
399  // layer tree will be updated
400  mLayerTreeRegistryBridge = new QgsLayerTreeRegistryBridge( mRootGroup, this, this );
401  connect( this, &QgsProject::layersAdded, this, &QgsProject::onMapLayersAdded );
402  connect( this, &QgsProject::layersRemoved, this, [ = ] { cleanTransactionGroups(); } );
403  connect( this, qOverload< const QList<QgsMapLayer *> & >( &QgsProject::layersWillBeRemoved ), this, &QgsProject::onMapLayersRemoved );
404 
405  // proxy map layer store signals to this
406  connect( mLayerStore.get(), qOverload<const QStringList &>( &QgsMapLayerStore::layersWillBeRemoved ),
407  this, [ = ]( const QStringList & layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
408  connect( mLayerStore.get(), qOverload< const QList<QgsMapLayer *> & >( &QgsMapLayerStore::layersWillBeRemoved ),
409  this, [ = ]( const QList<QgsMapLayer *> &layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
410  connect( mLayerStore.get(), qOverload< const QString & >( &QgsMapLayerStore::layerWillBeRemoved ),
411  this, [ = ]( const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
412  connect( mLayerStore.get(), qOverload< QgsMapLayer * >( &QgsMapLayerStore::layerWillBeRemoved ),
413  this, [ = ]( QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
414  connect( mLayerStore.get(), qOverload<const QStringList & >( &QgsMapLayerStore::layersRemoved ), this,
415  [ = ]( const QStringList & layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
416  connect( mLayerStore.get(), &QgsMapLayerStore::layerRemoved, this,
417  [ = ]( const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
418  connect( mLayerStore.get(), &QgsMapLayerStore::allLayersRemoved, this,
419  [ = ]() { mProjectScope.reset(); emit removeAll(); } );
420  connect( mLayerStore.get(), &QgsMapLayerStore::layersAdded, this,
421  [ = ]( const QList< QgsMapLayer * > &layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
422  connect( mLayerStore.get(), &QgsMapLayerStore::layerWasAdded, this,
423  [ = ]( QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
424 
425  if ( QgsApplication::instance() )
426  {
428  }
429 
430  connect( mLayerStore.get(), qOverload< const QList<QgsMapLayer *> & >( &QgsMapLayerStore::layersWillBeRemoved ), this,
431  [ = ]( const QList<QgsMapLayer *> &layers )
432  {
433  for ( const auto &layer : layers )
434  {
435  disconnect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
436  }
437  }
438  );
439  connect( mLayerStore.get(), qOverload< const QList<QgsMapLayer *> & >( &QgsMapLayerStore::layersAdded ), this,
440  [ = ]( const QList<QgsMapLayer *> &layers )
441  {
442  for ( const auto &layer : layers )
443  {
444  connect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
445  }
446  }
447  );
448 
452 
453 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
454  mStyleSettings->combinedStyleModel()->addDefaultStyle();
455 #endif
456 }
457 
458 
460 {
461  mIsBeingDeleted = true;
462 
463  clear();
464  delete mBadLayerHandler;
465  delete mRelationManager;
466  delete mLayerTreeRegistryBridge;
467  delete mRootGroup;
468  if ( this == sProject )
469  {
470  sProject = nullptr;
471  }
472 }
473 
475 {
476  sProject = project;
477 }
478 
479 
481 {
482  if ( !sProject )
483  {
484  sProject = new QgsProject;
485 
487  }
488  return sProject;
489 }
490 
491 void QgsProject::setTitle( const QString &title )
492 {
493  if ( title == mMetadata.title() )
494  return;
495 
496  mMetadata.setTitle( title );
497  mProjectScope.reset();
498  emit metadataChanged();
499 
500  setDirty( true );
501 }
502 
503 QString QgsProject::title() const
504 {
505  return mMetadata.title();
506 }
507 
508 void QgsProject::setFlags( Qgis::ProjectFlags flags )
509 {
510  const bool oldEvaluateDefaultValues = mFlags & Qgis::ProjectFlag::EvaluateDefaultValuesOnProviderSide;
511  const bool newEvaluateDefaultValues = flags & Qgis::ProjectFlag::EvaluateDefaultValuesOnProviderSide;
512  if ( oldEvaluateDefaultValues != newEvaluateDefaultValues )
513  {
514  const QMap<QString, QgsMapLayer *> layers = mapLayers();
515  for ( auto layerIt = layers.constBegin(); layerIt != layers.constEnd(); ++layerIt )
516  {
517  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
518  {
519  vl->dataProvider()->setProviderProperty( QgsVectorDataProvider::EvaluateDefaultValues, newEvaluateDefaultValues );
520  }
521  }
522  }
523 
524  const bool oldTrustLayerMetadata = mFlags & Qgis::ProjectFlag::TrustStoredLayerStatistics;
525  const bool newTrustLayerMetadata = flags & Qgis::ProjectFlag::TrustStoredLayerStatistics;
526  if ( oldTrustLayerMetadata != newTrustLayerMetadata )
527  {
528  const QMap<QString, QgsMapLayer *> layers = mapLayers();
529  for ( auto layerIt = layers.constBegin(); layerIt != layers.constEnd(); ++layerIt )
530  {
531  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() ) )
532  {
533  vl->setReadExtentFromXml( newTrustLayerMetadata );
534  }
535  }
536  }
537 
538  mFlags = flags;
539 }
540 
541 void QgsProject::setFlag( Qgis::ProjectFlag flag, bool enabled )
542 {
543  Qgis::ProjectFlags newFlags = mFlags;
544  if ( enabled )
545  newFlags |= flag;
546  else
547  newFlags &= ~( static_cast< int >( flag ) );
548  setFlags( newFlags );
549 }
550 
551 QString QgsProject::saveUser() const
552 {
553  return mSaveUser;
554 }
555 
557 {
558  return mSaveUserFull;
559 }
560 
562 {
563  return mSaveDateTime;
564 }
565 
567 {
568  return mSaveVersion;
569 }
570 
572 {
573  return mDirty;
574 }
575 
576 void QgsProject::setDirty( const bool dirty )
577 {
578  if ( dirty && mDirtyBlockCount > 0 )
579  return;
580 
581  if ( dirty )
582  emit dirtySet();
583 
584  if ( mDirty == dirty )
585  return;
586 
587  mDirty = dirty;
588  emit isDirtyChanged( mDirty );
589 }
590 
591 void QgsProject::setPresetHomePath( const QString &path )
592 {
593  if ( path == mHomePath )
594  return;
595 
596  mHomePath = path;
597  mCachedHomePath.clear();
598  mProjectScope.reset();
599 
600  emit homePathChanged();
601 
602  setDirty( true );
603 }
604 
605 void QgsProject::registerTranslatableContainers( QgsTranslationContext *translationContext, QgsAttributeEditorContainer *parent, const QString &layerId )
606 {
607  const QList<QgsAttributeEditorElement *> elements = parent->children();
608 
609  for ( QgsAttributeEditorElement *element : elements )
610  {
611  if ( element->type() == QgsAttributeEditorElement::AeTypeContainer )
612  {
613  QgsAttributeEditorContainer *container = dynamic_cast<QgsAttributeEditorContainer *>( element );
614 
615  translationContext->registerTranslation( QStringLiteral( "project:layers:%1:formcontainers" ).arg( layerId ), container->name() );
616 
617  if ( !container->children().empty() )
618  registerTranslatableContainers( translationContext, container, layerId );
619  }
620  }
621 }
622 
624 {
625  //register layers
626  const QList<QgsLayerTreeLayer *> layers = mRootGroup->findLayers();
627 
628  for ( const QgsLayerTreeLayer *layer : layers )
629  {
630  translationContext->registerTranslation( QStringLiteral( "project:layers:%1" ).arg( layer->layerId() ), layer->name() );
631 
632  QgsMapLayer *mapLayer = layer->layer();
634  {
635  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mapLayer );
636 
637  //register aliases and fields
638  const QgsFields fields = vlayer->fields();
639  for ( const QgsField &field : fields )
640  {
641  QString fieldName;
642  if ( field.alias().isEmpty() )
643  fieldName = field.name();
644  else
645  fieldName = field.alias();
646 
647  translationContext->registerTranslation( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( vlayer->id() ), fieldName );
648 
649  if ( field.editorWidgetSetup().type() == QLatin1String( "ValueRelation" ) )
650  {
651  translationContext->registerTranslation( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( vlayer->id(), field.name() ), field.editorWidgetSetup().config().value( QStringLiteral( "Value" ) ).toString() );
652  }
653  }
654 
655  //register formcontainers
656  registerTranslatableContainers( translationContext, vlayer->editFormConfig().invisibleRootContainer(), vlayer->id() );
657 
658  }
659  }
660 
661  //register layergroups
662  const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->findGroups();
663  for ( const QgsLayerTreeGroup *groupLayer : groupLayers )
664  {
665  translationContext->registerTranslation( QStringLiteral( "project:layergroups" ), groupLayer->name() );
666  }
667 
668  //register relations
669  const QList<QgsRelation> &relations = mRelationManager->relations().values();
670  for ( const QgsRelation &relation : relations )
671  {
672  translationContext->registerTranslation( QStringLiteral( "project:relations" ), relation.name() );
673  }
674 }
675 
677 {
678  mDataDefinedServerProperties = properties;
679 }
680 
682 {
683  return mDataDefinedServerProperties;
684 }
685 
687 {
688  switch ( mTransactionMode )
689  {
692  {
693  if ( ! vectorLayer )
694  return false;
695  return vectorLayer->startEditing();
696  }
697 
699  return mEditBufferGroup.startEditing();
700  }
701 
702  return false;
703 }
704 
705 bool QgsProject::commitChanges( QStringList &commitErrors, bool stopEditing, QgsVectorLayer *vectorLayer )
706 {
707  switch ( mTransactionMode )
708  {
711  {
712  if ( ! vectorLayer )
713  {
714  commitErrors.append( tr( "Trying to commit changes without a layer specified. This only works if the transaction mode is buffered" ) );
715  return false;
716  }
717  bool success = vectorLayer->commitChanges( stopEditing );
718  commitErrors = vectorLayer->commitErrors();
719  return success;
720  }
721 
723  return mEditBufferGroup.commitChanges( commitErrors, stopEditing );
724  }
725 
726  return false;
727 }
728 
729 bool QgsProject::rollBack( QStringList &rollbackErrors, bool stopEditing, QgsVectorLayer *vectorLayer )
730 {
731  switch ( mTransactionMode )
732  {
735  {
736  if ( ! vectorLayer )
737  {
738  rollbackErrors.append( tr( "Trying to roll back changes without a layer specified. This only works if the transaction mode is buffered" ) );
739  return false;
740  }
741  bool success = vectorLayer->rollBack( stopEditing );
742  rollbackErrors = vectorLayer->commitErrors();
743  return success;
744  }
745 
747  return mEditBufferGroup.rollBack( rollbackErrors, stopEditing );
748  }
749 
750  return false;
751 }
752 
753 void QgsProject::setFileName( const QString &name )
754 {
755  if ( name == mFile.fileName() )
756  return;
757 
758  const QString oldHomePath = homePath();
759 
760  mFile.setFileName( name );
761  mCachedHomePath.clear();
762  mProjectScope.reset();
763 
764  emit fileNameChanged();
765 
766  const QString newHomePath = homePath();
767  if ( newHomePath != oldHomePath )
768  emit homePathChanged();
769 
770  setDirty( true );
771 }
772 
773 QString QgsProject::fileName() const
774 {
775  return mFile.fileName();
776 }
777 
778 void QgsProject::setOriginalPath( const QString &path )
779 {
780  mOriginalPath = path;
781 }
782 
784 {
785  return mOriginalPath;
786 }
787 
788 QFileInfo QgsProject::fileInfo() const
789 {
790  return QFileInfo( mFile );
791 }
792 
794 {
796 }
797 
798 QDateTime QgsProject::lastModified() const
799 {
800  if ( QgsProjectStorage *storage = projectStorage() )
801  {
803  storage->readProjectStorageMetadata( mFile.fileName(), metadata );
804  return metadata.lastModified;
805  }
806  else
807  {
808  return QFileInfo( mFile.fileName() ).lastModified();
809  }
810 }
811 
813 {
814  if ( projectStorage() )
815  return QString();
816 
817  if ( mFile.fileName().isEmpty() )
818  return QString(); // this is to protect ourselves from getting current directory from QFileInfo::absoluteFilePath()
819 
820  return QFileInfo( mFile.fileName() ).absolutePath();
821 }
822 
824 {
825  if ( projectStorage() )
826  return QString();
827 
828  if ( mFile.fileName().isEmpty() )
829  return QString(); // this is to protect ourselves from getting current directory from QFileInfo::absoluteFilePath()
830 
831  return QFileInfo( mFile.fileName() ).absoluteFilePath();
832 }
833 
834 QString QgsProject::baseName() const
835 {
836  if ( QgsProjectStorage *storage = projectStorage() )
837  {
839  storage->readProjectStorageMetadata( mFile.fileName(), metadata );
840  return metadata.name;
841  }
842  else
843  {
844  return QFileInfo( mFile.fileName() ).completeBaseName();
845  }
846 }
847 
849 {
850  const bool absolutePaths = readBoolEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), false );
852 }
853 
855 {
856  switch ( type )
857  {
859  writeEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), true );
860  break;
862  writeEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), false );
863  break;
864  }
865 }
866 
868 {
869  return mCrs;
870 }
871 
872 void QgsProject::setCrs( const QgsCoordinateReferenceSystem &crs, bool adjustEllipsoid )
873 {
874  if ( crs != mCrs )
875  {
876  mCrs = crs;
877  writeEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectionsEnabled" ), crs.isValid() ? 1 : 0 );
878  mProjectScope.reset();
879 
880  // if annotation layer doesn't have a crs (i.e. in a newly created project), it should
881  // initially inherit the project CRS
882  if ( !mMainAnnotationLayer->crs().isValid() || mMainAnnotationLayer->isEmpty() )
883  mMainAnnotationLayer->setCrs( crs );
884 
885  setDirty( true );
886  emit crsChanged();
887  }
888 
889  if ( adjustEllipsoid )
891 }
892 
893 QString QgsProject::ellipsoid() const
894 {
895  if ( !crs().isValid() )
896  return geoNone();
897 
898  return readEntry( QStringLiteral( "Measure" ), QStringLiteral( "/Ellipsoid" ), geoNone() );
899 }
900 
901 void QgsProject::setEllipsoid( const QString &ellipsoid )
902 {
903  if ( ellipsoid == readEntry( QStringLiteral( "Measure" ), QStringLiteral( "/Ellipsoid" ) ) )
904  return;
905 
906  mProjectScope.reset();
907  writeEntry( QStringLiteral( "Measure" ), QStringLiteral( "/Ellipsoid" ), ellipsoid );
908  emit ellipsoidChanged( ellipsoid );
909 }
910 
912 {
913  return mTransformContext;
914 }
915 
917 {
918  if ( context == mTransformContext )
919  return;
920 
921  mTransformContext = context;
922  mProjectScope.reset();
923 
924  mMainAnnotationLayer->setTransformContext( context );
925  for ( auto &layer : mLayerStore.get()->mapLayers() )
926  {
927  layer->setTransformContext( context );
928  }
930 }
931 
933 {
934  ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
935 
936  mProjectScope.reset();
937  mFile.setFileName( QString() );
938  mProperties.clearKeys();
939  mSaveUser.clear();
940  mSaveUserFull.clear();
941  mSaveDateTime = QDateTime();
942  mSaveVersion = QgsProjectVersion();
943  mHomePath.clear();
944  mCachedHomePath.clear();
945  mTransactionMode = Qgis::TransactionMode::Disabled;
946  mFlags = Qgis::ProjectFlags();
947  mDirty = false;
948  mCustomVariables.clear();
950  mMetadata = QgsProjectMetadata();
951  if ( !mSettings.value( QStringLiteral( "projects/anonymize_new_projects" ), false, QgsSettings::Core ).toBool() )
952  {
953  mMetadata.setCreationDateTime( QDateTime::currentDateTime() );
955  }
956  emit metadataChanged();
957 
959  context.readSettings();
960  setTransformContext( context );
961 
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();
973  mAvoidIntersectionsMode = Qgis::AvoidIntersectionsMode::AllowIntersections;
976 
977  mMapThemeCollection.reset( new QgsMapThemeCollection( this ) );
979 
980  mLabelingEngineSettings->clear();
981 
982  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage() );
983  mArchive.reset( new QgsArchive() );
984 
985  // must happen after archive reset!
986  mStyleSettings->reset();
987 
989 
990  if ( !mIsBeingDeleted )
991  {
992  // possibly other signals should also not be thrown on destruction -- e.g. labelEngineSettingsChanged, etc.
993  emit projectColorsChanged();
994  }
995 
996  // reset some default project properties
997  // XXX THESE SHOULD BE MOVED TO STATUSBAR RELATED SOURCE
998  writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ), true );
999  writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ), 2 );
1000 
1001  const bool defaultRelativePaths = mSettings.value( QStringLiteral( "/qgis/defaultProjectPathsRelative" ), true ).toBool();
1003 
1004  //copy default units to project
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() );
1007 
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();
1011  setBackgroundColor( QColor( red, green, blue ) );
1012 
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();
1017  setSelectionColor( QColor( red, green, blue, alpha ) );
1018 
1019  mSnappingConfig.clearIndividualLayerSettings();
1020 
1022  mRootGroup->clear();
1023  if ( mMainAnnotationLayer )
1024  mMainAnnotationLayer->reset();
1025 
1026  snapSingleBlocker.release();
1027 
1028  if ( !mBlockSnappingUpdates )
1029  emit snappingConfigChanged( mSnappingConfig );
1030 
1031  setDirty( false );
1032  emit homePathChanged();
1033  emit cleared();
1034 }
1035 
1036 // basically a debugging tool to dump property list values
1037 void dump_( const QgsProjectPropertyKey &topQgsPropertyKey )
1038 {
1039  QgsDebugMsgLevel( QStringLiteral( "current properties:" ), 3 );
1040  topQgsPropertyKey.dump();
1041 }
1042 
1071 void _getProperties( const QDomDocument &doc, QgsProjectPropertyKey &project_properties )
1072 {
1073  const QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral( "properties" ) );
1074 
1075  if ( propertiesElem.isNull() ) // no properties found, so we're done
1076  {
1077  return;
1078  }
1079 
1080  const QDomNodeList scopes = propertiesElem.childNodes();
1081 
1082  if ( propertiesElem.firstChild().isNull() )
1083  {
1084  QgsDebugMsg( QStringLiteral( "empty ``properties'' XML tag ... bailing" ) );
1085  return;
1086  }
1087 
1088  if ( ! project_properties.readXml( propertiesElem ) )
1089  {
1090  QgsDebugMsg( QStringLiteral( "Project_properties.readXml() failed" ) );
1091  }
1092 }
1093 
1100 QgsPropertyCollection getDataDefinedServerProperties( const QDomDocument &doc, const QgsPropertiesDefinition &dataDefinedServerPropertyDefinitions )
1101 {
1102  QgsPropertyCollection ddServerProperties;
1103  // Read data defined server properties
1104  const QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral( "dataDefinedServerProperties" ) );
1105  if ( !ddElem.isNull() )
1106  {
1107  if ( !ddServerProperties.readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
1108  {
1109  QgsDebugMsg( QStringLiteral( "dataDefinedServerProperties.readXml() failed" ) );
1110  }
1111  }
1112  return ddServerProperties;
1113 }
1114 
1119 static void _getTitle( const QDomDocument &doc, QString &title )
1120 {
1121  const QDomElement titleNode = doc.documentElement().firstChildElement( QStringLiteral( "title" ) );
1122 
1123  title.clear(); // by default the title will be empty
1124 
1125  if ( titleNode.isNull() )
1126  {
1127  QgsDebugMsgLevel( QStringLiteral( "unable to find title element" ), 2 );
1128  return;
1129  }
1130 
1131  if ( !titleNode.hasChildNodes() ) // if not, then there's no actual text
1132  {
1133  QgsDebugMsgLevel( QStringLiteral( "unable to find title element" ), 2 );
1134  return;
1135  }
1136 
1137  const QDomNode titleTextNode = titleNode.firstChild(); // should only have one child
1138 
1139  if ( !titleTextNode.isText() )
1140  {
1141  QgsDebugMsgLevel( QStringLiteral( "unable to find title element" ), 2 );
1142  return;
1143  }
1144 
1145  const QDomText titleText = titleTextNode.toText();
1146 
1147  title = titleText.data();
1148 
1149 }
1150 
1151 static void readProjectFileMetadata( const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
1152 {
1153  const QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
1154 
1155  if ( !nl.count() )
1156  {
1157  QgsDebugMsg( QStringLiteral( "unable to find qgis element" ) );
1158  return;
1159  }
1160 
1161  const QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element OK
1162 
1163  const QDomElement qgisElement = qgisNode.toElement(); // qgis node should be element
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 );
1167 }
1168 
1169 
1170 QgsProjectVersion getVersion( const QDomDocument &doc )
1171 {
1172  const QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
1173 
1174  if ( !nl.count() )
1175  {
1176  QgsDebugMsg( QStringLiteral( " unable to find qgis element in project file" ) );
1177  return QgsProjectVersion( 0, 0, 0, QString() );
1178  }
1179 
1180  const QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element OK
1181 
1182  const QDomElement qgisElement = qgisNode.toElement(); // qgis node should be element
1183  QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral( "version" ) ) );
1184  return projectVersion;
1185 }
1186 
1187 
1189 {
1190  return mSnappingConfig;
1191 }
1192 
1194 {
1195  if ( mSnappingConfig == snappingConfig )
1196  return;
1197 
1198  mSnappingConfig = snappingConfig;
1199  setDirty( true );
1200  emit snappingConfigChanged( mSnappingConfig );
1201 }
1202 
1204 {
1205  if ( mAvoidIntersectionsMode == mode )
1206  return;
1207 
1208  mAvoidIntersectionsMode = mode;
1210 }
1211 
1212 bool QgsProject::_getMapLayers( const QDomDocument &doc, QList<QDomNode> &brokenNodes, Qgis::ProjectReadFlags flags )
1213 {
1214  // Layer order is set by the restoring the legend settings from project file.
1215  // This is done on the 'readProject( ... )' signal
1216 
1217  QDomElement layerElement = doc.documentElement().firstChildElement( QStringLiteral( "projectlayers" ) ).firstChildElement( QStringLiteral( "maplayer" ) );
1218 
1219  // process the map layer nodes
1220 
1221  if ( layerElement.isNull() ) // if we have no layers to process, bail
1222  {
1223  return true; // Decided to return "true" since it's
1224  // possible for there to be a project with no
1225  // layers; but also, more imporantly, this
1226  // would cause the tests/qgsproject to fail
1227  // since the test suite doesn't currently
1228  // support test layers
1229  }
1230 
1231  bool returnStatus = true;
1232  int numLayers = 0;
1233 
1234  while ( ! layerElement.isNull() )
1235  {
1236  numLayers++;
1237  layerElement = layerElement.nextSiblingElement( QStringLiteral( "maplayer" ) );
1238  }
1239 
1240  // order layers based on their dependencies
1241  QgsScopedRuntimeProfile profile( tr( "Sorting layers" ), QStringLiteral( "projectload" ) );
1242  const QgsLayerDefinition::DependencySorter depSorter( doc );
1243  if ( depSorter.hasCycle() )
1244  return false;
1245 
1246  // Missing a dependency? We still load all the layers, otherwise the project is completely broken!
1247  if ( depSorter.hasMissingDependency() )
1248  returnStatus = false;
1249 
1250  emit layerLoaded( 0, numLayers );
1251 
1252  const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1253  const int totalLayerCount = sortedLayerNodes.count();
1254 
1255  int i = 0;
1256  for ( const QDomNode &node : sortedLayerNodes )
1257  {
1258  const QDomElement element = node.toElement();
1259 
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 ) );
1263 
1264  profile.switchTask( name );
1265 
1266  if ( element.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
1267  {
1268  createEmbeddedLayer( element.attribute( QStringLiteral( "id" ) ), readPath( element.attribute( QStringLiteral( "project" ) ) ), brokenNodes, true, flags );
1269  }
1270  else
1271  {
1272  QgsReadWriteContext context;
1273  context.setPathResolver( pathResolver() );
1274  context.setProjectTranslator( this );
1276 
1277  if ( !addLayer( element, brokenNodes, context, flags ) )
1278  {
1279  returnStatus = false;
1280  }
1281  const auto messages = context.takeMessages();
1282  if ( !messages.isEmpty() )
1283  {
1284  emit loadingLayerMessageReceived( tr( "Loading layer %1" ).arg( name ), messages );
1285  }
1286  }
1287  emit layerLoaded( i + 1, totalLayerCount );
1288  i++;
1289  }
1290 
1291  return returnStatus;
1292 }
1293 
1294 bool QgsProject::addLayer( const QDomElement &layerElem, QList<QDomNode> &brokenNodes, QgsReadWriteContext &context, Qgis::ProjectReadFlags flags )
1295 {
1296  const QString type = layerElem.attribute( QStringLiteral( "type" ) );
1297  QgsDebugMsgLevel( "Layer type is " + type, 4 );
1298  std::unique_ptr<QgsMapLayer> mapLayer;
1299 
1300  QgsScopedRuntimeProfile profile( tr( "Create layer" ), QStringLiteral( "projectload" ) );
1301 
1302  bool ok = false;
1303  const QgsMapLayerType layerType( QgsMapLayerFactory::typeFromString( type, ok ) );
1304  if ( !ok )
1305  {
1306  QgsDebugMsg( QStringLiteral( "Unknown layer type \"%1\"" ).arg( type ) );
1307  return false;
1308  }
1309 
1310  switch ( layerType )
1311  {
1313  {
1314  mapLayer = std::make_unique<QgsVectorLayer>();
1315  // apply specific settings to vector layer
1316  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mapLayer.get() ) )
1317  {
1318  vl->setReadExtentFromXml( ( mFlags & Qgis::ProjectFlag::TrustStoredLayerStatistics ) || ( flags & Qgis::ProjectReadFlag::TrustLayerMetadata ) );
1319  }
1320  break;
1321  }
1322 
1324  mapLayer = std::make_unique<QgsRasterLayer>();
1325  break;
1326 
1328  mapLayer = std::make_unique<QgsMeshLayer>();
1329  break;
1330 
1332  mapLayer = std::make_unique<QgsVectorTileLayer>();
1333  break;
1334 
1336  mapLayer = std::make_unique<QgsPointCloudLayer>();
1337  break;
1338 
1340  {
1341  const QString typeName = layerElem.attribute( QStringLiteral( "name" ) );
1342  mapLayer.reset( QgsApplication::pluginLayerRegistry()->createLayer( typeName ) );
1343  break;
1344  }
1345 
1347  {
1348  const QgsAnnotationLayer::LayerOptions options( mTransformContext );
1349  mapLayer = std::make_unique<QgsAnnotationLayer>( QString(), options );
1350  break;
1351  }
1352 
1354  {
1355  const QgsGroupLayer::LayerOptions options( mTransformContext );
1356  mapLayer = std::make_unique<QgsGroupLayer>( QString(), options );
1357  break;
1358  }
1359  }
1360 
1361  if ( !mapLayer )
1362  {
1363  QgsDebugMsg( QStringLiteral( "Unable to create layer" ) );
1364  return false;
1365  }
1366 
1367  Q_CHECK_PTR( mapLayer ); // NOLINT
1368 
1369  // This is tricky: to avoid a leak we need to check if the layer was already in the store
1370  // because if it was, the newly created layer will not be added to the store and it would leak.
1371  const QString layerId { layerElem.namedItem( QStringLiteral( "id" ) ).toElement().text() };
1372  Q_ASSERT( ! layerId.isEmpty() );
1373  const bool layerWasStored { layerStore()->mapLayer( layerId ) != nullptr };
1374 
1375  // have the layer restore state that is stored in Dom node
1376  QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1377  if ( flags & Qgis::ProjectReadFlag::DontResolveLayers )
1378  layerFlags |= QgsMapLayer::FlagDontResolveLayers;
1379  // Propagate trust layer metadata flag
1380  if ( ( mFlags & Qgis::ProjectFlag::TrustStoredLayerStatistics ) || ( flags & Qgis::ProjectReadFlag::TrustLayerMetadata ) )
1382 
1383  profile.switchTask( tr( "Load layer source" ) );
1384  const bool layerIsValid = mapLayer->readLayerXml( layerElem, context, layerFlags ) && mapLayer->isValid();
1385 
1386  profile.switchTask( tr( "Add layer to project" ) );
1387  QList<QgsMapLayer *> newLayers;
1388  newLayers << mapLayer.get();
1389  if ( layerIsValid || flags & Qgis::ProjectReadFlag::DontResolveLayers )
1390  {
1391  emit readMapLayer( mapLayer.get(), layerElem );
1392  addMapLayers( newLayers );
1393  // Try to resolve references here (this is necessary to set up joined fields that will be possibly used by
1394  // virtual layers that point to this layer's joined field in their query otherwise they won't be valid ),
1395  // a second attempt to resolve references will be done after all layers are loaded
1396  // see https://github.com/qgis/QGIS/issues/46834
1397  if ( QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mapLayer.get() ) )
1398  {
1399  vLayer->joinBuffer()->resolveReferences( this );
1400  }
1401  }
1402  else
1403  {
1404  // It's a bad layer: do not add to legend (the user will decide if she wants to do so)
1405  addMapLayers( newLayers, false );
1406  newLayers.first();
1407  QgsDebugMsg( "Unable to load " + type + " layer" );
1408  brokenNodes.push_back( layerElem );
1409  }
1410 
1411  const bool wasEditable = layerElem.attribute( QStringLiteral( "editable" ), QStringLiteral( "0" ) ).toInt();
1412  if ( wasEditable )
1413  {
1414  mapLayer->setCustomProperty( QStringLiteral( "_layer_was_editable" ), true );
1415  }
1416  else
1417  {
1418  mapLayer->removeCustomProperty( QStringLiteral( "_layer_was_editable" ) );
1419  }
1420 
1421  // It should be safe to delete the layer now if layer was stored, because all the store
1422  // had to to was to reset the data source in case the validity changed.
1423  if ( ! layerWasStored )
1424  {
1425  mapLayer.release();
1426  }
1427 
1428  return layerIsValid;
1429 }
1430 
1431 bool QgsProject::read( const QString &filename, Qgis::ProjectReadFlags flags )
1432 {
1433  mFile.setFileName( filename );
1434  mCachedHomePath.clear();
1435  mProjectScope.reset();
1436 
1437  return read( flags );
1438 }
1439 
1440 bool QgsProject::read( Qgis::ProjectReadFlags flags )
1441 {
1442  const QString filename = mFile.fileName();
1443  bool returnValue;
1444 
1445  if ( QgsProjectStorage *storage = projectStorage() )
1446  {
1447  QTemporaryFile inDevice;
1448  if ( !inDevice.open() )
1449  {
1450  setError( tr( "Unable to open %1" ).arg( inDevice.fileName() ) );
1451  return false;
1452  }
1453 
1454  QgsReadWriteContext context;
1455  context.setProjectTranslator( this );
1456  if ( !storage->readProject( filename, &inDevice, context ) )
1457  {
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();
1462  setError( err );
1463  return false;
1464  }
1465  returnValue = unzip( inDevice.fileName(), flags ); // calls setError() if returning false
1466  }
1467  else
1468  {
1469  if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
1470  {
1471  returnValue = unzip( mFile.fileName(), flags );
1472  }
1473  else
1474  {
1475  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( *this ) );
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() )
1479  {
1480  std::unique_ptr<QgsArchive> archive( new QgsArchive() );
1481  if ( archive->unzip( attachmentsZip ) )
1482  {
1483  mArchive = std::move( archive );
1484  }
1485  }
1486  returnValue = readProjectFile( mFile.fileName(), flags );
1487  }
1488 
1489  //on translation we should not change the filename back
1490  if ( !mTranslator )
1491  {
1492  mFile.setFileName( filename );
1493  mCachedHomePath.clear();
1494  mProjectScope.reset();
1495  }
1496  else
1497  {
1498  //but delete the translator
1499  mTranslator.reset( nullptr );
1500  }
1501  }
1502  emit homePathChanged();
1503  return returnValue;
1504 }
1505 
1506 bool QgsProject::readProjectFile( const QString &filename, Qgis::ProjectReadFlags flags )
1507 {
1508  // avoid multiple emission of snapping updated signals
1509  ScopedIntIncrementor snapSignalBlock( &mBlockSnappingUpdates );
1510 
1511  QFile projectFile( filename );
1512  clearError();
1513 
1514  QgsApplication::profiler()->clear( QStringLiteral( "projectload" ) );
1515  QgsScopedRuntimeProfile profile( tr( "Setting up translations" ), QStringLiteral( "projectload" ) );
1516 
1517  const QString localeFileName = QStringLiteral( "%1_%2" ).arg( QFileInfo( projectFile.fileName() ).baseName(), QgsApplication::settingsLocaleUserLocale.value() );
1518 
1519  if ( QFile( QStringLiteral( "%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1520  {
1521  mTranslator.reset( new QTranslator() );
1522  ( void )mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1523  }
1524 
1525  profile.switchTask( tr( "Reading project file" ) );
1526  std::unique_ptr<QDomDocument> doc( new QDomDocument( QStringLiteral( "qgis" ) ) );
1527 
1528  if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1529  {
1530  projectFile.close();
1531 
1532  setError( tr( "Unable to open %1" ).arg( projectFile.fileName() ) );
1533 
1534  return false;
1535  }
1536 
1537  // location of problem associated with errorMsg
1538  int line, column;
1539  QString errorMsg;
1540 
1541  if ( !doc->setContent( &projectFile, &errorMsg, &line, &column ) )
1542  {
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 );
1545 
1546  QgsDebugMsg( errorString );
1547 
1548  projectFile.close();
1549 
1550  setError( tr( "%1 for file %2" ).arg( errorString, projectFile.fileName() ) );
1551 
1552  return false;
1553  }
1554 
1555  projectFile.close();
1556 
1557  QgsDebugMsgLevel( "Opened document " + projectFile.fileName(), 2 );
1558 
1559  // get project version string, if any
1560  const QgsProjectVersion fileVersion = getVersion( *doc );
1561  const QgsProjectVersion thisVersion( Qgis::version() );
1562 
1563  profile.switchTask( tr( "Updating project file" ) );
1564  if ( thisVersion > fileVersion )
1565  {
1566  const bool isOlderMajorVersion = fileVersion.majorVersion() < thisVersion.majorVersion();
1567 
1568  if ( isOlderMajorVersion )
1569  {
1570  QgsLogger::warning( "Loading a file that was saved with an older "
1571  "version of qgis (saved in " + fileVersion.text() +
1572  ", loaded in " + Qgis::version() +
1573  "). Problems may occur." );
1574  }
1575 
1576  QgsProjectFileTransform projectFile( *doc, fileVersion );
1577 
1578  // Shows a warning when an old project file is read.
1580  emit oldProjectVersionWarning( fileVersion.text() );
1582  emit readVersionMismatchOccurred( fileVersion.text() );
1583 
1584  projectFile.updateRevision( thisVersion );
1585  }
1586  else if ( fileVersion > thisVersion )
1587  {
1588  QgsLogger::warning( "Loading a file that was saved with a newer "
1589  "version of qgis (saved in " + fileVersion.text() +
1590  ", loaded in " + Qgis::version() +
1591  "). Problems may occur." );
1592 
1593  emit readVersionMismatchOccurred( fileVersion.text() );
1594  }
1595 
1596  // start new project, just keep the file name and auxiliary storage
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 );
1601  clear();
1602  mAuxiliaryStorage = std::move( aStorage );
1603  mArchive = std::move( archive );
1604  mFile.setFileName( fileName );
1605  mCachedHomePath.clear();
1606  mProjectScope.reset();
1607  mSaveVersion = fileVersion;
1608 
1609  // now get any properties
1610  profile.switchTask( tr( "Reading properties" ) );
1611  _getProperties( *doc, mProperties );
1612 
1613  // now get the data defined server properties
1614  mDataDefinedServerProperties = getDataDefinedServerProperties( *doc, dataDefinedServerPropertyDefinitions() );
1615 
1616  QgsDebugMsgLevel( QString::number( mProperties.count() ) + " properties read", 2 );
1617 
1618 #if 0
1619  dump_( mProperties );
1620 #endif
1621 
1622  // get older style project title
1623  QString oldTitle;
1624  _getTitle( *doc, oldTitle );
1625 
1626  readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1627 
1628  const QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral( "homePath" ) );
1629  if ( homePathNl.count() > 0 )
1630  {
1631  const QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1632  const QString homePath = homePathElement.attribute( QStringLiteral( "path" ) );
1633  if ( !homePath.isEmpty() )
1635  }
1636  else
1637  {
1638  emit homePathChanged();
1639  }
1640 
1641  const QColor backgroundColor( readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), 255 ),
1642  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), 255 ),
1643  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), 255 ) );
1645  const QColor selectionColor( readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorRedPart" ), 255 ),
1646  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorGreenPart" ), 255 ),
1647  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorBluePart" ), 255 ),
1648  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorAlphaPart" ), 255 ) );
1650 
1651  QgsReadWriteContext context;
1652  context.setPathResolver( pathResolver() );
1653  context.setProjectTranslator( this );
1654 
1655  //crs
1656  QgsCoordinateReferenceSystem projectCrs;
1657  if ( readNumEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectionsEnabled" ), 0 ) )
1658  {
1659  // first preference - dedicated projectCrs node
1660  const QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral( "projectCrs" ) );
1661  if ( !srsNode.isNull() )
1662  {
1663  projectCrs.readXml( srsNode );
1664  }
1665 
1666  if ( !projectCrs.isValid() )
1667  {
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" ) );
1671 
1672  // authid should be prioritized over all
1673  const bool isUserAuthId = authid.startsWith( QLatin1String( "USER:" ), Qt::CaseInsensitive );
1674  if ( !authid.isEmpty() && !isUserAuthId )
1675  projectCrs = QgsCoordinateReferenceSystem( authid );
1676 
1677  // try the CRS
1678  if ( !projectCrs.isValid() && currentCRS >= 0 )
1679  {
1680  projectCrs = QgsCoordinateReferenceSystem::fromSrsId( currentCRS );
1681  }
1682 
1683  // if that didn't produce a match, try the proj.4 string
1684  if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.isValid() || projectCrs.toProj() != projCrsString ) )
1685  {
1686  projectCrs = QgsCoordinateReferenceSystem::fromProj( projCrsString );
1687  }
1688 
1689  // last just take the given id
1690  if ( !projectCrs.isValid() )
1691  {
1692  projectCrs = QgsCoordinateReferenceSystem::fromSrsId( currentCRS );
1693  }
1694  }
1695  }
1696  mCrs = projectCrs;
1697 
1698  QStringList datumErrors;
1699  if ( !mTransformContext.readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
1700  {
1701  emit missingDatumTransforms( datumErrors );
1702  }
1703  emit transformContextChanged();
1704 
1705  //add variables defined in project file - do this early in the reading cycle, as other components
1706  //(e.g. layouts) may depend on these variables
1707  const QStringList variableNames = readListEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableNames" ) );
1708  const QStringList variableValues = readListEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableValues" ) );
1709 
1710  mCustomVariables.clear();
1711  if ( variableNames.length() == variableValues.length() )
1712  {
1713  for ( int i = 0; i < variableNames.length(); ++i )
1714  {
1715  mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
1716  }
1717  }
1718  else
1719  {
1720  QgsMessageLog::logMessage( tr( "Project Variables Invalid" ), tr( "The project contains invalid variable settings." ) );
1721  }
1722 
1723  QDomElement element = doc->documentElement().firstChildElement( QStringLiteral( "projectMetadata" ) );
1724 
1725  if ( !element.isNull() )
1726  {
1727  mMetadata.readMetadataXml( element );
1728  }
1729  else
1730  {
1731  // older project, no metadata => remove auto generated metadata which is populated on QgsProject::clear()
1732  mMetadata = QgsProjectMetadata();
1733  }
1734  if ( mMetadata.title().isEmpty() && !oldTitle.isEmpty() )
1735  {
1736  // upgrade older title storage to storing within project metadata.
1737  mMetadata.setTitle( oldTitle );
1738  }
1739  emit metadataChanged();
1740 
1741  // Transaction mode
1742  element = doc->documentElement().firstChildElement( QStringLiteral( "transaction" ) );
1743  if ( !element.isNull() )
1744  {
1745  mTransactionMode = qgsEnumKeyToValue( element.attribute( QStringLiteral( "mode" ) ), Qgis::TransactionMode::Disabled );
1746  }
1747  else
1748  {
1749  // maybe older project => try read autotransaction
1750  element = doc->documentElement().firstChildElement( QStringLiteral( "autotransaction" ) );
1751  if ( ! element.isNull() )
1752  {
1753  mTransactionMode = static_cast<Qgis::TransactionMode>( element.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() );
1754  }
1755  }
1756 
1757  element = doc->documentElement().firstChildElement( QStringLiteral( "projectFlags" ) );
1758  if ( !element.isNull() )
1759  {
1760  mFlags = qgsFlagKeysToValue( element.attribute( QStringLiteral( "set" ) ), Qgis::ProjectFlags() );
1761  }
1762  else
1763  {
1764  // older project compatibility
1765  element = doc->documentElement().firstChildElement( QStringLiteral( "evaluateDefaultValues" ) );
1766  if ( !element.isNull() )
1767  {
1768  if ( element.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 )
1770  }
1771 
1772  // Read trust layer metadata config in the project
1773  element = doc->documentElement().firstChildElement( QStringLiteral( "trust" ) );
1774  if ( !element.isNull() )
1775  {
1776  if ( element.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 )
1778  }
1779  }
1780 
1781  // read the layer tree from project file
1782  profile.switchTask( tr( "Loading layer tree" ) );
1783  mRootGroup->setCustomProperty( QStringLiteral( "loading" ), 1 );
1784 
1785  QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
1786  if ( !layerTreeElem.isNull() )
1787  {
1788  // Use a temporary tree to read the nodes to prevent signals being delivered to the models
1789  QgsLayerTree tempTree;
1790  tempTree.readChildrenFromXml( layerTreeElem, context );
1791  mRootGroup->insertChildNodes( -1, tempTree.abandonChildren() );
1792  }
1793  else
1794  {
1795  QgsLayerTreeUtils::readOldLegend( mRootGroup, doc->documentElement().firstChildElement( QStringLiteral( "legend" ) ) );
1796  }
1797 
1798  mLayerTreeRegistryBridge->setEnabled( false );
1799 
1800  // get the map layers
1801  profile.switchTask( tr( "Reading map layers" ) );
1802 
1803  QList<QDomNode> brokenNodes;
1804  const bool clean = _getMapLayers( *doc, brokenNodes, flags );
1805 
1806  // review the integrity of the retrieved map layers
1807  if ( !clean && !( flags & Qgis::ProjectReadFlag::DontResolveLayers ) )
1808  {
1809  QgsDebugMsg( QStringLiteral( "Unable to get map layers from project file." ) );
1810 
1811  if ( !brokenNodes.isEmpty() )
1812  {
1813  QgsDebugMsg( "there are " + QString::number( brokenNodes.size() ) + " broken layers" );
1814  }
1815 
1816  // we let a custom handler decide what to do with missing layers
1817  // (default implementation ignores them, there's also a GUI handler that lets user choose correct path)
1818  mBadLayerHandler->handleBadLayers( brokenNodes );
1819  }
1820 
1821  mMainAnnotationLayer->readLayerXml( doc->documentElement().firstChildElement( QStringLiteral( "main-annotation-layer" ) ), context );
1822  mMainAnnotationLayer->setTransformContext( mTransformContext );
1823 
1824  // load embedded groups and layers
1825  profile.switchTask( tr( "Loading embedded layers" ) );
1826  loadEmbeddedNodes( mRootGroup, flags );
1827 
1828  // Resolve references to other layers
1829  // Needs to be done here once all dependent layers are loaded
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 )
1833  {
1834  it.value()->resolveReferences( this );
1835  }
1836 
1837  mLayerTreeRegistryBridge->setEnabled( true );
1838 
1839  // now that layers are loaded, we can resolve layer tree's references to the layers
1840  profile.switchTask( tr( "Resolving references" ) );
1841  mRootGroup->resolveReferences( this );
1842 
1843  if ( !layerTreeElem.isNull() )
1844  {
1845  mRootGroup->readLayerOrderFromXml( layerTreeElem );
1846  }
1847 
1848  // Load pre 3.0 configuration
1849  const QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-canvas" ) );
1850  if ( !layerTreeCanvasElem.isNull( ) )
1851  {
1852  mRootGroup->readLayerOrderFromXml( layerTreeCanvasElem );
1853  }
1854 
1855  // Convert pre 3.4 to create layers flags
1856  if ( QgsProjectVersion( 3, 4, 0 ) > mSaveVersion )
1857  {
1858  const QStringList requiredLayerIds = readListEntry( QStringLiteral( "RequiredLayers" ), QStringLiteral( "Layers" ) );
1859  for ( const QString &layerId : requiredLayerIds )
1860  {
1861  if ( QgsMapLayer *layer = mapLayer( layerId ) )
1862  {
1863  layer->setFlags( layer->flags() & ~QgsMapLayer::Removable );
1864  }
1865  }
1866  const QStringList disabledLayerIds = readListEntry( QStringLiteral( "Identify" ), QStringLiteral( "/disabledLayers" ) );
1867  for ( const QString &layerId : disabledLayerIds )
1868  {
1869  if ( QgsMapLayer *layer = mapLayer( layerId ) )
1870  {
1871  layer->setFlags( layer->flags() & ~QgsMapLayer::Identifiable );
1872  }
1873  }
1874  }
1875 
1876  // Convert pre 3.26 default styles
1877  if ( QgsProjectVersion( 3, 26, 0 ) > mSaveVersion )
1878  {
1879  // Convert default symbols
1880  QString styleName = readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Marker" ) );
1881  if ( !styleName.isEmpty() )
1882  {
1883  std::unique_ptr<QgsSymbol> symbol( QgsStyle::defaultStyle()->symbol( styleName ) );
1885  }
1886  styleName = readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Line" ) );
1887  if ( !styleName.isEmpty() )
1888  {
1889  std::unique_ptr<QgsSymbol> symbol( QgsStyle::defaultStyle()->symbol( styleName ) );
1891  }
1892  styleName = readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Fill" ) );
1893  if ( !styleName.isEmpty() )
1894  {
1895  std::unique_ptr<QgsSymbol> symbol( QgsStyle::defaultStyle()->symbol( styleName ) );
1897  }
1898  styleName = readEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/ColorRamp" ) );
1899  if ( !styleName.isEmpty() )
1900  {
1901  std::unique_ptr<QgsColorRamp> colorRamp( QgsStyle::defaultStyle()->colorRamp( styleName ) );
1902  styleSettings()->setDefaultColorRamp( colorRamp.get() );
1903  }
1904 
1905  // Convert randomize default symbol fill color
1906  styleSettings()->setRandomizeDefaultSymbolColor( readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) );
1907 
1908  // Convert default symbol opacity
1909  double opacity = 1.0;
1910  bool ok = false;
1911  // upgrade old setting
1912  double alpha = readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/AlphaInt" ), 255, &ok );
1913  if ( ok )
1914  opacity = alpha / 255.0;
1915  double newOpacity = readDoubleEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/Opacity" ), 1.0, &ok );
1916  if ( ok )
1917  opacity = newOpacity;
1918  styleSettings()->setDefaultSymbolOpacity( opacity );
1919 
1920  // Cleanup
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" ) );
1928  }
1929 
1930  // After bad layer handling we might still have invalid layers,
1931  // store them in case the user wanted to handle them later
1932  // or wanted to pass them through when saving
1933  if ( !( flags & Qgis::ProjectReadFlag::DontStoreOriginalStyles ) )
1934  {
1935  profile.switchTask( tr( "Storing original layer properties" ) );
1936  QgsLayerTreeUtils::storeOriginalLayersProperties( mRootGroup, doc.get() );
1937  }
1938 
1939  mRootGroup->removeCustomProperty( QStringLiteral( "loading" ) );
1940 
1941  profile.switchTask( tr( "Loading map themes" ) );
1942  mMapThemeCollection.reset( new QgsMapThemeCollection( this ) );
1944  mMapThemeCollection->readXml( *doc );
1945 
1946  profile.switchTask( tr( "Loading label settings" ) );
1947  mLabelingEngineSettings->readSettingsFromProject( this );
1949 
1950  profile.switchTask( tr( "Loading annotations" ) );
1951  mAnnotationManager->readXml( doc->documentElement(), context );
1952  if ( !( flags & Qgis::ProjectReadFlag::DontLoadLayouts ) )
1953  {
1954  profile.switchTask( tr( "Loading layouts" ) );
1955  mLayoutManager->readXml( doc->documentElement(), *doc );
1956  }
1957 
1958  if ( !( flags & Qgis::ProjectReadFlag::DontLoad3DViews ) )
1959  {
1960  profile.switchTask( tr( "Loading 3D Views" ) );
1961  m3DViewsManager->readXml( doc->documentElement(), *doc );
1962  }
1963 
1964  profile.switchTask( tr( "Loading bookmarks" ) );
1965  mBookmarkManager->readXml( doc->documentElement(), *doc );
1966 
1967  // reassign change dependencies now that all layers are loaded
1968  QMap<QString, QgsMapLayer *> existingMaps = mapLayers();
1969  for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
1970  {
1971  it.value()->setDependencies( it.value()->dependencies() );
1972  }
1973 
1974  profile.switchTask( tr( "Loading snapping settings" ) );
1975  mSnappingConfig.readProject( *doc );
1976  mAvoidIntersectionsMode = static_cast<Qgis::AvoidIntersectionsMode>( readNumEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsMode" ), static_cast<int>( Qgis::AvoidIntersectionsMode::AvoidIntersectionsLayers ) ) );
1977 
1978  profile.switchTask( tr( "Loading view settings" ) );
1979  // restore older project scales settings
1980  mViewSettings->setUseProjectScales( readBoolEntry( QStringLiteral( "Scales" ), QStringLiteral( "/useProjectScales" ) ) );
1981  const QStringList scales = readListEntry( QStringLiteral( "Scales" ), QStringLiteral( "/ScalesList" ) );
1982  QVector<double> res;
1983  for ( const QString &scale : scales )
1984  {
1985  const QStringList parts = scale.split( ':' );
1986  if ( parts.size() != 2 )
1987  continue;
1988 
1989  bool ok = false;
1990  const double denominator = QLocale().toDouble( parts[1], &ok );
1991  if ( ok )
1992  {
1993  res << denominator;
1994  }
1995  }
1996  mViewSettings->setMapScales( res );
1997  const QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral( "ProjectViewSettings" ) );
1998  if ( !viewSettingsElement.isNull() )
1999  mViewSettings->readXml( viewSettingsElement, context );
2000 
2001  // restore style settings
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 );
2006 
2007  // restore time settings
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 );
2012 
2013 
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 );
2018  mElevationProperties->resolveReferences( this );
2019 
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 );
2024 
2025  profile.switchTask( tr( "Updating variables" ) );
2026  emit customVariablesChanged();
2027  profile.switchTask( tr( "Updating CRS" ) );
2028  emit crsChanged();
2029  emit ellipsoidChanged( ellipsoid() );
2030 
2031  // read the project: used by map canvas and legend
2032  profile.switchTask( tr( "Reading external settings" ) );
2033  emit readProject( *doc );
2034  emit readProjectWithContext( *doc, context );
2035 
2036  profile.switchTask( tr( "Updating interface" ) );
2037 
2038  snapSignalBlock.release();
2039  if ( !mBlockSnappingUpdates )
2040  emit snappingConfigChanged( mSnappingConfig );
2041 
2044  emit projectColorsChanged();
2045 
2046  // if all went well, we're allegedly in pristine state
2047  if ( clean )
2048  setDirty( false );
2049 
2050  QgsDebugMsgLevel( QStringLiteral( "Project save user: %1" ).arg( mSaveUser ), 2 );
2051  QgsDebugMsgLevel( QStringLiteral( "Project save user: %1" ).arg( mSaveUserFull ), 2 );
2052 
2056 
2057  if ( mTranslator )
2058  {
2059  //project possibly translated -> rename it with locale postfix
2060  const QString newFileName( QStringLiteral( "%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
2061  setFileName( newFileName );
2062 
2063  if ( write() )
2064  {
2065  setTitle( localeFileName );
2066  QgsMessageLog::logMessage( tr( "Translated project saved with locale prefix %1" ).arg( newFileName ), QObject::tr( "Project translation" ), Qgis::MessageLevel::Success );
2067  }
2068  else
2069  {
2070  QgsMessageLog::logMessage( tr( "Error saving translated project with locale prefix %1" ).arg( newFileName ), QObject::tr( "Project translation" ), Qgis::MessageLevel::Critical );
2071  }
2072  }
2073 
2074  // lastly, make any previously editable layers editable
2075  const QMap<QString, QgsMapLayer *> loadedLayers = mapLayers();
2076  for ( auto it = loadedLayers.constBegin(); it != loadedLayers.constEnd(); ++it )
2077  {
2078  if ( it.value()->isValid() && it.value()->customProperty( QStringLiteral( "_layer_was_editable" ) ).toBool() )
2079  {
2080  if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( it.value() ) )
2081  vl->startEditing();
2082  it.value()->removeCustomProperty( QStringLiteral( "_layer_was_editable" ) );
2083  }
2084  }
2085 
2086  return true;
2087 }
2088 
2089 
2090 bool QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
2091 {
2092  bool valid = true;
2093  const auto constChildren = group->children();
2094  for ( QgsLayerTreeNode *child : constChildren )
2095  {
2096  if ( QgsLayerTree::isGroup( child ) )
2097  {
2098  QgsLayerTreeGroup *childGroup = QgsLayerTree::toGroup( child );
2099  if ( childGroup->customProperty( QStringLiteral( "embedded" ) ).toInt() )
2100  {
2101  // make sure to convert the path from relative to absolute
2102  const QString projectPath = readPath( childGroup->customProperty( QStringLiteral( "embedded_project" ) ).toString() );
2103  childGroup->setCustomProperty( QStringLiteral( "embedded_project" ), projectPath );
2104  QgsLayerTreeGroup *newGroup = createEmbeddedGroup( childGroup->name(), projectPath, childGroup->customProperty( QStringLiteral( "embedded-invisible-layers" ) ).toStringList(), flags );
2105  if ( newGroup )
2106  {
2107  QList<QgsLayerTreeNode *> clonedChildren;
2108  const QList<QgsLayerTreeNode *> constChildren = newGroup->children();
2109  clonedChildren.reserve( constChildren.size() );
2110  for ( QgsLayerTreeNode *newGroupChild : constChildren )
2111  clonedChildren << newGroupChild->clone();
2112  delete newGroup;
2113 
2114  childGroup->insertChildNodes( 0, clonedChildren );
2115  }
2116  }
2117  else
2118  {
2119  loadEmbeddedNodes( childGroup, flags );
2120  }
2121  }
2122  else if ( QgsLayerTree::isLayer( child ) )
2123  {
2124  if ( child->customProperty( QStringLiteral( "embedded" ) ).toInt() )
2125  {
2126  QList<QDomNode> brokenNodes;
2127  if ( ! createEmbeddedLayer( QgsLayerTree::toLayer( child )->layerId(), readPath( child->customProperty( QStringLiteral( "embedded_project" ) ).toString() ), brokenNodes, true, flags ) )
2128  {
2129  valid = valid && false;
2130  }
2131  }
2132  }
2133 
2134  }
2135 
2136  return valid;
2137 }
2138 
2139 QVariantMap QgsProject::customVariables() const
2140 {
2141  return mCustomVariables;
2142 }
2143 
2144 void QgsProject::setCustomVariables( const QVariantMap &variables )
2145 {
2146  if ( variables == mCustomVariables )
2147  return;
2148 
2149  //write variable to project
2150  QStringList variableNames;
2151  QStringList variableValues;
2152 
2153  QVariantMap::const_iterator it = variables.constBegin();
2154  for ( ; it != variables.constEnd(); ++it )
2155  {
2156  variableNames << it.key();
2157  variableValues << it.value().toString();
2158  }
2159 
2160  writeEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableNames" ), variableNames );
2161  writeEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableValues" ), variableValues );
2162 
2163  mCustomVariables = variables;
2164  mProjectScope.reset();
2165 
2166  emit customVariablesChanged();
2167 }
2168 
2170 {
2171  *mLabelingEngineSettings = settings;
2173 }
2174 
2176 {
2177  return *mLabelingEngineSettings;
2178 }
2179 
2181 {
2182  mProjectScope.reset();
2183  return mLayerStore.get();
2184 }
2185 
2187 {
2188  return mLayerStore.get();
2189 }
2190 
2191 QList<QgsVectorLayer *> QgsProject::avoidIntersectionsLayers() const
2192 {
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 )
2197  {
2198  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mapLayer( layerId ) ) )
2199  layers << vlayer;
2200  }
2201  return layers;
2202 }
2203 
2204 void QgsProject::setAvoidIntersectionsLayers( const QList<QgsVectorLayer *> &layers )
2205 {
2206  QStringList list;
2207  list.reserve( layers.size() );
2208  for ( QgsVectorLayer *layer : layers )
2209  list << layer->id();
2210  writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), list );
2212 }
2213 
2215 {
2216  QgsExpressionContext context;
2217 
2220 
2221  return context;
2222 }
2223 
2225 {
2226  // MUCH cheaper to clone than build
2227  if ( mProjectScope )
2228  {
2229  std::unique_ptr< QgsExpressionContextScope > projectScope = std::make_unique< QgsExpressionContextScope >( *mProjectScope );
2230  // we can't cache these
2231  projectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_distance_units" ), QgsUnitTypes::toString( distanceUnits() ), true, true ) );
2232  projectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_area_units" ), QgsUnitTypes::toString( areaUnits() ), true, true ) );
2233  return projectScope.release();
2234  }
2235 
2236  mProjectScope = std::make_unique< QgsExpressionContextScope >( QObject::tr( "Project" ) );
2237 
2238  const QVariantMap vars = customVariables();
2239 
2240  QVariantMap::const_iterator it = vars.constBegin();
2241 
2242  for ( ; it != vars.constEnd(); ++it )
2243  {
2244  mProjectScope->setVariable( it.key(), it.value(), true );
2245  }
2246 
2247  QString projectPath = projectStorage() ? fileName() : absoluteFilePath();
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();
2253 
2254  //add other known project variables
2255  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), title(), true, true ) );
2256  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), QDir::toNativeSeparators( projectPath ), true, true ) );
2257  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), QDir::toNativeSeparators( projectFolder ), true, true ) );
2258  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), projectFilename, true, true ) );
2259  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_basename" ), projectBasename, true, true ) );
2260  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_home" ), QDir::toNativeSeparators( homePath() ), true, true ) );
2261  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_last_saved" ), mSaveDateTime.isNull() ? QVariant() : QVariant( mSaveDateTime ), true, true ) );
2262  const QgsCoordinateReferenceSystem projectCrs = crs();
2263  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true, true ) );
2264  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj(), true, true ) );
2265  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_description" ), projectCrs.description(), true, true ) );
2266  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_ellipsoid" ), ellipsoid(), true, true ) );
2267  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_project_transform_context" ), QVariant::fromValue<QgsCoordinateTransformContext>( transformContext() ), true, true ) );
2268  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_units" ), QgsUnitTypes::toString( projectCrs.mapUnits() ), true ) );
2269  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_acronym" ), projectCrs.projectionAcronym(), true ) );
2270  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_ellipsoid" ), projectCrs.ellipsoidAcronym(), true ) );
2271  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_proj4" ), projectCrs.toProj(), true ) );
2272  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_wkt" ), projectCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), true ) );
2273 
2274  // metadata
2275  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_author" ), metadata().author(), true, true ) );
2276  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_abstract" ), metadata().abstract(), true, true ) );
2277  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_creation_date" ), metadata().creationDateTime(), true, true ) );
2278  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_identifier" ), metadata().identifier(), true, true ) );
2279 
2280  // keywords
2281  QVariantMap keywords;
2282  const QgsAbstractMetadataBase::KeywordMap metadataKeywords = metadata().keywords();
2283  for ( auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
2284  {
2285  keywords.insert( it.key(), it.value() );
2286  }
2287  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_keywords" ), keywords, true, true ) );
2288 
2289  // layers
2290  QVariantList layersIds;
2291  QVariantList layers;
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 )
2296  {
2297  layersIds << it.value()->id();
2298  layers << QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( it.value() ) );
2299  }
2300  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_ids" ), layersIds, true ) );
2301  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layers" ), layers, true ) );
2302 
2303  mProjectScope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( this ) );
2304 
2306 }
2307 
2308 void QgsProject::onMapLayersAdded( const QList<QgsMapLayer *> &layers )
2309 {
2310  const QMap<QString, QgsMapLayer *> existingMaps = mapLayers();
2311 
2312  const auto constLayers = layers;
2313  for ( QgsMapLayer *layer : constLayers )
2314  {
2315  if ( ! layer->isValid() )
2316  return;
2317 
2318  connect( layer, &QgsMapLayer::configChanged, this, [ = ] { setDirty(); } );
2319 
2320  // check if we have to update connections for layers with dependencies
2321  for ( QMap<QString, QgsMapLayer *>::const_iterator it = existingMaps.cbegin(); it != existingMaps.cend(); ++it )
2322  {
2323  const QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
2324  if ( deps.contains( layer->id() ) )
2325  {
2326  // reconnect to change signals
2327  it.value()->setDependencies( deps );
2328  }
2329  }
2330  }
2331 
2332  updateTransactionGroups();
2333 
2334  if ( !mBlockSnappingUpdates && mSnappingConfig.addLayers( layers ) )
2335  emit snappingConfigChanged( mSnappingConfig );
2336 }
2337 
2338 void QgsProject::onMapLayersRemoved( const QList<QgsMapLayer *> &layers )
2339 {
2340  if ( !mBlockSnappingUpdates && mSnappingConfig.removeLayers( layers ) )
2341  emit snappingConfigChanged( mSnappingConfig );
2342 }
2343 
2344 void QgsProject::cleanTransactionGroups( bool force )
2345 {
2346  bool changed = false;
2347  for ( QMap< QPair< QString, QString>, QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
2348  {
2349  if ( tg.value()->isEmpty() || force )
2350  {
2351  delete tg.value();
2352  tg = mTransactionGroups.erase( tg );
2353  changed = true;
2354  }
2355  else
2356  {
2357  ++tg;
2358  }
2359  }
2360  if ( changed )
2361  emit transactionGroupsChanged();
2362 }
2363 
2364 void QgsProject::updateTransactionGroups()
2365 {
2366  mEditBufferGroup.clear();
2367 
2368  switch ( mTransactionMode )
2369  {
2371  {
2372  cleanTransactionGroups( true );
2373  return;
2374  }
2375  break;
2377  cleanTransactionGroups( true );
2378  break;
2380  cleanTransactionGroups( false );
2381  break;
2382  }
2383 
2384  bool tgChanged = false;
2385  const auto constLayers = mapLayers().values();
2386  for ( QgsMapLayer *layer : constLayers )
2387  {
2388  if ( ! layer->isValid() )
2389  continue;
2390 
2391  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
2392  if ( ! vlayer )
2393  continue;
2394 
2395  switch ( mTransactionMode )
2396  {
2398  Q_ASSERT( false );
2399  break;
2401  {
2402  if ( QgsTransaction::supportsTransaction( vlayer ) )
2403  {
2404  const QString connString = QgsTransaction::connectionString( vlayer->source() );
2405  const QString key = vlayer->providerType();
2406 
2407  QgsTransactionGroup *tg = mTransactionGroups.value( qMakePair( key, connString ) );
2408 
2409  if ( !tg )
2410  {
2411  tg = new QgsTransactionGroup();
2412  mTransactionGroups.insert( qMakePair( key, connString ), tg );
2413  tgChanged = true;
2414  }
2415  tg->addLayer( vlayer );
2416  }
2417  }
2418  break;
2420  {
2421  if ( vlayer->supportsEditing() )
2422  mEditBufferGroup.addLayer( vlayer );
2423  }
2424  break;
2425  }
2426  }
2427 
2428  if ( tgChanged )
2429  emit transactionGroupsChanged();
2430 }
2431 
2432 bool QgsProject::readLayer( const QDomNode &layerNode )
2433 {
2434  QgsReadWriteContext context;
2435  context.setPathResolver( pathResolver() );
2436  context.setProjectTranslator( this );
2438  QList<QDomNode> brokenNodes;
2439  if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
2440  {
2441  // have to try to update joins for all layers now - a previously added layer may be dependent on this newly
2442  // added layer for joins
2443  const QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
2444  for ( QgsVectorLayer *layer : vectorLayers )
2445  {
2446  // TODO: should be only done later - and with all layers (other layers may have referenced this layer)
2447  layer->resolveReferences( this );
2448 
2449  if ( layer->isValid() && layer->customProperty( QStringLiteral( "_layer_was_editable" ) ).toBool() )
2450  {
2451  layer->startEditing();
2452  layer->removeCustomProperty( QStringLiteral( "_layer_was_editable" ) );
2453  }
2454  }
2455  return true;
2456  }
2457  return false;
2458 }
2459 
2460 bool QgsProject::write( const QString &filename )
2461 {
2462  mFile.setFileName( filename );
2463  mCachedHomePath.clear();
2464  return write();
2465 }
2466 
2468 {
2469  mProjectScope.reset();
2470  if ( QgsProjectStorage *storage = projectStorage() )
2471  {
2472  QgsReadWriteContext context;
2473  // for projects stored in a custom storage, we have to check for the support
2474  // of relative paths since the storage most likely will not be in a file system
2475  const QString storageFilePath { storage->filePath( mFile.fileName() ) };
2476  if ( storageFilePath.isEmpty() )
2477  {
2479  }
2480  context.setPathResolver( pathResolver() );
2481 
2482  const QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2483  const QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2484 
2485  if ( !zip( tmpZipFilename ) )
2486  return false; // zip() already calls setError() when returning false
2487 
2488  QFile tmpZipFile( tmpZipFilename );
2489  if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2490  {
2491  setError( tr( "Unable to read file %1" ).arg( tmpZipFilename ) );
2492  return false;
2493  }
2494 
2496  if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2497  {
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();
2502  setError( err );
2503  return false;
2504  }
2505 
2506  tmpZipFile.close();
2507  QFile::remove( tmpZipFilename );
2508 
2509  return true;
2510  }
2511 
2512  if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
2513  {
2514  return zip( mFile.fileName() );
2515  }
2516  else
2517  {
2518  // write project file even if the auxiliary storage is not correctly
2519  // saved
2520  const bool asOk = saveAuxiliaryStorage();
2521  const bool writeOk = writeProjectFile( mFile.fileName() );
2522  bool attachmentsOk = true;
2523  if ( !mArchive->files().isEmpty() )
2524  {
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 );
2528  }
2529 
2530  // errors raised during writing project file are more important
2531  if ( ( !asOk || !attachmentsOk ) && writeOk )
2532  {
2533  QStringList errorMessage;
2534  if ( !asOk )
2535  {
2536  const QString err = mAuxiliaryStorage->errorString();
2537  errorMessage.append( tr( "Unable to save auxiliary storage ('%1')" ).arg( err ) );
2538  }
2539  if ( !attachmentsOk )
2540  {
2541  errorMessage.append( tr( "Unable to save attachments archive" ) );
2542  }
2543  setError( errorMessage.join( '\n' ) );
2544  }
2545 
2546  return asOk && writeOk && attachmentsOk;
2547  }
2548 }
2549 
2550 bool QgsProject::writeProjectFile( const QString &filename )
2551 {
2552  QFile projectFile( filename );
2553  clearError();
2554 
2555  // if we have problems creating or otherwise writing to the project file,
2556  // let's find out up front before we go through all the hand-waving
2557  // necessary to create all the Dom objects
2558  const QFileInfo myFileInfo( projectFile );
2559  if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2560  {
2561  setError( tr( "%1 is not writable. Please adjust permissions (if possible) and try again." )
2562  .arg( projectFile.fileName() ) );
2563  return false;
2564  }
2565 
2566  QgsReadWriteContext context;
2567  context.setPathResolver( pathResolver() );
2569 
2570  QDomImplementation::setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2571 
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 ) );
2576 
2577  QDomElement qgisNode = doc->createElement( QStringLiteral( "qgis" ) );
2578  qgisNode.setAttribute( QStringLiteral( "projectname" ), title() );
2579  qgisNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
2580 
2581  if ( !mSettings.value( QStringLiteral( "projects/anonymize_saved_projects" ), false, QgsSettings::Core ).toBool() )
2582  {
2583  const QString newSaveUser = QgsApplication::userLoginName();
2584  const QString newSaveUserFull = QgsApplication::userFullName();
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 ) );
2591  }
2592  else
2593  {
2594  mSaveUser.clear();
2595  mSaveUserFull.clear();
2596  mSaveDateTime = QDateTime();
2597  }
2598  doc->appendChild( qgisNode );
2599  mSaveVersion = QgsProjectVersion( Qgis::version() );
2600 
2601  QDomElement homePathNode = doc->createElement( QStringLiteral( "homePath" ) );
2602  homePathNode.setAttribute( QStringLiteral( "path" ), mHomePath );
2603  qgisNode.appendChild( homePathNode );
2604 
2605  // title
2606  QDomElement titleNode = doc->createElement( QStringLiteral( "title" ) );
2607  qgisNode.appendChild( titleNode );
2608 
2609  QDomElement transactionNode = doc->createElement( QStringLiteral( "transaction" ) );
2610  transactionNode.setAttribute( QStringLiteral( "mode" ), qgsEnumValueToKey( mTransactionMode ) );
2611  qgisNode.appendChild( transactionNode );
2612 
2613  QDomElement flagsNode = doc->createElement( QStringLiteral( "projectFlags" ) );
2614  flagsNode.setAttribute( QStringLiteral( "set" ), qgsFlagValueToKeys( mFlags ) );
2615  qgisNode.appendChild( flagsNode );
2616 
2617  const QDomText titleText = doc->createTextNode( title() ); // XXX why have title TWICE?
2618  titleNode.appendChild( titleText );
2619 
2620  // write project CRS
2621  QDomElement srsNode = doc->createElement( QStringLiteral( "projectCrs" ) );
2622  mCrs.writeXml( srsNode, *doc );
2623  qgisNode.appendChild( srsNode );
2624 
2625  // write layer tree - make sure it is without embedded subgroups
2626  QgsLayerTreeNode *clonedRoot = mRootGroup->clone();
2628  QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ), this ); // convert absolute paths to relative paths if required
2629 
2630  clonedRoot->writeXml( qgisNode, context );
2631  delete clonedRoot;
2632 
2633  mSnappingConfig.writeProject( *doc );
2634  writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsMode" ), static_cast<int>( mAvoidIntersectionsMode ) );
2635 
2636  // let map canvas and legend write their information
2637  emit writeProject( *doc );
2638 
2639  // within top level node save list of layers
2640  const QMap<QString, QgsMapLayer *> layers = mapLayers();
2641 
2642  QDomElement annotationLayerNode = doc->createElement( QStringLiteral( "main-annotation-layer" ) );
2643  mMainAnnotationLayer->writeLayerXml( annotationLayerNode, *doc, context );
2644  qgisNode.appendChild( annotationLayerNode );
2645 
2646  // Iterate over layers in zOrder
2647  // Call writeXml() on each
2648  QDomElement projectLayersNode = doc->createElement( QStringLiteral( "projectlayers" ) );
2649 
2650  QMap<QString, QgsMapLayer *>::ConstIterator li = layers.constBegin();
2651  while ( li != layers.end() )
2652  {
2653  QgsMapLayer *ml = li.value();
2654 
2655  if ( ml )
2656  {
2657  const QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->id() );
2658  if ( emIt == mEmbeddedLayers.constEnd() )
2659  {
2660  QDomElement maplayerElem;
2661  // If layer is not valid, prefer to restore saved properties from invalidLayerProperties. But if that's
2662  // not available, just write what we DO have
2663  if ( ml->isValid() || ml->originalXmlProperties().isEmpty() )
2664  {
2665  // general layer metadata
2666  maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );
2667  ml->writeLayerXml( maplayerElem, *doc, context );
2668 
2670  maplayerElem.setAttribute( QStringLiteral( "editable" ), QStringLiteral( "1" ) );
2671  }
2672  else if ( ! ml->originalXmlProperties().isEmpty() )
2673  {
2674  QDomDocument document;
2675  if ( document.setContent( ml->originalXmlProperties() ) )
2676  {
2677  maplayerElem = document.firstChildElement();
2678  }
2679  else
2680  {
2681  QgsDebugMsg( QStringLiteral( "Could not restore layer properties for layer %1" ).arg( ml->id() ) );
2682  }
2683  }
2684 
2685  emit writeMapLayer( ml, maplayerElem, *doc );
2686 
2687  projectLayersNode.appendChild( maplayerElem );
2688  }
2689  else
2690  {
2691  // layer defined in an external project file
2692  // only save embedded layer if not managed by a legend group
2693  if ( emIt.value().second )
2694  {
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 );
2700  }
2701  }
2702  }
2703  li++;
2704  }
2705 
2706  qgisNode.appendChild( projectLayersNode );
2707 
2708  QDomElement layerOrderNode = doc->createElement( QStringLiteral( "layerorder" ) );
2709  const auto constCustomLayerOrder = mRootGroup->customLayerOrder();
2710  for ( QgsMapLayer *layer : constCustomLayerOrder )
2711  {
2712  QDomElement mapLayerElem = doc->createElement( QStringLiteral( "layer" ) );
2713  mapLayerElem.setAttribute( QStringLiteral( "id" ), layer->id() );
2714  layerOrderNode.appendChild( mapLayerElem );
2715  }
2716  qgisNode.appendChild( layerOrderNode );
2717 
2718  mLabelingEngineSettings->writeSettingsToProject( this );
2719 
2720  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), mBackgroundColor.red() );
2721  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), mBackgroundColor.green() );
2722  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), mBackgroundColor.blue() );
2723 
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() );
2728 
2729  // now add the optional extra properties
2730 #if 0
2731  dump_( mProperties );
2732 #endif
2733 
2734  QgsDebugMsgLevel( QStringLiteral( "there are %1 property scopes" ).arg( static_cast<int>( mProperties.count() ) ), 2 );
2735 
2736  if ( !mProperties.isEmpty() ) // only worry about properties if we
2737  // actually have any properties
2738  {
2739  mProperties.writeXml( QStringLiteral( "properties" ), qgisNode, *doc );
2740  }
2741 
2742  QDomElement ddElem = doc->createElement( QStringLiteral( "dataDefinedServerProperties" ) );
2743  mDataDefinedServerProperties.writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
2744  qgisNode.appendChild( ddElem );
2745 
2746  mMapThemeCollection->writeXml( *doc );
2747 
2748  mTransformContext.writeXml( qgisNode, context );
2749 
2750  QDomElement metadataElem = doc->createElement( QStringLiteral( "projectMetadata" ) );
2751  mMetadata.writeMetadataXml( metadataElem, *doc );
2752  qgisNode.appendChild( metadataElem );
2753 
2754  const QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
2755  qgisNode.appendChild( annotationsElem );
2756 
2757  const QDomElement layoutElem = mLayoutManager->writeXml( *doc );
2758  qgisNode.appendChild( layoutElem );
2759 
2760  const QDomElement views3DElem = m3DViewsManager->writeXml( *doc );
2761  qgisNode.appendChild( views3DElem );
2762 
2763  const QDomElement bookmarkElem = mBookmarkManager->writeXml( *doc );
2764  qgisNode.appendChild( bookmarkElem );
2765 
2766  const QDomElement viewSettingsElem = mViewSettings->writeXml( *doc, context );
2767  qgisNode.appendChild( viewSettingsElem );
2768 
2769  const QDomElement styleSettingsElem = mStyleSettings->writeXml( *doc, context );
2770  qgisNode.appendChild( styleSettingsElem );
2771 
2772  const QDomElement timeSettingsElement = mTimeSettings->writeXml( *doc, context );
2773  qgisNode.appendChild( timeSettingsElement );
2774 
2775  const QDomElement elevationPropertiesElement = mElevationProperties->writeXml( *doc, context );
2776  qgisNode.appendChild( elevationPropertiesElement );
2777 
2778  const QDomElement displaySettingsElem = mDisplaySettings->writeXml( *doc, context );
2779  qgisNode.appendChild( displaySettingsElem );
2780 
2781  // now wrap it up and ship it to the project file
2782  doc->normalize(); // XXX I'm not entirely sure what this does
2783 
2784  // Create backup file
2785  if ( QFile::exists( fileName() ) )
2786  {
2787  QFile backupFile( QStringLiteral( "%1~" ).arg( filename ) );
2788  bool ok = true;
2789  ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
2790  ok &= projectFile.open( QIODevice::ReadOnly );
2791 
2792  QByteArray ba;
2793  while ( ok && !projectFile.atEnd() )
2794  {
2795  ba = projectFile.read( 10240 );
2796  ok &= backupFile.write( ba ) == ba.size();
2797  }
2798 
2799  projectFile.close();
2800  backupFile.close();
2801 
2802  if ( !ok )
2803  {
2804  setError( tr( "Unable to create backup file %1" ).arg( backupFile.fileName() ) );
2805  return false;
2806  }
2807 
2808  const QFileInfo fi( 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 );
2811  }
2812 
2813  if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
2814  {
2815  projectFile.close(); // even though we got an error, let's make
2816  // sure it's closed anyway
2817 
2818  setError( tr( "Unable to save to file %1" ).arg( projectFile.fileName() ) );
2819  return false;
2820  }
2821 
2822  QTemporaryFile tempFile;
2823  bool ok = tempFile.open();
2824  if ( ok )
2825  {
2826  QTextStream projectFileStream( &tempFile );
2827  doc->save( projectFileStream, 2 ); // save as utf-8
2828  ok &= projectFileStream.pos() > -1;
2829 
2830  ok &= tempFile.seek( 0 );
2831 
2832  QByteArray ba;
2833  while ( ok && !tempFile.atEnd() )
2834  {
2835  ba = tempFile.read( 10240 );
2836  ok &= projectFile.write( ba ) == ba.size();
2837  }
2838 
2839  ok &= projectFile.error() == QFile::NoError;
2840 
2841  projectFile.close();
2842  }
2843 
2844  tempFile.close();
2845 
2846  if ( !ok )
2847  {
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() ) );
2852  return false;
2853  }
2854 
2855  setDirty( false ); // reset to pristine state
2856 
2857  emit projectSaved();
2858  return true;
2859 }
2860 
2861 bool QgsProject::writeEntry( const QString &scope, QString const &key, bool value )
2862 {
2863  bool propertiesModified;
2864  const bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2865 
2866  if ( propertiesModified )
2867  setDirty( true );
2868 
2869  return success;
2870 }
2871 
2872 bool QgsProject::writeEntry( const QString &scope, const QString &key, double value )
2873 {
2874  bool propertiesModified;
2875  const bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2876 
2877  if ( propertiesModified )
2878  setDirty( true );
2879 
2880  return success;
2881 }
2882 
2883 bool QgsProject::writeEntry( const QString &scope, QString const &key, int value )
2884 {
2885  bool propertiesModified;
2886  const bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2887 
2888  if ( propertiesModified )
2889  setDirty( true );
2890 
2891  return success;
2892 }
2893 
2894 bool QgsProject::writeEntry( const QString &scope, const QString &key, const QString &value )
2895 {
2896  bool propertiesModified;
2897  const bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2898 
2899  if ( propertiesModified )
2900  setDirty( true );
2901 
2902  return success;
2903 }
2904 
2905 bool QgsProject::writeEntry( const QString &scope, const QString &key, const QStringList &value )
2906 {
2907  bool propertiesModified;
2908  const bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2909 
2910  if ( propertiesModified )
2911  setDirty( true );
2912 
2913  return success;
2914 }
2915 
2916 QStringList QgsProject::readListEntry( const QString &scope,
2917  const QString &key,
2918  const QStringList &def,
2919  bool *ok ) const
2920 {
2921  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2922 
2923  QVariant value;
2924 
2925  if ( property )
2926  {
2927  value = property->value();
2928 
2929  const bool valid = QVariant::StringList == value.type();
2930  if ( ok )
2931  *ok = valid;
2932 
2933  if ( valid )
2934  {
2935  return value.toStringList();
2936  }
2937  }
2938  else if ( ok )
2939  *ok = false;
2940 
2941 
2942  return def;
2943 }
2944 
2945 
2946 QString QgsProject::readEntry( const QString &scope,
2947  const QString &key,
2948  const QString &def,
2949  bool *ok ) const
2950 {
2951  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2952 
2953  QVariant value;
2954 
2955  if ( property )
2956  {
2957  value = property->value();
2958 
2959  const bool valid = value.canConvert( QVariant::String );
2960  if ( ok )
2961  *ok = valid;
2962 
2963  if ( valid )
2964  return value.toString();
2965  }
2966  else if ( ok )
2967  *ok = false;
2968 
2969  return def;
2970 }
2971 
2972 int QgsProject::readNumEntry( const QString &scope, const QString &key, int def,
2973  bool *ok ) const
2974 {
2975  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2976 
2977  QVariant value;
2978 
2979  if ( property )
2980  {
2981  value = property->value();
2982  }
2983 
2984  const bool valid = value.canConvert( QVariant::Int );
2985 
2986  if ( ok )
2987  {
2988  *ok = valid;
2989  }
2990 
2991  if ( valid )
2992  {
2993  return value.toInt();
2994  }
2995 
2996  return def;
2997 }
2998 
2999 double QgsProject::readDoubleEntry( const QString &scope, const QString &key,
3000  double def,
3001  bool *ok ) const
3002 {
3003  QgsProjectProperty *property = findKey_( scope, key, mProperties );
3004  if ( property )
3005  {
3006  const QVariant value = property->value();
3007 
3008  const bool valid = value.canConvert( QVariant::Double );
3009  if ( ok )
3010  *ok = valid;
3011 
3012  if ( valid )
3013  return value.toDouble();
3014  }
3015  else if ( ok )
3016  *ok = false;
3017 
3018  return def;
3019 }
3020 
3021 bool QgsProject::readBoolEntry( const QString &scope, const QString &key, bool def,
3022  bool *ok ) const
3023 {
3024  QgsProjectProperty *property = findKey_( scope, key, mProperties );
3025 
3026  if ( property )
3027  {
3028  const QVariant value = property->value();
3029 
3030  const bool valid = value.canConvert( QVariant::Bool );
3031  if ( ok )
3032  *ok = valid;
3033 
3034  if ( valid )
3035  return value.toBool();
3036  }
3037  else if ( ok )
3038  *ok = false;
3039 
3040  return def;
3041 }
3042 
3043 bool QgsProject::removeEntry( const QString &scope, const QString &key )
3044 {
3045  if ( findKey_( scope, key, mProperties ) )
3046  {
3047  removeKey_( scope, key, mProperties );
3048  setDirty( true );
3049  }
3050 
3051  return !findKey_( scope, key, mProperties );
3052 }
3053 
3054 
3055 QStringList QgsProject::entryList( const QString &scope, const QString &key ) const
3056 {
3057  QgsProjectProperty *foundProperty = findKey_( scope, key, mProperties );
3058 
3059  QStringList entries;
3060 
3061  if ( foundProperty )
3062  {
3063  QgsProjectPropertyKey *propertyKey = dynamic_cast<QgsProjectPropertyKey *>( foundProperty );
3064 
3065  if ( propertyKey )
3066  { propertyKey->entryList( entries ); }
3067  }
3068 
3069  return entries;
3070 }
3071 
3072 QStringList QgsProject::subkeyList( const QString &scope, const QString &key ) const
3073 {
3074  QgsProjectProperty *foundProperty = findKey_( scope, key, mProperties );
3075 
3076  QStringList entries;
3077 
3078  if ( foundProperty )
3079  {
3080  QgsProjectPropertyKey *propertyKey = dynamic_cast<QgsProjectPropertyKey *>( foundProperty );
3081 
3082  if ( propertyKey )
3083  { propertyKey->subkeyList( entries ); }
3084  }
3085 
3086  return entries;
3087 }
3088 
3090 {
3091  dump_( mProperties );
3092 }
3093 
3095 {
3096  QString filePath;
3097  switch ( filePathStorage() )
3098  {
3100  break;
3101 
3103  {
3104  // for projects stored in a custom storage, we need to ask to the
3105  // storage for the path, if the storage returns an empty path
3106  // relative paths are not supported
3107  if ( QgsProjectStorage *storage = projectStorage() )
3108  {
3109  filePath = storage->filePath( mFile.fileName() );
3110  }
3111  else
3112  {
3113  filePath = fileName();
3114  }
3115  break;
3116  }
3117  }
3118 
3119  return QgsPathResolver( filePath, mArchive->dir() );
3120 }
3121 
3122 QString QgsProject::readPath( const QString &src ) const
3123 {
3124  return pathResolver().readPath( src );
3125 }
3126 
3127 QString QgsProject::writePath( const QString &src ) const
3128 {
3129  return pathResolver().writePath( src );
3130 }
3131 
3132 void QgsProject::setError( const QString &errorMessage )
3133 {
3134  mErrorMessage = errorMessage;
3135 }
3136 
3137 QString QgsProject::error() const
3138 {
3139  return mErrorMessage;
3140 }
3141 
3142 void QgsProject::clearError()
3143 {
3144  setError( QString() );
3145 }
3146 
3148 {
3149  delete mBadLayerHandler;
3150  mBadLayerHandler = handler;
3151 }
3152 
3153 QString QgsProject::layerIsEmbedded( const QString &id ) const
3154 {
3155  const QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find( id );
3156  if ( it == mEmbeddedLayers.constEnd() )
3157  {
3158  return QString();
3159  }
3160  return it.value().first;
3161 }
3162 
3163 bool QgsProject::createEmbeddedLayer( const QString &layerId, const QString &projectFilePath, QList<QDomNode> &brokenNodes,
3164  bool saveFlag, Qgis::ProjectReadFlags flags )
3165 {
3166  QgsDebugCall;
3167 
3168  static QString sPrevProjectFilePath;
3169  static QDateTime sPrevProjectFileTimestamp;
3170  static QDomDocument sProjectDocument;
3171 
3172  QString qgsProjectFile = projectFilePath;
3173  QgsProjectArchive archive;
3174  if ( projectFilePath.endsWith( QLatin1String( ".qgz" ), Qt::CaseInsensitive ) )
3175  {
3176  archive.unzip( projectFilePath );
3177  qgsProjectFile = archive.projectFile();
3178  }
3179 
3180  const QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
3181 
3182  if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
3183  {
3184  sPrevProjectFilePath.clear();
3185 
3186  QFile projectFile( qgsProjectFile );
3187  if ( !projectFile.open( QIODevice::ReadOnly ) )
3188  {
3189  return false;
3190  }
3191 
3192  if ( !sProjectDocument.setContent( &projectFile ) )
3193  {
3194  return false;
3195  }
3196 
3197  sPrevProjectFilePath = projectFilePath;
3198  sPrevProjectFileTimestamp = projectFileTimestamp;
3199  }
3200 
3201  // does project store paths absolute or relative?
3202  bool useAbsolutePaths = true;
3203 
3204  const QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral( "properties" ) );
3205  if ( !propertiesElem.isNull() )
3206  {
3207  const QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral( "Paths" ) ).firstChildElement( QStringLiteral( "Absolute" ) );
3208  if ( !absElem.isNull() )
3209  {
3210  useAbsolutePaths = absElem.text().compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
3211  }
3212  }
3213 
3214  QgsReadWriteContext embeddedContext;
3215  if ( !useAbsolutePaths )
3216  embeddedContext.setPathResolver( QgsPathResolver( projectFilePath ) );
3217  embeddedContext.setProjectTranslator( this );
3218  embeddedContext.setTransformContext( transformContext() );
3219 
3220  const QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral( "projectlayers" ) );
3221  if ( projectLayersElem.isNull() )
3222  {
3223  return false;
3224  }
3225 
3226  QDomElement mapLayerElem = projectLayersElem.firstChildElement( QStringLiteral( "maplayer" ) );
3227  while ( ! mapLayerElem.isNull() )
3228  {
3229  // get layer id
3230  const QString id = mapLayerElem.firstChildElement( QStringLiteral( "id" ) ).text();
3231  if ( id == layerId )
3232  {
3233  // layer can be embedded only once
3234  if ( mapLayerElem.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
3235  {
3236  return false;
3237  }
3238 
3239  mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
3240 
3241  if ( addLayer( mapLayerElem, brokenNodes, embeddedContext, flags ) )
3242  {
3243  return true;
3244  }
3245  else
3246  {
3247  mEmbeddedLayers.remove( layerId );
3248  return false;
3249  }
3250  }
3251  mapLayerElem = mapLayerElem.nextSiblingElement( QStringLiteral( "maplayer" ) );
3252  }
3253 
3254  return false;
3255 }
3256 
3257 
3258 QgsLayerTreeGroup *QgsProject::createEmbeddedGroup( const QString &groupName, const QString &projectFilePath, const QStringList &invisibleLayers, Qgis::ProjectReadFlags flags )
3259 {
3260  QString qgsProjectFile = projectFilePath;
3261  QgsProjectArchive archive;
3262  if ( projectFilePath.endsWith( QLatin1String( ".qgz" ), Qt::CaseInsensitive ) )
3263  {
3264  archive.unzip( projectFilePath );
3265  qgsProjectFile = archive.projectFile();
3266  }
3267 
3268  // open project file, get layer ids in group, add the layers
3269  QFile projectFile( qgsProjectFile );
3270  if ( !projectFile.open( QIODevice::ReadOnly ) )
3271  {
3272  return nullptr;
3273  }
3274 
3275  QDomDocument projectDocument;
3276  if ( !projectDocument.setContent( &projectFile ) )
3277  {
3278  return nullptr;
3279  }
3280 
3281  QgsReadWriteContext context;
3282  context.setPathResolver( pathResolver() );
3283  context.setProjectTranslator( this );
3285 
3287 
3288  QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
3289  if ( !layerTreeElem.isNull() )
3290  {
3291  root->readChildrenFromXml( layerTreeElem, context );
3292  }
3293  else
3294  {
3295  QgsLayerTreeUtils::readOldLegend( root, projectDocument.documentElement().firstChildElement( QStringLiteral( "legend" ) ) );
3296  }
3297 
3298  QgsLayerTreeGroup *group = root->findGroup( groupName );
3299  if ( !group || group->customProperty( QStringLiteral( "embedded" ) ).toBool() )
3300  {
3301  // embedded groups cannot be embedded again
3302  delete root;
3303  return nullptr;
3304  }
3305 
3306  // clone the group sub-tree (it is used already in a tree, we cannot just tear it off)
3307  QgsLayerTreeGroup *newGroup = QgsLayerTree::toGroup( group->clone() );
3308  delete root;
3309  root = nullptr;
3310 
3311  newGroup->setCustomProperty( QStringLiteral( "embedded" ), 1 );
3312  newGroup->setCustomProperty( QStringLiteral( "embedded_project" ), projectFilePath );
3313 
3314  // set "embedded" to all children + load embedded layers
3315  mLayerTreeRegistryBridge->setEnabled( false );
3316  initializeEmbeddedSubtree( projectFilePath, newGroup, flags );
3317  mLayerTreeRegistryBridge->setEnabled( true );
3318 
3319  // consider the layers might be identify disabled in its project
3320  const auto constFindLayerIds = newGroup->findLayerIds();
3321  for ( const QString &layerId : constFindLayerIds )
3322  {
3323  QgsLayerTreeLayer *layer = newGroup->findLayer( layerId );
3324  if ( layer )
3325  {
3326  layer->resolveReferences( this );
3327  layer->setItemVisibilityChecked( !invisibleLayers.contains( layerId ) );
3328  }
3329  }
3330 
3331  return newGroup;
3332 }
3333 
3334 void QgsProject::initializeEmbeddedSubtree( const QString &projectFilePath, QgsLayerTreeGroup *group, Qgis::ProjectReadFlags flags )
3335 {
3336  const auto constChildren = group->children();
3337  for ( QgsLayerTreeNode *child : constChildren )
3338  {
3339  // all nodes in the subtree will have "embedded" custom property set
3340  child->setCustomProperty( QStringLiteral( "embedded" ), 1 );
3341 
3342  if ( QgsLayerTree::isGroup( child ) )
3343  {
3344  initializeEmbeddedSubtree( projectFilePath, QgsLayerTree::toGroup( child ), flags );
3345  }
3346  else if ( QgsLayerTree::isLayer( child ) )
3347  {
3348  // load the layer into our project
3349  QList<QDomNode> brokenNodes;
3350  createEmbeddedLayer( QgsLayerTree::toLayer( child )->layerId(), projectFilePath, brokenNodes, false, flags );
3351  }
3352  }
3353 }
3354 
3356 {
3358 }
3359 
3360 void QgsProject::setEvaluateDefaultValues( bool evaluateDefaultValues )
3361 {
3363 }
3364 
3366 {
3367  writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
3369 }
3370 
3371 bool QgsProject::topologicalEditing() const
3372 {
3373  return readNumEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/TopologicalEditing" ), 0 );
3374 }
3375 
3377 {
3378  const QString distanceUnitString = readEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/DistanceUnits" ), QString() );
3379  if ( !distanceUnitString.isEmpty() )
3380  return QgsUnitTypes::decodeDistanceUnit( distanceUnitString );
3381 
3382  //fallback to QGIS default measurement unit
3383  bool ok = false;
3384  const QgsUnitTypes::DistanceUnit type = QgsUnitTypes::decodeDistanceUnit( mSettings.value( QStringLiteral( "/qgis/measure/displayunits" ) ).toString(), &ok );
3385  return ok ? type : QgsUnitTypes::DistanceMeters;
3386 }
3387 
3389 {
3390  writeEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/DistanceUnits" ), QgsUnitTypes::encodeUnit( unit ) );
3391 }
3392 
3394 {
3395  const QString areaUnitString = readEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/AreaUnits" ), QString() );
3396  if ( !areaUnitString.isEmpty() )
3397  return QgsUnitTypes::decodeAreaUnit( areaUnitString );
3398 
3399  //fallback to QGIS default area unit
3400  bool ok = false;
3401  const QgsUnitTypes::AreaUnit type = QgsUnitTypes::decodeAreaUnit( mSettings.value( QStringLiteral( "/qgis/measure/areaunits" ) ).toString(), &ok );
3402  return ok ? type : QgsUnitTypes::AreaSquareMeters;
3403 }
3404 
3406 {
3407  writeEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/AreaUnits" ), QgsUnitTypes::encodeUnit( unit ) );
3408 }
3409 
3410 QString QgsProject::homePath() const
3411 {
3412  if ( !mCachedHomePath.isEmpty() )
3413  return mCachedHomePath;
3414 
3415  const QFileInfo pfi( fileName() );
3416 
3417  if ( !mHomePath.isEmpty() )
3418  {
3419  const QFileInfo homeInfo( mHomePath );
3420  if ( !homeInfo.isRelative() )
3421  {
3422  mCachedHomePath = mHomePath;
3423  return mHomePath;
3424  }
3425  }
3426  else if ( !fileName().isEmpty() )
3427  {
3428  mCachedHomePath = pfi.path();
3429 
3430  return mCachedHomePath;
3431  }
3432 
3433  if ( !pfi.exists() )
3434  {
3435  mCachedHomePath = mHomePath;
3436  return mHomePath;
3437  }
3438 
3439  if ( !mHomePath.isEmpty() )
3440  {
3441  // path is relative to project file
3442  mCachedHomePath = QDir::cleanPath( pfi.path() + '/' + mHomePath );
3443  }
3444  else
3445  {
3446  mCachedHomePath = pfi.canonicalPath();
3447  }
3448  return mCachedHomePath;
3449 }
3450 
3452 {
3453  return mHomePath;
3454 }
3455 
3457 {
3458  return mRelationManager;
3459 }
3460 
3462 {
3463  return mLayoutManager.get();
3464 }
3465 
3467 {
3468  return mLayoutManager.get();
3469 }
3470 
3472 {
3473  return m3DViewsManager.get();
3474 }
3475 
3477 {
3478  return m3DViewsManager.get();
3479 }
3480 
3482 {
3483  return mBookmarkManager;
3484 }
3485 
3487 {
3488  return mBookmarkManager;
3489 }
3490 
3492 {
3493  return mViewSettings;
3494 }
3495 
3497 {
3498  return mViewSettings;
3499 }
3500 
3502 {
3503  return mStyleSettings;
3504 }
3505 
3507 {
3508  return mStyleSettings;
3509 }
3510 
3512 {
3513  return mTimeSettings;
3514 }
3515 
3517 {
3518  return mTimeSettings;
3519 }
3520 
3522 {
3523  return mElevationProperties;
3524 }
3525 
3527 {
3528  return mElevationProperties;
3529 }
3530 
3532 {
3533  return mDisplaySettings;
3534 }
3535 
3537 {
3538  return mDisplaySettings;
3539 }
3540 
3542 {
3543  return mRootGroup;
3544 }
3545 
3547 {
3548  return mMapThemeCollection.get();
3549 }
3550 
3552 {
3553  return mAnnotationManager.get();
3554 }
3555 
3557 {
3558  return mAnnotationManager.get();
3559 }
3560 
3561 void QgsProject::setNonIdentifiableLayers( const QList<QgsMapLayer *> &layers )
3562 {
3563  const QMap<QString, QgsMapLayer *> &projectLayers = mapLayers();
3564  for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3565  {
3566  if ( layers.contains( it.value() ) == !it.value()->flags().testFlag( QgsMapLayer::Identifiable ) )
3567  continue;
3568 
3569  if ( layers.contains( it.value() ) )
3570  it.value()->setFlags( it.value()->flags() & ~QgsMapLayer::Identifiable );
3571  else
3572  it.value()->setFlags( it.value()->flags() | QgsMapLayer::Identifiable );
3573  }
3574 
3578 }
3579 
3580 void QgsProject::setNonIdentifiableLayers( const QStringList &layerIds )
3581 {
3582  QList<QgsMapLayer *> nonIdentifiableLayers;
3583  nonIdentifiableLayers.reserve( layerIds.count() );
3584  for ( const QString &layerId : layerIds )
3585  {
3586  QgsMapLayer *layer = mapLayer( layerId );
3587  if ( layer )
3588  nonIdentifiableLayers << layer;
3589  }
3593 }
3594 
3595 QStringList QgsProject::nonIdentifiableLayers() const
3596 {
3597  QStringList nonIdentifiableLayers;
3598 
3599  const QMap<QString, QgsMapLayer *> &layers = mapLayers();
3600  for ( QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin(); it != layers.constEnd(); ++it )
3601  {
3602  if ( !it.value()->flags().testFlag( QgsMapLayer::Identifiable ) )
3603  {
3604  nonIdentifiableLayers.append( it.value()->id() );
3605  }
3606  }
3607  return nonIdentifiableLayers;
3608 }
3609 
3611 {
3612  return mTransactionMode == Qgis::TransactionMode::AutomaticGroups;
3613 }
3614 
3615 void QgsProject::setAutoTransaction( bool autoTransaction )
3616 {
3617  if ( autoTransaction
3618  && mTransactionMode == Qgis::TransactionMode::AutomaticGroups )
3619  return;
3620 
3621  if ( ! autoTransaction
3622  && mTransactionMode == Qgis::TransactionMode::Disabled )
3623  return;
3624 
3625  if ( autoTransaction )
3626  mTransactionMode = Qgis::TransactionMode::AutomaticGroups;
3627  else
3628  mTransactionMode = Qgis::TransactionMode::Disabled;
3629 
3630  updateTransactionGroups();
3631 }
3632 
3634 {
3635  return mTransactionMode;
3636 }
3637 
3639 {
3640  if ( transactionMode == mTransactionMode )
3641  return true;
3642 
3643  // Check that all layer are not in edit mode
3644  const auto constLayers = mapLayers().values();
3645  for ( QgsMapLayer *layer : constLayers )
3646  {
3647  if ( layer->isEditable() )
3648  {
3649  QgsLogger::warning( tr( "Transaction mode can be changed only if all layers are not editable." ) );
3650  return false;
3651  }
3652  }
3653 
3654  mTransactionMode = transactionMode;
3655  updateTransactionGroups();
3656  return true;
3657 }
3658 
3659 QMap<QPair<QString, QString>, QgsTransactionGroup *> QgsProject::transactionGroups()
3660 {
3661  return mTransactionGroups;
3662 }
3663 
3664 
3665 //
3666 // QgsMapLayerStore methods
3667 //
3668 
3669 
3671 {
3672  return mLayerStore->count();
3673 }
3674 
3676 {
3677  return mLayerStore->validCount();
3678 }
3679 
3680 QgsMapLayer *QgsProject::mapLayer( const QString &layerId ) const
3681 {
3682  return mLayerStore->mapLayer( layerId );
3683 }
3684 
3685 QList<QgsMapLayer *> QgsProject::mapLayersByName( const QString &layerName ) const
3686 {
3687  return mLayerStore->mapLayersByName( layerName );
3688 }
3689 
3690 QList<QgsMapLayer *> QgsProject::mapLayersByShortName( const QString &shortName ) const
3691 {
3692  QList<QgsMapLayer *> layers;
3693  const auto constMapLayers { mLayerStore->mapLayers() };
3694  for ( const auto &l : constMapLayers )
3695  {
3696  if ( ! l->shortName().isEmpty() )
3697  {
3698  if ( l->shortName() == shortName )
3699  layers << l;
3700  }
3701  else if ( l->name() == shortName )
3702  {
3703  layers << l;
3704  }
3705  }
3706  return layers;
3707 }
3708 
3709 bool QgsProject::unzip( const QString &filename, Qgis::ProjectReadFlags flags )
3710 {
3711  clearError();
3712  std::unique_ptr<QgsProjectArchive> archive( new QgsProjectArchive() );
3713 
3714  // unzip the archive
3715  if ( !archive->unzip( filename ) )
3716  {
3717  setError( tr( "Unable to unzip file '%1'" ).arg( filename ) );
3718  return false;
3719  }
3720 
3721  // test if zip provides a .qgs file
3722  if ( archive->projectFile().isEmpty() )
3723  {
3724  setError( tr( "Zip archive does not provide a project file" ) );
3725  return false;
3726  }
3727 
3728  // Keep the archive
3729  mArchive = std::move( archive );
3730 
3731  // load auxiliary storage
3732  if ( !static_cast<QgsProjectArchive *>( mArchive.get() )->auxiliaryStorageFile().isEmpty() )
3733  {
3734  // database file is already a copy as it's been unzipped. So we don't open
3735  // auxiliary storage in copy mode in this case
3736  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( static_cast<QgsProjectArchive *>( mArchive.get() )->auxiliaryStorageFile(), false ) );
3737  }
3738  else
3739  {
3740  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( *this ) );
3741  }
3742 
3743  // read the project file
3744  if ( ! readProjectFile( static_cast<QgsProjectArchive *>( mArchive.get() )->projectFile(), flags ) )
3745  {
3746  setError( tr( "Cannot read unzipped qgs project file" ) );
3747  return false;
3748  }
3749 
3750  // Remove the temporary .qgs file
3751  static_cast<QgsProjectArchive *>( mArchive.get() )->clearProjectFile();
3752 
3753  return true;
3754 }
3755 
3756 bool QgsProject::zip( const QString &filename )
3757 {
3758  clearError();
3759 
3760  // save the current project in a temporary .qgs file
3761  std::unique_ptr<QgsProjectArchive> archive( new QgsProjectArchive() );
3762  const QString baseName = QFileInfo( filename ).baseName();
3763  const QString qgsFileName = QStringLiteral( "%1.qgs" ).arg( baseName );
3764  QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
3765 
3766  bool writeOk = false;
3767  if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3768  {
3769  writeOk = writeProjectFile( qgsFile.fileName() );
3770  qgsFile.close();
3771  }
3772 
3773  // stop here with an error message
3774  if ( ! writeOk )
3775  {
3776  setError( tr( "Unable to write temporary qgs file" ) );
3777  return false;
3778  }
3779 
3780  // save auxiliary storage
3781  const QFileInfo info( qgsFile );
3782  const QString asExt = QStringLiteral( ".%1" ).arg( QgsAuxiliaryStorage::extension() );
3783  const QString asFileName = info.path() + QDir::separator() + info.completeBaseName() + asExt;
3784 
3785  bool auxiliaryStorageSavedOk = true;
3786  if ( ! saveAuxiliaryStorage( asFileName ) )
3787  {
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;
3791 
3792  // fixes the current archive and keep the previous version of qgd
3793  if ( !mArchive->exists() )
3794  {
3795  mArchive.reset( new QgsProjectArchive() );
3796  mArchive->unzip( mFile.fileName() );
3797  static_cast<QgsProjectArchive *>( mArchive.get() )->clearProjectFile();
3798 
3799  const QString auxiliaryStorageFile = static_cast<QgsProjectArchive *>( mArchive.get() )->auxiliaryStorageFile();
3800  if ( ! auxiliaryStorageFile.isEmpty() )
3801  {
3802  archive->addFile( auxiliaryStorageFile );
3803  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( auxiliaryStorageFile, false ) );
3804  }
3805  }
3806  }
3807  else
3808  {
3809  // in this case, an empty filename means that the auxiliary database is
3810  // empty, so we don't want to save it
3811  if ( QFile::exists( asFileName ) )
3812  {
3813  archive->addFile( asFileName );
3814  }
3815  }
3816 
3817  // create the archive
3818  archive->addFile( qgsFile.fileName() );
3819 
3820  // Add all other files
3821  const QStringList &files = mArchive->files();
3822  for ( const QString &file : files )
3823  {
3824  if ( !file.endsWith( QLatin1String( ".qgs" ), Qt::CaseInsensitive ) && !file.endsWith( asExt, Qt::CaseInsensitive ) )
3825  {
3826  archive->addFile( file );
3827  }
3828  }
3829 
3830  // zip
3831  bool zipOk = true;
3832  if ( !archive->zip( filename ) )
3833  {
3834  setError( tr( "Unable to perform zip" ) );
3835  zipOk = false;
3836  }
3837 
3838  return auxiliaryStorageSavedOk && zipOk;
3839 }
3840 
3842 {
3843  return QgsZipUtils::isZipFile( mFile.fileName() );
3844 }
3845 
3846 QList<QgsMapLayer *> QgsProject::addMapLayers(
3847  const QList<QgsMapLayer *> &layers,
3848  bool addToLegend,
3849  bool takeOwnership )
3850 {
3851  const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers( layers, takeOwnership ) };
3852  if ( !myResultList.isEmpty() )
3853  {
3854  // Update transform context
3855  for ( auto &l : myResultList )
3856  {
3857  l->setTransformContext( transformContext() );
3858  }
3859  if ( addToLegend )
3860  {
3861  emit legendLayersAdded( myResultList );
3862  }
3863  }
3864 
3865  if ( mAuxiliaryStorage )
3866  {
3867  for ( QgsMapLayer *mlayer : myResultList )
3868  {
3869  if ( mlayer->type() != QgsMapLayerType::VectorLayer )
3870  continue;
3871 
3872  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mlayer );
3873  if ( vl )
3874  {
3875  vl->loadAuxiliaryLayer( *mAuxiliaryStorage );
3876  }
3877  }
3878  }
3879 
3880  mProjectScope.reset();
3881 
3882  return myResultList;
3883 }
3884 
3885 QgsMapLayer *
3887  bool addToLegend,
3888  bool takeOwnership )
3889 {
3890  QList<QgsMapLayer *> addedLayers;
3891  addedLayers = addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
3892  return addedLayers.isEmpty() ? nullptr : addedLayers[0];
3893 }
3894 
3895 void QgsProject::removeMapLayers( const QStringList &layerIds )
3896 {
3897  mProjectScope.reset();
3898  mLayerStore->removeMapLayers( layerIds );
3899 }
3900 
3901 void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
3902 {
3903  mProjectScope.reset();
3904  mLayerStore->removeMapLayers( layers );
3905 }
3906 
3907 void QgsProject::removeMapLayer( const QString &layerId )
3908 {
3909  mProjectScope.reset();
3910  mLayerStore->removeMapLayer( layerId );
3911 }
3912 
3914 {
3915  mProjectScope.reset();
3916  mLayerStore->removeMapLayer( layer );
3917 }
3918 
3920 {
3921  mProjectScope.reset();
3922  return mLayerStore->takeMapLayer( layer );
3923 }
3924 
3926 {
3927  return mMainAnnotationLayer;
3928 }
3929 
3931 {
3932  if ( mLayerStore->count() == 0 )
3933  return;
3934 
3935  ScopedIntIncrementor snapSingleBlocker( &mBlockSnappingUpdates );
3936  mProjectScope.reset();
3937  mLayerStore->removeAllMapLayers();
3938 
3939  snapSingleBlocker.release();
3940  mSnappingConfig.clearIndividualLayerSettings();
3941  if ( !mBlockSnappingUpdates )
3942  emit snappingConfigChanged( mSnappingConfig );
3943 }
3944 
3946 {
3947  const QMap<QString, QgsMapLayer *> layers = mLayerStore->mapLayers();
3948  QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin();
3949  for ( ; it != layers.constEnd(); ++it )
3950  {
3951  it.value()->reload();
3952  }
3953 }
3954 
3955 QMap<QString, QgsMapLayer *> QgsProject::mapLayers( const bool validOnly ) const
3956 {
3957  return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
3958 }
3959 
3960 QgsTransactionGroup *QgsProject::transactionGroup( const QString &providerKey, const QString &connString )
3961 {
3962  return mTransactionGroups.value( qMakePair( providerKey, connString ) );
3963 }
3964 
3966 {
3967  return &mEditBufferGroup;
3968 }
3969 
3971 {
3972  QgsCoordinateReferenceSystem defaultCrs;
3973 
3974  // TODO QGIS 4.0 -- remove this method, and place it somewhere in app (where it belongs)
3975  // in the meantime, we have a slightly hacky way to read the settings key using an enum which isn't available (since it lives in app)
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" ) )
3978  {
3979  // for new layers if the new layer crs method is set to either prompt or use project, then we use the project crs
3980  defaultCrs = crs();
3981  }
3982  else
3983  {
3984  // global crs
3985  const QString layerDefaultCrs = mSettings.value( QStringLiteral( "/Projections/layerDefaultCrs" ), geoEpsgCrsAuthId() ).toString();
3986  defaultCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( layerDefaultCrs );
3987  }
3988 
3989  return defaultCrs;
3990 }
3991 
3993 {
3995 }
3996 
3998 {
4000 }
4001 
4002 bool QgsProject::saveAuxiliaryStorage( const QString &filename )
4003 {
4004  const QMap<QString, QgsMapLayer *> layers = mapLayers();
4005  bool empty = true;
4006  for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
4007  {
4008  if ( it.value()->type() != QgsMapLayerType::VectorLayer )
4009  continue;
4010 
4011  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
4012  if ( vl && vl->auxiliaryLayer() )
4013  {
4014  vl->auxiliaryLayer()->save();
4015  empty &= vl->auxiliaryLayer()->auxiliaryFields().isEmpty();
4016  }
4017  }
4018 
4019  if ( !mAuxiliaryStorage->exists( *this ) && empty )
4020  {
4021  return true; // it's not an error
4022  }
4023  else if ( !filename.isEmpty() )
4024  {
4025  return mAuxiliaryStorage->saveAs( filename );
4026  }
4027  else
4028  {
4029  return mAuxiliaryStorage->saveAs( *this );
4030  }
4031 }
4032 
4033 QgsPropertiesDefinition &QgsProject::dataDefinedServerPropertyDefinitions()
4034 {
4035  static QgsPropertiesDefinition sPropertyDefinitions
4036  {
4037  {
4038  QgsProject::DataDefinedServerProperty::WMSOnlineResource,
4039  QgsPropertyDefinition( "WMSOnlineResource", QObject::tr( "WMS Online Resource" ), QgsPropertyDefinition::String )
4040  },
4041  };
4042  return sPropertyDefinitions;
4043 }
4044 
4046 {
4047  return mAuxiliaryStorage.get();
4048 }
4049 
4051 {
4052  return mAuxiliaryStorage.get();
4053 }
4054 
4055 QString QgsProject::createAttachedFile( const QString &nameTemplate )
4056 {
4057  const QDir archiveDir( mArchive->dir() );
4058  QTemporaryFile tmpFile( archiveDir.filePath( "XXXXXX_" + nameTemplate ), this );
4059  tmpFile.setAutoRemove( false );
4060  tmpFile.open();
4061  mArchive->addFile( tmpFile.fileName() );
4062  return tmpFile.fileName();
4063 }
4064 
4065 QStringList QgsProject::attachedFiles() const
4066 {
4067  QStringList attachments;
4068  const QString baseName = QFileInfo( fileName() ).baseName();
4069  const QStringList files = mArchive->files();
4070  attachments.reserve( files.size() );
4071  for ( const QString &file : files )
4072  {
4073  if ( QFileInfo( file ).baseName() != baseName )
4074  {
4075  attachments.append( file );
4076  }
4077  }
4078  return attachments;
4079 }
4080 
4081 bool QgsProject::removeAttachedFile( const QString &path )
4082 {
4083  return mArchive->removeFile( path );
4084 }
4085 
4086 QString QgsProject::attachmentIdentifier( const QString &attachedFile ) const
4087 {
4088  return QStringLiteral( "attachment:///%1" ).arg( QFileInfo( attachedFile ).fileName() );
4089 }
4090 
4091 QString QgsProject::resolveAttachmentIdentifier( const QString &identifier ) const
4092 {
4093  if ( identifier.startsWith( QLatin1String( "attachment:///" ) ) )
4094  {
4095  return QDir( mArchive->dir() ).absoluteFilePath( identifier.mid( 14 ) );
4096  }
4097  return QString();
4098 }
4099 
4101 {
4102  return mMetadata;
4103 }
4104 
4106 {
4107  if ( metadata == mMetadata )
4108  return;
4109 
4110  mMetadata = metadata;
4111  mProjectScope.reset();
4112 
4113  emit metadataChanged();
4114 
4115  setDirty( true );
4116 }
4117 
4118 QSet<QgsMapLayer *> QgsProject::requiredLayers() const
4119 {
4120  QSet<QgsMapLayer *> requiredLayers;
4121 
4122  const QMap<QString, QgsMapLayer *> &layers = mapLayers();
4123  for ( QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin(); it != layers.constEnd(); ++it )
4124  {
4125  if ( !it.value()->flags().testFlag( QgsMapLayer::Removable ) )
4126  {
4127  requiredLayers.insert( it.value() );
4128  }
4129  }
4130  return requiredLayers;
4131 }
4132 
4133 void QgsProject::setRequiredLayers( const QSet<QgsMapLayer *> &layers )
4134 {
4135  const QMap<QString, QgsMapLayer *> &projectLayers = mapLayers();
4136  for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
4137  {
4138  if ( layers.contains( it.value() ) == !it.value()->flags().testFlag( QgsMapLayer::Removable ) )
4139  continue;
4140 
4141  if ( layers.contains( it.value() ) )
4142  it.value()->setFlags( it.value()->flags() & ~QgsMapLayer::Removable );
4143  else
4144  it.value()->setFlags( it.value()->flags() | QgsMapLayer::Removable );
4145  }
4146 }
4147 
4149 {
4150  // save colors to project
4151  QStringList customColors;
4152  QStringList customColorLabels;
4153 
4154  QgsNamedColorList::const_iterator colorIt = colors.constBegin();
4155  for ( ; colorIt != colors.constEnd(); ++colorIt )
4156  {
4157  const QString color = QgsSymbolLayerUtils::encodeColor( ( *colorIt ).first );
4158  const QString label = ( *colorIt ).second;
4159  customColors.append( color );
4160  customColorLabels.append( label );
4161  }
4162  writeEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ), customColors );
4163  writeEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ), customColorLabels );
4164  mProjectScope.reset();
4165  emit projectColorsChanged();
4166 }
4167 
4168 void QgsProject::setBackgroundColor( const QColor &color )
4169 {
4170  if ( mBackgroundColor == color )
4171  return;
4172 
4173  mBackgroundColor = color;
4174  emit backgroundColorChanged();
4175 }
4176 
4177 QColor QgsProject::backgroundColor() const
4178 {
4179  return mBackgroundColor;
4180 }
4181 
4182 void QgsProject::setSelectionColor( const QColor &color )
4183 {
4184  if ( mSelectionColor == color )
4185  return;
4186 
4187  mSelectionColor = color;
4188  emit selectionColorChanged();
4189 }
4190 
4191 QColor QgsProject::selectionColor() const
4192 {
4193  return mSelectionColor;
4194 }
4195 
4196 void QgsProject::setMapScales( const QVector<double> &scales )
4197 {
4198  mViewSettings->setMapScales( scales );
4199 }
4200 
4201 QVector<double> QgsProject::mapScales() const
4202 {
4203  return mViewSettings->mapScales();
4204 }
4205 
4207 {
4208  mViewSettings->setUseProjectScales( enabled );
4209 }
4210 
4212 {
4213  return mViewSettings->useProjectScales();
4214 }
4215 
4216 void QgsProject::generateTsFile( const QString &locale )
4217 {
4218  QgsTranslationContext translationContext;
4219  translationContext.setProject( this );
4220  translationContext.setFileName( QStringLiteral( "%1/%2.ts" ).arg( absolutePath(), baseName() ) );
4221 
4222  QgsApplication::instance()->collectTranslatableObjects( &translationContext );
4223 
4224  translationContext.writeTsFile( locale );
4225 }
4226 
4227 QString QgsProject::translate( const QString &context, const QString &sourceText, const char *disambiguation, int n ) const
4228 {
4229  if ( !mTranslator )
4230  {
4231  return sourceText;
4232  }
4233 
4234  QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
4235 
4236  if ( result.isEmpty() )
4237  {
4238  return sourceText;
4239  }
4240  return result;
4241 }
4242 
4244 {
4245  const QMap<QString, QgsMapLayer *> layers = mapLayers( false );
4246  if ( !layers.empty() )
4247  {
4248  for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
4249  {
4250  // NOTE: if visitEnter returns false it means "don't visit this layer", not "abort all further visitations"
4251  if ( visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Layer, ( *it )->id(), ( *it )->name() ) ) )
4252  {
4253  if ( !( ( *it )->accept( visitor ) ) )
4254  return false;
4255 
4256  if ( !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Layer, ( *it )->id(), ( *it )->name() ) ) )
4257  return false;
4258  }
4259  }
4260  }
4261 
4262  if ( !mLayoutManager->accept( visitor ) )
4263  return false;
4264 
4265  if ( !mAnnotationManager->accept( visitor ) )
4266  return false;
4267 
4268  return true;
4269 }
4270 
4272 GetNamedProjectColor::GetNamedProjectColor( const QgsProject *project )
4273  : QgsScopedExpressionFunction( QStringLiteral( "project_color" ), 1, QStringLiteral( "Color" ) )
4274 {
4275  if ( !project )
4276  return;
4277 
4278  //build up color list from project. Do this in advance for speed
4279  QStringList colorStrings = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ) );
4280  const QStringList colorLabels = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ) );
4281 
4282  //generate list from custom colors
4283  int colorIndex = 0;
4284  for ( QStringList::iterator it = colorStrings.begin();
4285  it != colorStrings.end(); ++it )
4286  {
4287  const QColor color = QgsSymbolLayerUtils::decodeColor( *it );
4288  QString label;
4289  if ( colorLabels.length() > colorIndex )
4290  {
4291  label = colorLabels.at( colorIndex );
4292  }
4293 
4294  mColors.insert( label.toLower(), color );
4295  colorIndex++;
4296  }
4297 }
4298 
4299 GetNamedProjectColor::GetNamedProjectColor( const QHash<QString, QColor> &colors )
4300  : QgsScopedExpressionFunction( QStringLiteral( "project_color" ), 1, QStringLiteral( "Color" ) )
4301  , mColors( colors )
4302 {
4303 }
4304 
4305 QVariant GetNamedProjectColor::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
4306 {
4307  const QString colorName = values.at( 0 ).toString().toLower();
4308  if ( mColors.contains( colorName ) )
4309  {
4310  return QStringLiteral( "%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
4311  }
4312  else
4313  return QVariant();
4314 }
4315 
4316 QgsScopedExpressionFunction *GetNamedProjectColor::clone() const
4317 {
4318  return new GetNamedProjectColor( mColors );
4319 }
QgsAttributeEditorElement
This is an abstract base class for any elements of a drag and drop form.
Definition: qgsattributeeditorelement.h:37
QgsProject::layersRemoved
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the registry.
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsSnappingConfig::readProject
void readProject(const QDomDocument &doc)
Reads the configuration from the specified QGIS project document.
Definition: qgssnappingconfig.cpp:441
QgsProject::transactionGroupsChanged
void transactionGroupsChanged()
Emitted whenever a new transaction group has been created or a transaction group has been removed.
QgsProject::relationManager
QgsRelationManager relationManager
Definition: qgsproject.h:114
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QgsProject::writeEntry
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean value to the project file.
Definition: qgsproject.cpp:2861
QgsLayerTreeGroup::findLayer
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Definition: qgslayertreegroup.cpp:221
QgsLayerTreeGroup::findLayers
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Definition: qgslayertreegroup.cpp:249
QgsProject::title
QString title() const
Returns the project's title.
Definition: qgsproject.cpp:503
qgsexpressioncontextutils.h
QgsReadWriteContext::setPathResolver
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
Definition: qgsreadwritecontext.cpp:52
QgsBookmarkManager::writeXml
QDomElement writeXml(QDomDocument &doc) const
Returns a DOM element representing the state of the manager.
Definition: qgsbookmarkmanager.cpp:324
QgsProject::customVariables
QVariantMap customVariables() const
A map of custom project variables.
Definition: qgsproject.cpp:2139
QgsProject::layerStore
QgsMapLayerStore * layerStore()
Returns a pointer to the project's internal layer store.
Definition: qgsproject.cpp:2180
QgsProject::setFileName
void setFileName(const QString &name)
Sets the file name associated with the project.
Definition: qgsproject.cpp:753
QgsProject::createEmbeddedGroup
QgsLayerTreeGroup * createEmbeddedGroup(const QString &groupName, const QString &projectFilePath, const QStringList &invisibleLayers, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Create layer group instance defined in an arbitrary project file.
Definition: qgsproject.cpp:3258
QgsProjectProperty::isValue
virtual bool isValue() const =0
Returns true if the property is a QgsProjectPropertyValue.
QgsProject::annotationManager
QgsAnnotationManager * annotationManager()
Returns pointer to the project's annotation manager.
Definition: qgsproject.cpp:3551
QgsVectorLayerEditBufferGroup::addLayer
void addLayer(QgsVectorLayer *layer)
Add a layer to this edit buffer group.
Definition: qgsvectorlayereditbuffergroup.cpp:32
QgsProject::layers
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
Definition: qgsproject.h:1175
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:64
QgsProject::projectStorage
QgsProjectStorage * projectStorage() const
Returns pointer to project storage implementation that handles read/write of the project file.
Definition: qgsproject.cpp:793
Qgis::FilePathType::Relative
@ Relative
Relative path.
QgsLayerTreeUtils::readOldLegend
static bool readOldLegend(QgsLayerTreeGroup *root, const QDomElement &legendElem)
Try to load layer tree from.
Definition: qgslayertreeutils.cpp:29
QgsLayerTreeNode
This class is a base class for nodes in a layer tree.
Definition: qgslayertreenode.h:75
QgsProject::selectionColor
QColor selectionColor
Definition: qgsproject.h:119
QgsMapLayerStore::allLayersRemoved
void allLayersRemoved()
Emitted when all layers are removed, before layersWillBeRemoved() and layerWillBeRemoved() signals ar...
QgsTransactionGroup
Definition: qgstransactiongroup.h:31
QgsProject::trustLayerMetadata
Q_DECL_DEPRECATED bool trustLayerMetadata() const
Returns true if the trust option is activated, false otherwise.
Definition: qgsproject.cpp:3997
qgsEnumValueToKey
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:2440
QgsLayoutManager
Manages storage of a set of layouts.
Definition: qgslayoutmanager.h:44
Qgis::version
static QString version()
Version string.
Definition: qgis.cpp:277
QgsProjectPropertyKey::dump
void dump(int tabs=0) const override
Dumps out the keys and values.
Definition: qgsprojectproperty.cpp:295
QgsRelationManager
This class manages a set of relations between layers.
Definition: qgsrelationmanager.h:35
makeKeyTokens_
QStringList makeKeyTokens_(const QString &scope, const QString &key)
Takes the given scope and key and convert them to a string list of key tokens that will be used to na...
Definition: qgsproject.cpp:105
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:57
qgsrasterlayer.h
QgsProjectViewSettings::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Definition: qgsprojectviewsettings.cpp:204
qgsruntimeprofiler.h
QgsMapLayer::FlagTrustLayerMetadata
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:641
QgsProject::attachedFiles
QStringList attachedFiles() const
Returns a map of all attached files with identifier and real paths.
Definition: qgsproject.cpp:4065
QgsProject::layersWillBeRemoved
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QgsProject::viewSettings
const QgsProjectViewSettings * viewSettings() const
Returns the project's view settings, which contains settings and properties relating to how a QgsProj...
Definition: qgsproject.cpp:3491
QgsProject::setAutoTransaction
Q_DECL_DEPRECATED void setAutoTransaction(bool autoTransaction)
Transactional editing means that on supported datasources (postgres databases) the edit state of all ...
Definition: qgsproject.cpp:3615
QgsMapLayer::configChanged
void configChanged()
Emitted whenever the configuration is changed.
QgsProjectViewSettings::mapScalesChanged
void mapScalesChanged()
Emitted when the list of custom project map scales changes.
qgsprojectstylesettings.h
QgsProject::fileNameChanged
void fileNameChanged()
Emitted when the file name of the project changes.
QgsMapLayer::writeLayerXml
bool writeLayerXml(QDomElement &layerElement, QDomDocument &document, const QgsReadWriteContext &context) const
Stores state in DOM node.
Definition: qgsmaplayer.cpp:540
Qgis::SymbolType::Fill
@ Fill
Fill symbol.
QgsProject::setFlag
void setFlag(Qgis::ProjectFlag flag, bool enabled=true)
Sets whether a project flag is enabled.
Definition: qgsproject.cpp:541
QgsProject::mapThemeCollectionChanged
void mapThemeCollectionChanged()
Emitted when the map theme collection changes.
qgsziputils.h
Qgis::SymbolType::Line
@ Line
Line symbol.
QgsLayerTreeNode::setItemVisibilityChecked
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
Definition: qgslayertreenode.cpp:95
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
QgsMapLayerType::MeshLayer
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
QgsProject::filePathStorage
Qgis::FilePathType filePathStorage() const
Returns the type of paths used when storing file paths in a QGS/QGZ project file.
Definition: qgsproject.cpp:848
QgsProject::auxiliaryStorage
const QgsAuxiliaryStorage * auxiliaryStorage() const
Returns the current const auxiliary storage.
Definition: qgsproject.cpp:4045
QgsExpressionContextUtils::globalScope
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Definition: qgsexpressioncontextutils.cpp:40
QgsProjectPropertyKey::subkeyList
void subkeyList(QStringList &entries) const
Returns any sub-keys contained by this property which themselves contain other keys.
Definition: qgsprojectproperty.cpp:440
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
qgsattributeeditorcontainer.h
QgsProjectArchive::unzip
bool unzip(const QString &zipFilename) override
Clear the current content of this archive and unzip.
Definition: qgsarchive.cpp:147
qgsrectangle.h
QgsCoordinateReferenceSystem::projectionAcronym
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
Definition: qgscoordinatereferencesystem.cpp:1239
qgslayertreeregistrybridge.h
QgsProjectMetadata
A structured metadata store for a map layer.
Definition: qgsprojectmetadata.h:53
QgsProject::layersAdded
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the registry.
QgsVectorLayer::supportsEditing
bool supportsEditing
Definition: qgsvectorlayer.h:400
QgsProject::mapScales
Q_DECL_DEPRECATED QVector< double > mapScales() const
Returns the list of custom project map scales.
Definition: qgsproject.cpp:4201
QgsMapLayerType::VectorLayer
@ VectorLayer
Vector layer.
qgsmapthemecollection.h
QgsDebugCall
#define QgsDebugCall
Definition: qgslogger.h:37
QgsProjectPropertyKey::addKey
QgsProjectPropertyKey * addKey(const QString &keyName)
Adds the specified property key as a sub-key.
Definition: qgsprojectproperty.h:218
QgsProjectPropertyKey::find
QgsProjectProperty * find(const QString &propertyName) const
Attempts to find a property with a matching sub-key name.
Definition: qgsprojectproperty.h:316
QgsFields::isEmpty
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsSettings::App
@ App
Definition: qgssettings.h:75
QgsProject::entryList
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.
Definition: qgsproject.cpp:3055
QgsProject::dirtySet
void dirtySet()
Emitted when setDirty(true) is called.
QgsProject::rollBack
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true, QgsVectorLayer *vectorLayer=nullptr)
Stops a current editing operation on vectorLayer and discards any uncommitted edits.
Definition: qgsproject.cpp:729
removeKey_
void removeKey_(const QString &scope, const QString &key, QgsProjectPropertyKey &rootProperty)
Removes a given key.
Definition: qgsproject.cpp:309
QgsProjectStyleSettings::setDefaultSymbolOpacity
void setDefaultSymbolOpacity(double opacity)
Sets the default symbol opacity.
Definition: qgsprojectstylesettings.h:118
QgsLayerTreeGroup::resolveReferences
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Calls resolveReferences() on child tree nodes.
Definition: qgslayertreegroup.cpp:414
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsAuxiliaryLayer::save
bool save()
Commits changes and starts editing then.
Definition: qgsauxiliarystorage.cpp:210
QgsProject::distanceUnits
QgsUnitTypes::DistanceUnit distanceUnits() const
Convenience function to query default distance measurement units for project.
Definition: qgsproject.cpp:3376
QgsProjectStyleSettings::setDefaultSymbol
void setDefaultSymbol(Qgis::SymbolType symbolType, QgsSymbol *symbol)
Sets the project default symbol for a given type.
Definition: qgsprojectstylesettings.cpp:72
QgsProject::mapLayersByName
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
Definition: qgsproject.cpp:3685
QgsReadWriteContext::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &transformContext)
Sets data coordinate transform context to transformContext.
Definition: qgsreadwritecontext.cpp:82
qgspluginlayerregistry.h
QgsLayerTreeRegistryBridge::setEnabled
void setEnabled(bool enabled)
Definition: qgslayertreeregistrybridge.h:67
QgsProject::mapLayers
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
Definition: qgsproject.cpp:3955
QgsProject::setBackgroundColor
void setBackgroundColor(const QColor &color)
Sets the default background color used by default map canvases.
Definition: qgsproject.cpp:4168
QgsMapLayer::setCustomProperty
Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
Definition: qgsmaplayer.cpp:1976
QgsCoordinateReferenceSystem::WKT_PREFERRED
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Definition: qgscoordinatereferencesystem.h:680
QgsSettings::Core
@ Core
Definition: qgssettings.h:70
qgsreadwritecontext.h
qgslabelingenginesettings.h
QgsProject::setFilePathStorage
void setFilePathStorage(Qgis::FilePathType type)
Sets the type of paths used when storing file paths in a QGS/QGZ project file.
Definition: qgsproject.cpp:854
QgsProject::write
bool write()
Writes the project to its current associated file (see fileName() ).
Definition: qgsproject.cpp:2467
QgsProjectStyleSettings
Contains settings and properties relating to how a QgsProject should handle styling.
Definition: qgsprojectstylesettings.h:43
QgsVectorLayerEditBufferGroup
The edit buffer group manages a group of edit buffers.
Definition: qgsvectorlayereditbuffergroup.h:38
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsLayerTree::customLayerOrder
QList< QgsMapLayer * > customLayerOrder() const
The order in which layers will be rendered on the canvas.
Definition: qgslayertree.cpp:39
QgsCoordinateReferenceSystem::fromOgcWmsCrs
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Definition: qgscoordinatereferencesystem.cpp:195
QgsProjectMetadata::readMetadataXml
bool readMetadataXml(const QDomElement &metadataElement) override
Sets state from DOM document.
Definition: qgsprojectmetadata.cpp:22
QgsCoordinateReferenceSystem::fromProj
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
Definition: qgscoordinatereferencesystem.cpp:221
QgsTranslationContext::writeTsFile
void writeTsFile(const QString &locale) const
Writes the Ts-file.
Definition: qgstranslationcontext.cpp:53
QgsProject::cleared
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QgsMapLayerType::AnnotationLayer
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
QgsProjectDisplaySettings
Contains settings and properties relating to how a QgsProject should display values such as map coord...
Definition: qgsprojectdisplaysettings.h:37
QgsProject::setEvaluateDefaultValues
Q_DECL_DEPRECATED void setEvaluateDefaultValues(bool evaluateDefaultValues)
Defines if default values should be evaluated on provider side when requested and not when committed.
Definition: qgsproject.cpp:3360
QgsProject::pathResolver
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
Definition: qgsproject.cpp:3094
QgsProject::avoidIntersectionsLayers
QList< QgsVectorLayer * > avoidIntersectionsLayers
Definition: qgsproject.h:116
qgssymbollayerutils.h
QgsMapLayerType
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:46
QgsCoordinateReferenceSystem::description
QString description
Definition: qgscoordinatereferencesystem.h:218
QgsAbstractPropertyCollection::readXml
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
Definition: qgspropertycollection.cpp:108
QgsLayerTreeGroup::readChildrenFromXml
void readChildrenFromXml(QDomElement &element, const QgsReadWriteContext &context)
Read children from XML and append them to the group.
Definition: qgslayertreegroup.cpp:382
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsTranslationContext::registerTranslation
void registerTranslation(const QString &context, const QString &source)
Registers the source to be translated.
Definition: qgstranslationcontext.cpp:45
QgsProjectTimeSettings::reset
void reset()
Resets the settings to a default state.
Definition: qgsprojecttimesettings.cpp:28
qgsprojectstorageregistry.h
QgsProject::transactionGroups
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
Definition: qgsproject.cpp:3659
QgsEditorWidgetSetup::config
QVariantMap config() const
Definition: qgseditorwidgetsetup.h:64
qgsFlagKeysToValue
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
Definition: qgis.h:2520
QgsNamedColorList
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
Definition: qgscolorscheme.h:34
QgsProject::homePath
QString homePath
Definition: qgsproject.h:108
QgsProjectStyleSettings::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Reads the settings's state from a DOM element.
Definition: qgsprojectstylesettings.cpp:168
QgsMapViewsManager
Manages storage of a set of views.
Definition: qgsmapviewsmanager.h:40
qgslayoutmanager.h
QgsProject::originalPath
QString originalPath() const
Returns the original path associated with the project.
Definition: qgsproject.cpp:783
QgsProject::removeAllMapLayers
void removeAllMapLayers()
Removes all registered layers.
Definition: qgsproject.cpp:3930
qgspathresolver.h
QgsRelationManager::clear
void clear()
Remove any relation managed by this class.
Definition: qgsrelationmanager.cpp:113
QgsProjectStorage::Metadata
Metadata associated with a project.
Definition: qgsprojectstorage.h:45
QgsProject::transformContext
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:110
QgsProject::avoidIntersectionsLayersChanged
void avoidIntersectionsLayersChanged()
Emitted whenever avoidIntersectionsLayers has changed.
QgsProjectElevationProperties::resolveReferences
void resolveReferences(const QgsProject *project)
Resolves reference to layers from stored layer ID.
Definition: qgsprojectelevationproperties.cpp:38
QgsProject::setCustomVariables
void setCustomVariables(const QVariantMap &customVariables)
A map of custom project variables.
Definition: qgsproject.cpp:2144
geoEpsgCrsAuthId
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:2732
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsProject::setBadLayerHandler
void setBadLayerHandler(QgsProjectBadLayerHandler *handler)
Change handler for missing layers.
Definition: qgsproject.cpp:3147
QgsProject::readProject
void readProject(const QDomDocument &)
Emitted when a project is being read.
QgsStyleEntityVisitorInterface
An interface for classes which can visit style entity (e.g. symbol) nodes (using the visitor pattern)...
Definition: qgsstyleentityvisitor.h:33
QgsProject::dataDefinedServerProperties
QgsPropertyCollection dataDefinedServerProperties() const
Returns the data defined properties used for overrides in user defined server parameters.
Definition: qgsproject.cpp:681
qgsunittypes.h
QgsVectorLayer::auxiliaryLayer
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
Definition: qgsvectorlayer.cpp:5520
QgsProject::displaySettings
const QgsProjectDisplaySettings * displaySettings() const
Returns the project's display settings, which settings and properties relating to how a QgsProject sh...
Definition: qgsproject.cpp:3531
QgsBookmarkManager
Manages storage of a set of bookmarks.
Definition: qgsbookmarkmanager.h:145
QgsStyleEntityVisitorInterface::visitExit
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
Definition: qgsstyleentityvisitor.h:183
QgsProject::viewsManager
const QgsMapViewsManager * viewsManager() const
Returns the project's views manager, which manages map views (including 3d maps) in the project.
Definition: qgsproject.cpp:3471
QgsAbstractMetadataBase::title
QString title() const
Returns the human readable name of the resource, typically displayed in search results.
Definition: qgsabstractmetadatabase.cpp:51
QgsProjectVersion::majorVersion
int majorVersion() const
Returns the major version number.
Definition: qgsprojectversion.h:68
QgsProjectViewSettings::setUseProjectScales
void setUseProjectScales(bool enabled)
Sets whether project mapScales() are enabled.
Definition: qgsprojectviewsettings.cpp:120
QgsVectorLayer::startEditing
Q_INVOKABLE bool startEditing()
Makes the layer editable.
Definition: qgsvectorlayer.cpp:1491
QgsMapLayer::isValid
bool isValid
Definition: qgsmaplayer.h:81
QgsLayerTree::toLayer
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:88
QgsApplication::instance
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
Definition: qgsapplication.cpp:478
QgsApplication::projectStorageRegistry
static QgsProjectStorageRegistry * projectStorageRegistry()
Returns registry of available project storage implementations.
Definition: qgsapplication.cpp:2500
QgsLayerTreeNode::abandonChildren
QList< QgsLayerTreeNode * > abandonChildren()
Removes the childrens, disconnect all the forwarded and external signals and sets their parent to nul...
Definition: qgslayertreenode.cpp:51
QgsProject::readEntry
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.
Definition: qgsproject.cpp:2946
QgsAbstractMetadataBase::setTitle
void setTitle(const QString &title)
Sets the human readable title (name) of the resource, typically displayed in search results.
Definition: qgsabstractmetadatabase.cpp:56
QgsProjectElevationProperties
Contains elevation properties for a QgsProject.
Definition: qgsprojectelevationproperties.h:38
field
const QgsField & field
Definition: qgsfield.h:463
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsProject::styleSettings
const QgsProjectStyleSettings * styleSettings() const
Returns the project's style settings, which contains settings and properties relating to how a QgsPro...
Definition: qgsproject.cpp:3501
QgsProject::setEllipsoid
void setEllipsoid(const QString &ellipsoid)
Sets the project's ellipsoid from a proj string representation, e.g., "WGS84".
Definition: qgsproject.cpp:901
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:67
QgsMapLayerStore::mapLayer
QgsMapLayer * mapLayer(const QString &id) const
Retrieve a pointer to a layer by layer id.
Definition: qgsmaplayerstore.cpp:49
QgsProject::mapLayer
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
Definition: qgsproject.cpp:3680
QgsProject::readBoolEntry
bool readBoolEntry(const QString &scope, const QString &key, bool def=false, bool *ok=nullptr) const
Reads a boolean from the specified scope and key.
Definition: qgsproject.cpp:3021
Qgis::ProjectFlag::TrustStoredLayerStatistics
@ TrustStoredLayerStatistics
If set, then layer statistics (such as the layer extent) will be read from values stored in the proje...
QgsAttributeEditorContainer::children
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
Definition: qgsattributeeditorcontainer.h:107
qgsmaplayerstore.h
QgsProject::areaUnits
QgsUnitTypes::AreaUnit areaUnits() const
Convenience function to query default area measurement units for project.
Definition: qgsproject.cpp:3393
QgsReadWriteContext::setProjectTranslator
void setProjectTranslator(QgsProjectTranslator *projectTranslator)
Sets the project translator.
Definition: qgsreadwritecontext.cpp:87
QgsCoordinateReferenceSystem::readXml
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
Definition: qgscoordinatereferencesystem.cpp:1860
QgsProject::homePathChanged
void homePathChanged()
Emitted when the home path of the project changes.
QgsProject::removeMapLayers
void removeMapLayers(const QStringList &layerIds)
Remove a set of layers from the registry by layer ID.
Definition: qgsproject.cpp:3895
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
Qgis::TransactionMode::AutomaticGroups
@ AutomaticGroups
Automatic transactional editing means that on supported datasources (postgres and geopackage database...
QgsProject::error
QString error() const
Returns error message from previous read/write.
Definition: qgsproject.cpp:3137
QgsField::name
QString name
Definition: qgsfield.h:60
QgsAnnotationLayer::LayerOptions
Setting options for loading annotation layers.
Definition: qgsannotationlayer.h:56
QgsMapLayer::setCrs
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Definition: qgsmaplayer.cpp:937
QgsProjectPropertyKey::entryList
void entryList(QStringList &entries) const
Returns any sub-keys contained by this property that do not contain other keys.
Definition: qgsprojectproperty.cpp:426
QgsProject::commitChanges
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...
Definition: qgsproject.cpp:705
QgsProject::saveUser
QString saveUser() const
Returns the user name that did the last save.
Definition: qgsproject.cpp:551
QgsProject::lastModified
QDateTime lastModified() const
Returns last modified time of the project file as returned by the file system (or other project stora...
Definition: qgsproject.cpp:798
QgsProject::removeAttachedFile
bool removeAttachedFile(const QString &path)
Removes the attached file.
Definition: qgsproject.cpp:4081
QgsGroupLayer::LayerOptions
Setting options for loading group layers.
Definition: qgsgrouplayer.h:51
QgsAuxiliaryStorage::extension
static QString extension()
Returns the extension used for auxiliary databases.
Definition: qgsauxiliarystorage.cpp:751
QgsLayerTree::toGroup
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:77
QgsProjectStorage
Abstract interface for project storage - to be implemented by various backends and registered in QgsP...
Definition: qgsprojectstorage.h:36
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:103
QgsProject::setLabelingEngineSettings
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets project's global labeling engine settings.
Definition: qgsproject.cpp:2169
QgsProject::layoutManager
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
Definition: qgsproject.cpp:3461
qgsvectorlayerjoininfo.h
QgsMapLayerStore::layersAdded
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the store.
qgssnappingconfig.h
QgsPropertyDefinition::String
@ String
Any string value.
Definition: qgsproperty.h:61
QgsMapLayerStore::layersRemoved
void layersRemoved(const QStringList &layerIds)
Emitted after one or more layers were removed from the store.
QgsMapLayer::providerType
QString providerType() const
Returns the provider type (provider key) for this layer.
Definition: qgsmaplayer.cpp:1864
QgsProject::editBufferGroup
QgsVectorLayerEditBufferGroup * editBufferGroup()
Returns the edit buffer group.
Definition: qgsproject.cpp:3965
qgsmaplayerlistutils_p.h
QgsEditFormConfig::invisibleRootContainer
QgsAttributeEditorContainer * invisibleRootContainer()
Gets the invisible root container for the drag and drop designer form (EditorLayout::TabLayout).
Definition: qgseditformconfig.cpp:191
QgsProject::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs, bool adjustEllipsoid=false)
Sets the project's native coordinate reference system.
Definition: qgsproject.cpp:872
QgsApplication::requestForTranslatableObjects
void requestForTranslatableObjects(QgsTranslationContext *translationContext)
Emitted when project strings which require translation are being collected for inclusion in a ....
QgsProject::selectionColorChanged
void selectionColorChanged()
Emitted whenever the project's selection color has been changed.
QgsProject::writeProject
void writeProject(QDomDocument &)
Emitted when the project is being written.
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
QgsProjectPropertyKey::removeKey
void removeKey(const QString &keyName)
Removes the specified key.
Definition: qgsprojectproperty.h:232
QgsProjectDisplaySettings::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Definition: qgsprojectdisplaysettings.cpp:114
qgsauxiliarystorage.h
qgsmaplayerfactory.h
qgsapplication.h
QgsBookmarkManager::clear
void clear()
Removes and deletes all bookmarks from the manager.
Definition: qgsbookmarkmanager.cpp:226
QgsProjectStyleSettings::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Definition: qgsprojectstylesettings.cpp:266
QgsProject::labelingEngineSettings
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns project's global labeling engine settings.
Definition: qgsproject.cpp:2175
QgsMapLayerStore::layerWasAdded
void layerWasAdded(QgsMapLayer *layer)
Emitted when a layer was added to the store.
qgsvectortilelayer.h
QgsCoordinateTransformContext::readSettings
void readSettings()
Reads the context's state from application settings.
Definition: qgscoordinatetransformcontext.cpp:296
QgsProject::~QgsProject
~QgsProject() override
Definition: qgsproject.cpp:459
QgsProject::registerTranslatableObjects
void registerTranslatableObjects(QgsTranslationContext *translationContext)
Registers the objects that require translation into the translationContext.
Definition: qgsproject.cpp:623
QgsProject::setProjectColors
void setProjectColors(const QgsNamedColorList &colors)
Sets the colors for the project's color scheme (see QgsProjectColorScheme).
Definition: qgsproject.cpp:4148
QgsProject::absolutePath
QString absolutePath() const
Returns full absolute path to the project folder if the project is stored in a file system - derived ...
Definition: qgsproject.cpp:812
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsUnitTypes::decodeDistanceUnit
static Q_INVOKABLE QgsUnitTypes::DistanceUnit decodeDistanceUnit(const QString &string, bool *ok=nullptr)
Decodes a distance unit from a string.
Definition: qgsunittypes.cpp:165
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsProject::addMapLayers
QList< QgsMapLayer * > addMapLayers(const QList< QgsMapLayer * > &mapLayers, bool addToLegend=true, bool takeOwnership=true)
Add a list of layers to the map of loaded layers.
Definition: qgsproject.cpp:3846
QgsProject::writeMapLayer
void writeMapLayer(QgsMapLayer *mapLayer, QDomElement &layerElem, QDomDocument &doc)
Emitted when a layer is being saved.
qgsFlagValueToKeys
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
Definition: qgis.h:2498
QgsProject::crsChanged
void crsChanged()
Emitted when the CRS of the project has changed.
QgsMapLayerStore
A storage object for map layers, in which the layers are owned by the store and have their lifetime b...
Definition: qgsmaplayerstore.h:35
QgsUnitTypes::AreaSquareMeters
@ AreaSquareMeters
Square meters.
Definition: qgsunittypes.h:95
QgsEditorWidgetSetup::type
QString type() const
Definition: qgseditorwidgetsetup.h:59
QgsMapLayer::FlagDontResolveLayers
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:640
QgsStyleEntityVisitorInterface::NodeType::Layer
@ Layer
Map layer.
qgscombinedstylemodel.h
Qgis::FilePathType::Absolute
@ Absolute
Absolute path.
QgsProjectDisplaySettings::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
Definition: qgsprojectdisplaysettings.cpp:69
QgsVectorLayerEditBufferGroup::clear
void clear()
Remove all layers from this edit buffer group.
Definition: qgsvectorlayereditbuffergroup.cpp:37
QgsPropertiesDefinition
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Definition: qgspropertycollection.h:29
QgsPathResolver::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgspathresolver.cpp:225
QgsSnappingConfig::writeProject
void writeProject(QDomDocument &doc)
Writes the configuration to the specified QGIS project document.
Definition: qgssnappingconfig.cpp:556
QgsProject::layerTreeRoot
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
Definition: qgsproject.cpp:3541
QgsExpressionContextUtils::projectScope
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
Definition: qgsexpressioncontextutils.cpp:291
QgsProject::createAttachedFile
QString createAttachedFile(const QString &nameTemplate)
Attaches a file to the project.
Definition: qgsproject.cpp:4055
QgsProjectPropertyKey::count
int count() const
Returns the number of sub-keys contained by this property.
Definition: qgsprojectproperty.h:272
QgsProjectPropertyKey::clearKeys
virtual void clearKeys()
Deletes any sub-nodes from the property.
Definition: qgsprojectproperty.h:307
QgsProject::oldProjectVersionWarning
Q_DECL_DEPRECATED void oldProjectVersionWarning(const QString &)
Emitted when an old project file is read.
qgsprojectfiletransform.h
QgsAttributeEditorElement::AeTypeContainer
@ AeTypeContainer
A container.
Definition: qgsattributeeditorelement.h:119
QgsProject::setFlags
void setFlags(Qgis::ProjectFlags flags)
Sets the project's flags, which dictate the behavior of the project.
Definition: qgsproject.cpp:508
QgsProject::bookmarkManager
const QgsBookmarkManager * bookmarkManager() const
Returns the project's bookmark manager, which manages bookmarks within the project.
Definition: qgsproject.cpp:3481
QgsDataProvider::EvaluateDefaultValues
@ EvaluateDefaultValues
Evaluate default values on provider side when calling QgsVectorDataProvider::defaultValue( int index ...
Definition: qgsdataprovider.h:95
QgsProject::setPresetHomePath
void setPresetHomePath(const QString &path)
Sets the project's home path.
Definition: qgsproject.cpp:591
QgsLayerTree
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:32
QgsProjectDisplaySettings::reset
void reset()
Resets the settings to a default state.
Definition: qgsprojectdisplaysettings.cpp:37
QgsSnappingConfig::removeLayers
bool removeLayers(const QList< QgsMapLayer * > &layers)
Removes the specified layers from the individual layer configuration.
Definition: qgssnappingconfig.cpp:612
Qgis::ProjectFlag::EvaluateDefaultValuesOnProviderSide
@ EvaluateDefaultValuesOnProviderSide
If set, default values for fields will be evaluated on the provider side when features from the proje...
QgsSnappingConfig::clearIndividualLayerSettings
void clearIndividualLayerSettings()
Removes all individual layer snapping settings.
Definition: qgssnappingconfig.cpp:414
getDataDefinedServerProperties
QgsPropertyCollection getDataDefinedServerProperties(const QDomDocument &doc, const QgsPropertiesDefinition &dataDefinedServerPropertyDefinitions)
Returns the data defined server properties collection found in "doc" to "dataDefinedServerProperties"...
Definition: qgsproject.cpp:1100
QgsProject::requiredLayers
Q_DECL_DEPRECATED QSet< QgsMapLayer * > requiredLayers() const
Returns a set of map layers that are required in the project and therefore they should not get remove...
Definition: qgsproject.cpp:4118
QgsProjectStyleSettings::setRandomizeDefaultSymbolColor
void setRandomizeDefaultSymbolColor(bool randomized)
Sets whether the default symbol fill color is randomized.
Definition: qgsprojectstylesettings.h:108
QgsCoordinateReferenceSystem::fromSrsId
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
Definition: qgscoordinatereferencesystem.cpp:235
QgsCoordinateTransformContext::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, QStringList &missingTransforms)
Reads the context's state from a DOM element.
Definition: qgscoordinatetransformcontext.cpp:198
QgsProject::removeMapLayer
void removeMapLayer(const QString &layerId)
Remove a layer from the registry by layer ID.
Definition: qgsproject.cpp:3907
QgsProject::topologicalEditing
bool topologicalEditing
Definition: qgsproject.h:120
QgsArchive::addFile
void addFile(const QString &filename)
Add a new file to this archive.
Definition: qgsarchive.cpp:107
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsProjectBadLayerHandler::handleBadLayers
virtual void handleBadLayers(const QList< QDomNode > &layers)
This method will be called whenever the project tries to load layers which cannot be accessed.
Definition: qgsprojectbadlayerhandler.cpp:23
qgspointcloudlayer.h
QgsProject::timeSettings
const QgsProjectTimeSettings * timeSettings() const
Returns the project's time settings, which contains the project's temporal range and other time based...
Definition: qgsproject.cpp:3511
QgsProject::nonIdentifiableLayersChanged
Q_DECL_DEPRECATED void nonIdentifiableLayersChanged(QStringList nonIdentifiableLayers)
Emitted when the list of layer which are excluded from map identification changes.
QgsVectorLayer::commitChanges
Q_INVOKABLE bool commitChanges(bool stopEditing=true)
Attempts to commit to the underlying data provider any buffered changes made since the last to call t...
Definition: qgsvectorlayer.cpp:3485
Qgis::AvoidIntersectionsMode::AllowIntersections
@ AllowIntersections
Overlap with any feature allowed when digitizing new features.
QgsProject::setAvoidIntersectionsLayers
void setAvoidIntersectionsLayers(const QList< QgsVectorLayer * > &layers)
Sets the list of layers with which intersections should be avoided.
Definition: qgsproject.cpp:2204
QgsProject::setMapScales
Q_DECL_DEPRECATED void setMapScales(const QVector< double > &scales)
Sets the list of custom project map scales.
Definition: qgsproject.cpp:4196
QgsVectorLayer::commitErrors
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
Definition: qgsvectorlayer.cpp:3559
QgsMapLayerFactory::typeFromString
static QgsMapLayerType typeFromString(const QString &string, bool &ok)
Returns the map layer type corresponding a string value.
Definition: qgsmaplayerfactory.cpp:27
QgsProject::reloadAllLayers
void reloadAllLayers()
Reload all registered layer's provider data caches, synchronising the layer with any changes in the d...
Definition: qgsproject.cpp:3945
QgsAnnotationLayer::isEmpty
bool isEmpty() const
Returns true if the annotation layer is empty and contains no annotations.
Definition: qgsannotationlayer.cpp:208
qgsgrouplayer.h
QgsRelationManager::relations
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
Definition: qgsrelationmanager.cpp:54
qgsvectorlayerjoinbuffer.h
qgsdatasourceuri.h
QgsCoordinateReferenceSystem::writeXml
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
Definition: qgscoordinatereferencesystem.cpp:1980
QgsProject::projectSaved
void projectSaved()
Emitted when the project file has been written and closed.
QgsProject::loadingLayer
void loadingLayer(const QString &layerName)
Emitted when a layer is loaded.
geoNone
CONSTLATIN1STRING geoNone()
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.h:2738
QgsProject::readVersionMismatchOccurred
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...
QgsMapLayerType::GroupLayer
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
QgsLabelingEngineSettings
Stores global configuration for labeling engine.
Definition: qgslabelingenginesettings.h:31
findKey_
QgsProjectProperty * findKey_(const QString &scope, const QString &key, QgsProjectPropertyKey &rootProperty)
Returns the property that matches the given key sequence, if any.
Definition: qgsproject.cpp:146
QgsTransaction::supportsTransaction
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if the provider of a given layer supports transactions.
Definition: qgstransaction.cpp:195
dump_
void dump_(const QgsProjectPropertyKey &topQgsPropertyKey)
Definition: qgsproject.cpp:1037
QgsVectorLayer::rollBack
Q_INVOKABLE bool rollBack(bool deleteBuffer=true)
Stops a current editing operation and discards any uncommitted edits.
Definition: qgsvectorlayer.cpp:3564
QgsProject::accept
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Definition: qgsproject.cpp:4243
QgsUnitTypes::toString
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Definition: qgsunittypes.cpp:199
QgsProject::flags
Qgis::ProjectFlags flags() const
Returns the project's flags, which dictate the behavior of the project.
Definition: qgsproject.h:199
QgsProjectArchive::projectFile
QString projectFile() const
Returns the current .qgs project file or an empty string if there's none.
Definition: qgsarchive.cpp:134
QgsProject::backgroundColorChanged
void backgroundColorChanged()
Emitted whenever the project's canvas background color has been changed.
QgsProject::setInstance
static void setInstance(QgsProject *project)
Set the current project singleton instance to project.
Definition: qgsproject.cpp:474
addKey_
QgsProjectProperty * addKey_(const QString &scope, const QString &key, QgsProjectPropertyKey *rootProperty, const QVariant &value, bool &propertiesModified)
Adds the given key and value.
Definition: qgsproject.cpp:223
QgsMapLayerStore::layersWillBeRemoved
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the store.
QgsLayerTreeLayer
Layer tree node points to a map layer.
Definition: qgslayertreelayer.h:43
QgsMapLayerType::RasterLayer
@ RasterLayer
Raster layer.
QgsProject::useProjectScales
Q_DECL_DEPRECATED bool useProjectScales() const
Returns true if project mapScales() are enabled.
Definition: qgsproject.cpp:4211
QgsVectorLayerEditBufferGroup::rollBack
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true)
Stop editing and discard the edits.
Definition: qgsvectorlayereditbuffergroup.cpp:326
QgsProject::projectColorsChanged
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
QgsLayerTreeNode::writeXml
virtual void writeXml(QDomElement &parentElement, const QgsReadWriteContext &context)=0
Write layer tree to XML.
qgsprojectbadlayerhandler.h
qgstransactiongroup.h
_getProperties
void _getProperties(const QDomDocument &doc, QgsProjectPropertyKey &project_properties)
Restores any optional properties found in "doc" to "properties".
Definition: qgsproject.cpp:1071
QgsProject::readMapLayer
void readMapLayer(QgsMapLayer *mapLayer, const QDomElement &layerNode)
Emitted after the basic initialization of a layer from the project file is done.
QgsProjectBadLayerHandler
Interface for classes that handle missing layer files when reading project file.
Definition: qgsprojectbadlayerhandler.h:27
QgsProject::readPath
QString readPath(const QString &filename) const
Transforms a filename read from the project file to an absolute path.
Definition: qgsproject.cpp:3122
QgsLayerTreeGroup
Layer tree group node serves as a container for layers and further groups.
Definition: qgslayertreegroup.h:40
qgsvectordataprovider.h
Qgis::FilePathType
FilePathType
File path types.
Definition: qgis.h:751
QgsProjectMetadata::setAuthor
void setAuthor(const QString &author)
Sets the project author string.
Definition: qgsprojectmetadata.cpp:89
QgsCoordinateReferenceSystem::toWkt
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1810
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:977
QgsAnnotationManager
Manages storage of a set of QgsAnnotation annotation objects.
Definition: qgsannotationmanager.h:44
QgsApplication::collectTranslatableObjects
void collectTranslatableObjects(QgsTranslationContext *translationContext)
Emits the signal to collect all the strings of .qgs to be included in ts file.
Definition: qgsapplication.cpp:2013
QgsLayerTreeGroup::insertChildNodes
void insertChildNodes(int index, const QList< QgsLayerTreeNode * > &nodes)
Insert existing nodes at specified position.
Definition: qgslayertreegroup.cpp:113
QgsProject::fileInfo
Q_DECL_DEPRECATED QFileInfo fileInfo() const
Returns QFileInfo object for the project's associated file.
Definition: qgsproject.cpp:788
QgsApplication::profiler
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
Definition: qgsapplication.cpp:549
QgsLogger::warning
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
QgsProject::mapLayersByShortName
QList< QgsMapLayer * > mapLayersByShortName(const QString &shortName) const
Retrieves a list of matching registered layers by layer shortName.
Definition: qgsproject.cpp:3690
QgsUnitTypes::DistanceMeters
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
QgsPropertyDefinition
Definition for a property.
Definition: qgsproperty.h:46
QgsProject::setRequiredLayers
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...
Definition: qgsproject.cpp:4133
QgsMapLayer::isEditable
virtual bool isEditable() const
Returns true if the layer can be edited.
Definition: qgsmaplayer.cpp:2021
QgsProject::setTopologicalEditing
void setTopologicalEditing(bool enabled)
Convenience function to set topological editing.
Definition: qgsproject.cpp:3365
QgsTranslationContext::setFileName
void setFileName(const QString &fileName)
Sets the fileName of the TS file.
Definition: qgstranslationcontext.cpp:40
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:169
QgsUnitTypes::decodeAreaUnit
static Q_INVOKABLE QgsUnitTypes::AreaUnit decodeAreaUnit(const QString &string, bool *ok=nullptr)
Decodes an areal unit from a string.
Definition: qgsunittypes.cpp:657
QgsUnitTypes::AreaUnit
AreaUnit
Units of area.
Definition: qgsunittypes.h:93
QgsSnappingConfig
This is a container for configuration of the snapping of the project.
Definition: qgssnappingconfig.h:37
QgsProject::setDirty
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:576
QgsTranslationContext
Used for the collecting of strings from projects for translation and creation of ts files.
Definition: qgstranslationcontext.h:35
QgsRuntimeProfiler::clear
void clear(const QString &group="startup")
clear Clear all profile data.
Definition: qgsruntimeprofiler.cpp:273
QgsWeakMapLayerPointer
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:2146
QgsApplication::settingsLocaleUserLocale
static const QgsSettingsEntryString settingsLocaleUserLocale
Settings entry locale user locale.
Definition: qgsapplication.h:1029
qgsannotationmanager.h
QgsProject::readDoubleEntry
double readDoubleEntry(const QString &scope, const QString &key, double def=0, bool *ok=nullptr) const
Reads a double from the specified scope and key.
Definition: qgsproject.cpp:2999
typeName
const QString & typeName
Definition: qgswfsgetfeature.cpp:109
QgsProject::mapThemeCollection
QgsMapThemeCollection mapThemeCollection
Definition: qgsproject.h:112
QgsProject::startEditing
bool startEditing(QgsVectorLayer *vectorLayer=nullptr)
Makes the layer editable.
Definition: qgsproject.cpp:686
QgsProjectProperty::isKey
virtual bool isKey() const =0
Returns true if the property is a QgsProjectPropertyKey.
QgsStyleEntityVisitorInterface::Node
Contains information relating to a node (i.e.
Definition: qgsstyleentityvisitor.h:110
QgsProject::setSnappingConfig
void setSnappingConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration for this project.
Definition: qgsproject.cpp:1193
QgsProjectVersion::text
QString text() const
Returns a string representation of the version.
Definition: qgsprojectversion.cpp:77
QgsProjectViewSettings
Contains settings and properties relating to how a QgsProject should be displayed inside map canvas,...
Definition: qgsprojectviewsettings.h:35
QgsProject::fileName
QString fileName
Definition: qgsproject.h:107
qgsannotationlayer.h
QgsMapLayer::originalXmlProperties
QString originalXmlProperties() const
Returns the XML properties of the original layer as they were when the layer was first read from the ...
Definition: qgsmaplayer.cpp:2161
QgsZipUtils::isZipFile
CORE_EXPORT bool isZipFile(const QString &filename)
Returns true if the file name is a zipped file ( i.e with a '.qgz' extension, false otherwise.
Definition: qgsziputils.cpp:32
QgsCoordinateReferenceSystem::toProj
QString toProj() const
Returns a Proj string representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1293
QgsExpressionNodeFunction
An expression node for expression functions.
Definition: qgsexpressionnodeimpl.h:395
QgsProjectStyleSettings::setDefaultColorRamp
void setDefaultColorRamp(QgsColorRamp *colorRamp)
Sets the project default color ramp.
Definition: qgsprojectstylesettings.cpp:98
QgsProject::transformContextChanged
void transformContextChanged()
Emitted when the project transformContext() is changed.
QgsMapLayer::removeCustomProperty
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
Definition: qgsmaplayer.cpp:2004
QgsBookmarkManager::readXml
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.
Definition: qgsbookmarkmanager.cpp:278
qgslayertree.h
qgsrelationmanager.h
QgsProject::clear
void clear()
Clears the project, removing all settings and resetting it back to an empty, default state.
Definition: qgsproject.cpp:932
QgsProject::setAvoidIntersectionsMode
void setAvoidIntersectionsMode(const Qgis::AvoidIntersectionsMode mode)
Sets the avoid intersections mode.
Definition: qgsproject.cpp:1203
QgsProject::setOriginalPath
void setOriginalPath(const QString &path)
Sets the original path associated with the project.
Definition: qgsproject.cpp:778
QgsProject::QgsProject
QgsProject(QObject *parent=nullptr, Qgis::ProjectCapabilities capabilities=Qgis::ProjectCapability::ProjectStyles)
Create a new QgsProject.
Definition: qgsproject.cpp:369
QgsProjectPropertyKey::setName
void setName(const QString &name)
The name of the property is used as identifier.
Definition: qgsprojectproperty.cpp:474
QgsTranslationContext::setProject
void setProject(QgsProject *project)
Sets the project being translated.
Definition: qgstranslationcontext.cpp:30
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsProject::metadata
QgsProjectMetadata metadata
Definition: qgsproject.h:117
QgsProject::setTitle
void setTitle(const QString &title)
Sets the project's title.
Definition: qgsproject.cpp:491
QgsVectorLayerEditBufferGroup::startEditing
bool startEditing()
Start editing.
Definition: qgsvectorlayereditbuffergroup.cpp:58
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsProject::absoluteFilePath
QString absoluteFilePath() const
Returns full absolute path to the project file if the project is stored in a file system - derived fr...
Definition: qgsproject.cpp:823
QgsProject::setDataDefinedServerProperties
void setDataDefinedServerProperties(const QgsPropertyCollection &properties)
Sets the data defined properties used for overrides in user defined server parameters to properties.
Definition: qgsproject.cpp:676
QgsProjectPropertyKey::setValue
QgsProjectPropertyValue * setValue(const QString &name, const QVariant &value)
Sets the value associated with this key.
Definition: qgsprojectproperty.h:243
qgsmeshlayer.h
QgsLayerTree::clear
void clear()
Clear any information from this layer tree.
Definition: qgslayertree.cpp:153
QgsProjectViewSettings::reset
void reset()
Resets the settings to a default state.
Definition: qgsprojectviewsettings.cpp:30
qgslayerdefinition.h
QgsProjectTimeSettings
Contains temporal settings and properties for the project, this may be used when animating maps or sh...
Definition: qgsprojecttimesettings.h:36
QgsStyleEntityVisitorInterface::visitEnter
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
Definition: qgsstyleentityvisitor.h:169
qgsprojecttimesettings.h
QgsProject::legendLayersAdded
void legendLayersAdded(const QList< QgsMapLayer * > &layers)
Emitted, when a layer was added to the registry and the legend.
QgsProjectStorageRegistry::projectStorageFromUri
QgsProjectStorage * projectStorageFromUri(const QString &uri)
Returns storage implementation if the URI matches one. Returns nullptr otherwise (it is a normal file...
Definition: qgsprojectstorageregistry.cpp:31
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups
static void replaceChildrenOfEmbeddedGroups(QgsLayerTreeGroup *group)
Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers.
Definition: qgslayertreeutils.cpp:387
QgsProjectMetadata::writeMetadataXml
bool writeMetadataXml(QDomElement &metadataElement, QDomDocument &document) const override
Stores state in a DOM node.
Definition: qgsprojectmetadata.cpp:39
Qgis::AvoidIntersectionsMode::AvoidIntersectionsLayers
@ AvoidIntersectionsLayers
Overlap with features from a specified list of layers when digitizing new features not allowed.
QgsProject::setTrustLayerMetadata
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...
Definition: qgsproject.cpp:3992
QgsPropertyCollection
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition: qgspropertycollection.h:318
QgsVectorLayerEditBufferGroup::commitChanges
bool commitChanges(QStringList &commitErrors, bool stopEditing=true)
Attempts to commit any changes to disk.
Definition: qgsvectorlayereditbuffergroup.cpp:115
qgsmapviewsmanager.h
qgstransaction.h
QgsLayerTree::isLayer
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:66
QgsProject::read
bool read(const QString &filename, Qgis::ProjectReadFlags flags=Qgis::ProjectReadFlags())
Reads given project file from the given file.
Definition: qgsproject.cpp:1431
QgsPathResolver::readPath
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Definition: qgspathresolver.cpp:37
QgsMapLayer::source
QString source() const
Returns the source for the layer.
Definition: qgsmaplayer.cpp:300
QgsProjectFileTransform
Class to convert from older project file versions to newer.
Definition: qgsprojectfiletransform.h:37
QgsProjectPropertyKey::name
QString name() const
The name of the property is used as identifier.
Definition: qgsprojectproperty.h:199
qgsprojectviewsettings.h
QgsApplication::userLoginName
static QString userLoginName()
Returns the user's operating system login account name.
Definition: qgsapplication.cpp:1211
getVersion
QgsProjectVersion getVersion(const QDomDocument &doc)
Returns the version string found in the given DOM document.
Definition: qgsproject.cpp:1170
QgsMapLayer::Identifiable
@ Identifiable
If the layer is identifiable using the identify map tool and as a WMS layer.
Definition: qgsmaplayer.h:145
Qgis::ProjectFlag
ProjectFlag
Flags which control the behavior of QgsProjects.
Definition: qgis.h:1808
QgsProject::setNonIdentifiableLayers
Q_DECL_DEPRECATED void setNonIdentifiableLayers(const QList< QgsMapLayer * > &layers)
Set a list of layers which should not be taken into account on map identification.
Definition: qgsproject.cpp:3561
QgsTransaction::connectionString
QString connectionString() const
Returns the connection string of the transaction.
Definition: qgstransaction.cpp:69
QgsProjectPropertyKey
Project property key node.
Definition: qgsprojectproperty.h:183
QgsLayerTreeGroup::findLayerIds
QStringList findLayerIds() const
Find layer IDs used in all layer nodes.
Definition: qgslayertreegroup.cpp:498
QgsProjectElevationProperties::reset
void reset()
Resets the properties to a default state.
Definition: qgsprojectelevationproperties.cpp:32
QgsCoordinateReferenceSystem::mapUnits
QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:215
QgsProject::lastSaveDateTime
QDateTime lastSaveDateTime() const
Returns the date and time when the project was last saved.
Definition: qgsproject.cpp:561
QgsProject::createEmbeddedLayer
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.
Definition: qgsproject.cpp:3163
QgsProject::saveUserFullName
QString saveUserFullName() const
Returns the full user name that did the last save.
Definition: qgsproject.cpp:556
Qgis::AvoidIntersectionsMode
AvoidIntersectionsMode
Flags which control how intersections of pre-existing feature are handled when digitizing new feature...
Definition: qgis.h:1915
QgsCoordinateTransformContext::writeXml
void writeXml(QDomElement &element, const QgsReadWriteContext &context) const
Writes the context's state to a DOM element.
Definition: qgscoordinatetransformcontext.cpp:266
QgsProject::baseName
QString baseName() const
Returns the base name of the project file without the path and without extension - derived from fileN...
Definition: qgsproject.cpp:834
qgsprojectstorage.h
QgsMapLayerStore::layerRemoved
void layerRemoved(const QString &layerId)
Emitted after a layer was removed from the store.
QgsSnappingConfig::addLayers
bool addLayers(const QList< QgsMapLayer * > &layers)
Adds the specified layers as individual layers to the configuration with standard configuration.
Definition: qgssnappingconfig.cpp:591
QgsLayerTree::clone
QgsLayerTree * clone() const override
Create a copy of the node. Returns new instance.
Definition: qgslayertree.cpp:148
QgsSettingsEntryByReference::value
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
Definition: qgssettingsentry.h:379
QgsProjectViewSettings::mapScales
QVector< double > mapScales() const
Returns the list of custom project map scales.
Definition: qgsprojectviewsettings.cpp:115
QgsProject::layerIsEmbedded
QString layerIsEmbedded(const QString &id) const
Returns the source project file path if the layer with matching id is embedded from other project fil...
Definition: qgsproject.cpp:3153
QgsLayerTreeUtils::storeOriginalLayersProperties
static void storeOriginalLayersProperties(QgsLayerTreeGroup *group, const QDomDocument *doc)
Stores in a layer's originalXmlProperties the layer properties information.
Definition: qgslayertreeutils.cpp:314
QgsLayerTreeNode::setCustomProperty
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.
Definition: qgslayertreenode.cpp:208
QgsProjectTimeSettings::writeXml
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Definition: qgsprojecttimesettings.cpp:71
QgsProject::defaultCrsForNewLayers
QgsCoordinateReferenceSystem defaultCrsForNewLayers() const
Returns the default CRS for new layers based on the settings and the current project CRS.
Definition: qgsproject.cpp:3970
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsProject::presetHomePath
QString presetHomePath() const
Returns any manual project home path setting, or an empty string if not set.
Definition: qgsproject.cpp:3451
QgsProject::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgsproject.cpp:3127
QgsProject::validCount
int validCount() const
Returns the number of registered valid layers.
Definition: qgsproject.cpp:3675
QgsStyle::triggerIconRebuild
void triggerIconRebuild()
Triggers emission of the rebuildIconPreviews() signal.
Definition: qgsstyle.cpp:3054
QgsVectorLayer::editFormConfig
QgsEditFormConfig editFormConfig
Definition: qgsvectorlayer.h:398
QgsLayerTreeNode::customProperty
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.
Definition: qgslayertreenode.cpp:217
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsAttributeEditorContainer
This is a container for attribute editors, used to group them visually in the attribute form if it is...
Definition: qgsattributeeditorcontainer.h:27
QgsMapLayer::readLayerXml
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags())
Sets state from DOM document.
Definition: qgsmaplayer.cpp:339
QgsAnnotationLayer
Represents a map layer containing a set of georeferenced annotations, e.g. markers,...
Definition: qgsannotationlayer.h:46
QgsProject::snappingConfig
QgsSnappingConfig snappingConfig
Definition: qgsproject.h:113
QgsProjectPropertyKey::isEmpty
bool isEmpty() const
Returns true if this property contains no sub-keys.
Definition: qgsprojectproperty.h:277
QgsProjectStyleSettings::reset
void reset()
Resets the settings to a default state.
Definition: qgsprojectstylesettings.cpp:113
QgsLayerTreeLayer::resolveReferences
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Resolves reference to layer from stored layer ID (if it has not been resolved already)
Definition: qgslayertreelayer.cpp:50
QgsProject::takeMapLayer
QgsMapLayer * takeMapLayer(QgsMapLayer *layer)
Takes a layer from the registry.
Definition: qgsproject.cpp:3919
QgsProject::generateTsFile
void generateTsFile(const QString &locale)
Triggers the collection strings of .qgs to be included in ts file and calls writeTsFile()
Definition: qgsproject.cpp:4216
QgsAnnotationLayer::reset
void reset()
Resets the annotation layer to a default state, and clears all items from it.
Definition: qgsannotationlayer.cpp:126
QgsScopedRuntimeProfile
Scoped object for logging of the runtime for a single operation or group of operations.
Definition: qgsruntimeprofiler.h:327
QgsProjectViewSettings::setMapScales
void setMapScales(const QVector< double > &scales)
Sets the list of custom project map scales.
Definition: qgsprojectviewsettings.cpp:101
qgsEnumKeyToValue
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:2459
Qgis::ProjectFlag::RememberLayerEditStatusBetweenSessions
@ RememberLayerEditStatusBetweenSessions
If set, then any layers set to be editable will be stored in the project and immediately made editabl...
QgsLayerTreeNode::children
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
Definition: qgslayertreenode.h:121
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
QgsProject::ellipsoidChanged
void ellipsoidChanged(const QString &ellipsoid)
Emitted when the project ellipsoid is changed.
QgsProject::labelingEngineSettingsChanged
void labelingEngineSettingsChanged()
Emitted when global configuration of the labeling engine changes.
QgsProjectPropertyKey::readXml
bool readXml(const QDomNode &keyNode) override
Restores the property hierarchy from a specified DOM node.
Definition: qgsprojectproperty.cpp:354
QgsProject::isDirty
bool isDirty() const
Returns true if the project has been modified since the last write()
Definition: qgsproject.cpp:571
QgsProjectPropertyKey::value
QVariant value() const override
If this key has a value, it will be stored by its name in its properties.
Definition: qgsprojectproperty.cpp:281
QgsProject::createExpressionContextScope
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsproject.cpp:2224
qgspluginlayer.h
QgsLayerTreeGroup::name
QString name() const override
Returns the group's name.
Definition: qgslayertreegroup.cpp:53
QgsProjectViewSettings::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
Definition: qgsprojectviewsettings.cpp:144
QgsProject::metadataChanged
void metadataChanged()
Emitted when the project's metadata is changed.
QgsProject::setMetadata
void setMetadata(const QgsProjectMetadata &metadata)
Sets the project's metadata store.
Definition: qgsproject.cpp:4105
QgsRelation
Definition: qgsrelation.h:42
QgsAuxiliaryStorage
Class providing some utility methods to manage auxiliary storage.
Definition: qgsauxiliarystorage.h:291
QgsProject::setAreaUnits
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the default area measurement units for the project.
Definition: qgsproject.cpp:3405
QgsProject::attachmentIdentifier
QString attachmentIdentifier(const QString &attachedFile) const
Returns an identifier for an attachment file path An attachment identifier is a string which does not...
Definition: qgsproject.cpp:4086
qgslayertreeutils.h
QgsCoordinateReferenceSystem::authid
QString authid
Definition: qgscoordinatereferencesystem.h:217
QgsProject::avoidIntersectionsModeChanged
void avoidIntersectionsModeChanged()
Emitted whenever the avoid intersections mode has changed.
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath
static void updateEmbeddedGroupsProjectPath(QgsLayerTreeGroup *group, const QgsProject *project)
Updates an embedded group from a project.
Definition: qgslayertreeutils.cpp:408
QgsAbstractMetadataBase::KeywordMap
QMap< QString, QStringList > KeywordMap
Map of vocabulary string to keyword list.
Definition: qgsabstractmetadatabase.h:78
QgsLayerDefinition::DependencySorter
Class used to work with layer dependencies stored in a XML project or layer definition file.
Definition: qgslayerdefinition.h:114
QgsLayerTree::readLayerOrderFromXml
void readLayerOrderFromXml(const QDomElement &doc)
Load the layer order from an XML element.
Definition: qgslayertree.cpp:244
QgsProject::elevationProperties
const QgsProjectElevationProperties * elevationProperties() const
Returns the project's elevation properties, which contains the project's elevation related settings.
Definition: qgsproject.cpp:3521
QgsProject::isDirtyChanged
void isDirtyChanged(bool dirty)
Emitted when the project dirty status changes.
QgsProject::transactionMode
Qgis::TransactionMode transactionMode() const
Returns the transaction mode.
Definition: qgsproject.cpp:3633
QgsProject::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsproject.cpp:2214
QgsMapLayer::Removable
@ Removable
If the layer can be removed from the project. The layer will not be removable from the legend menu en...
Definition: qgsmaplayer.h:146
QgsProject::transactionGroup
QgsTransactionGroup * transactionGroup(const QString &providerKey, const QString &connString)
Returns the matching transaction group from a provider key and connection string.
Definition: qgsproject.cpp:3960
QgsProject::dumpProperties
void dumpProperties() const
Dump out current project properties to stderr.
Definition: qgsproject.cpp:3089
QgsProject::nonIdentifiableLayers
QStringList nonIdentifiableLayers
Definition: qgsproject.h:106
qgsbookmarkmanager.h
QgsCoordinateReferenceSystem::ellipsoidAcronym
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
Definition: qgscoordinatereferencesystem.cpp:1251
QgsProjectArchive
Class allowing to manage the zip/unzip actions on project file.
Definition: qgsarchive.h:121
QgsArchive
Class allowing to manage the zip/unzip actions.
Definition: qgsarchive.h:35
QgsProject::subkeyList
QStringList subkeyList(const QString &scope, const QString &key) const
Returns a list of child keys which contain other keys that exist within the the specified scope and k...
Definition: qgsproject.cpp:3072
QgsProject::readProjectWithContext
void readProjectWithContext(const QDomDocument &, QgsReadWriteContext &context)
Emitted when a project is being read.
QgsAttributeEditorElement::name
QString name() const
Returns the name of this element.
Definition: qgsattributeeditorelement.h:156
QgsAuxiliaryLayer::auxiliaryFields
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
Definition: qgsauxiliarystorage.cpp:192
QgsProjectArchive::auxiliaryStorageFile
QString auxiliaryStorageFile() const
Returns the current .qgd auxiliary storage file or an empty string if there's none.
Definition: qgsarchive.cpp:160
QgsProject::evaluateDefaultValues
Q_DECL_DEPRECATED bool evaluateDefaultValues() const
Should default values be evaluated on provider side when requested and not when committed.
Definition: qgsproject.cpp:3355
QgsMapThemeCollection
Container class that allows storage of map themes consisting of visible map layers and layer styles.
Definition: qgsmapthemecollection.h:44
QgsProject::customVariablesChanged
void customVariablesChanged()
Emitted whenever the expression variables stored in the project have been changed.
QgsProject::lastSaveVersion
QgsProjectVersion lastSaveVersion() const
Returns the QGIS version which the project was last saved using.
Definition: qgsproject.cpp:566
QgsLayerTreeGroup::findGroups
QList< QgsLayerTreeGroup * > findGroups(bool recursive=false) const
Find group layer nodes.
Definition: qgslayertreegroup.cpp:310
QgsProject::setDistanceUnits
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the default distance measurement units for the project.
Definition: qgsproject.cpp:3388
QgsProject::readListEntry
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Reads a string list from the specified scope and key.
Definition: qgsproject.cpp:2916
qgslogger.h
QgsProject::autoTransaction
Q_DECL_DEPRECATED bool autoTransaction() const
Transactional editing means that on supported datasources (postgres databases) the edit state of all ...
Definition: qgsproject.cpp:3610
QgsLayerTreeGroup::clone
QgsLayerTreeGroup * clone() const override
Returns a clone of the group.
Definition: qgslayertreegroup.cpp:409
QgsReadWriteContext::takeMessages
QList< QgsReadWriteContext::ReadWriteMessage > takeMessages()
Returns the stored messages and remove them.
Definition: qgsreadwritecontext.cpp:93
QgsProjectPropertyKey::writeXml
bool writeXml(const QString &nodeName, QDomElement &element, QDomDocument &document) override
Writes the property hierarchy to a specified DOM element.
Definition: qgsprojectproperty.cpp:402
QgsProjectElevationProperties::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the property state from a DOM element.
Definition: qgsprojectelevationproperties.cpp:44
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsProject::count
int count() const
Returns the number of registered layers.
Definition: qgsproject.cpp:3670
QgsProjectTimeSettings::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
Definition: qgsprojecttimesettings.cpp:48
QgsField::editorWidgetSetup
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:602
qgsprojectversion.h
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
Qgis::TransactionMode
TransactionMode
Transaction mode.
Definition: qgis.h:1744
QgsProject::readLayer
bool readLayer(const QDomNode &layerNode)
Reads the layer described in the associated DOM node.
Definition: qgsproject.cpp:2432
QgsAnnotationLayer::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context) override
Sets the coordinate transform context to transformContext.
Definition: qgsannotationlayer.cpp:329
QgsLayerTreeNode::removeCustomProperty
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file.
Definition: qgslayertreenode.cpp:222
QgsProject::snappingConfigChanged
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsProject::registerTranslatableContainers
void registerTranslatableContainers(QgsTranslationContext *translationContext, QgsAttributeEditorContainer *parent, const QString &layerId)
Registers the containers that require translation into the translationContext.
Definition: qgsproject.cpp:605
QgsLayerTreeGroup::findGroup
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name.
Definition: qgslayertreegroup.cpp:290
QgsApplication::pluginLayerRegistry
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
Definition: qgsapplication.cpp:2415
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsMapLayerType::PointCloudLayer
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
qgsprojectdisplaysettings.h
QgsScopedExpressionFunction
Expression function for use within a QgsExpressionContextScope. This differs from a standard QgsExpre...
Definition: qgsexpressioncontext.h:39
QgsLayerTree::isGroup
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:56
QgsAbstractMetadataBase::keywords
QgsAbstractMetadataBase::KeywordMap keywords() const
Returns the keywords map, which is a set of descriptive keywords associated with the resource.
Definition: qgsabstractmetadatabase.cpp:86
QgsProject::ellipsoid
QString ellipsoid
Definition: qgsproject.h:111
QgsLayerTreeRegistryBridge
Listens to the updates in map layer registry and does changes in layer tree.
Definition: qgslayertreeregistrybridge.h:44
QgsProject::resolveAttachmentIdentifier
QString resolveAttachmentIdentifier(const QString &identifier) const
Resolves an attachment identifier to a attachment file path.
Definition: qgsproject.cpp:4091
QgsProject::crs
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:109
QgsMapLayerStore::layerWillBeRemoved
void layerWillBeRemoved(const QString &layerId)
Emitted when a layer is about to be removed from the store.
QgsPathResolver
Resolves relative paths into absolute paths and vice versa. Used for writing.
Definition: qgspathresolver.h:31
QgsProjectProperty
An Abstract Base Class for QGIS project property hierarchys.
Definition: qgsprojectproperty.h:50
QgsProject::setUseProjectScales
Q_DECL_DEPRECATED void setUseProjectScales(bool enabled)
Sets whether project mapScales() are enabled.
Definition: qgsproject.cpp:4206
QgsProject::mainAnnotationLayer
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
Definition: qgsproject.cpp:3925
QgsProject::missingDatumTransforms
void missingDatumTransforms(const QStringList &missingTransforms)
Emitted when datum transforms stored in the project are not available locally.
QgsProject::translate
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.
Definition: qgsproject.cpp:4227
Qgis::TransactionMode::Disabled
@ Disabled
Edits are buffered locally and sent to the provider when toggling layer editing mode.
QgsProject::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the project's coordinate transform context, which stores various information regarding which dat...
Definition: qgsproject.cpp:916
qgsproject.h
QgsProject::setTransactionMode
bool setTransactionMode(Qgis::TransactionMode transactionMode)
Set transaction mode.
Definition: qgsproject.cpp:3638
QgsProject::mapScalesChanged
Q_DECL_DEPRECATED void mapScalesChanged()
Emitted when the list of custom project map scales changes.
Qgis::SymbolType::Marker
@ Marker
Marker symbol.
QgsMapLayerType::PluginLayer
@ PluginLayer
Plugin based layer.
QgsProjectVersion
A class to describe the version of a project.
Definition: qgsprojectversion.h:32
QgsProject::isZipped
bool isZipped() const
Returns true if the project comes from a zip archive, false otherwise.
Definition: qgsproject.cpp:3841
QgsProject::layerLoaded
void layerLoaded(int i, int n)
Emitted when a layer from a projects was read.
QgsProject::readNumEntry
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
Reads an integer from the specified scope and key.
Definition: qgsproject.cpp:2972
QgsProject::backgroundColor
QColor backgroundColor
Definition: qgsproject.h:118
QgsTransactionGroup::addLayer
bool addLayer(QgsVectorLayer *layer)
Add a layer to this transaction group.
Definition: qgstransactiongroup.cpp:32
QgsSnappingConfig::reset
void reset()
reset to default values
Definition: qgssnappingconfig.cpp:189
qgsstyleentityvisitor.h
QgsVectorLayer::loadAuxiliaryLayer
bool loadAuxiliaryLayer(const QgsAuxiliaryStorage &storage, const QString &key=QString())
Loads the auxiliary layer for this vector layer.
Definition: qgsvectorlayer.cpp:5468
QgsProject::removeEntry
bool removeEntry(const QString &scope, const QString &key)
Remove the given key from the specified scope.
Definition: qgsproject.cpp:3043
QgsProject::loadingLayerMessageReceived
void loadingLayerMessageReceived(const QString &layerName, const QList< QgsReadWriteContext::ReadWriteMessage > &messages)
Emitted when loading layers has produced some messages.
QgsProjectElevationProperties::writeXml
QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns a DOM element representing the properties.
Definition: qgsprojectelevationproperties.cpp:70
QgsProject::setSelectionColor
void setSelectionColor(const QColor &color)
Sets the color used to highlight selected features.
Definition: qgsproject.cpp:4182
QgsProjectMetadata::setCreationDateTime
void setCreationDateTime(const QDateTime &creationDateTime)
Sets the project's creation date/timestamp.
Definition: qgsprojectmetadata.cpp:99
QgsAbstractPropertyCollection::writeXml
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Definition: qgspropertycollection.cpp:99
Qgis::TransactionMode::BufferedGroups
@ BufferedGroups
Buffered transactional editing means that all editable layers in the buffered transaction group are t...
qgsprojectelevationproperties.h
QgsApplication::userFullName
static QString userFullName()
Returns the user's operating system login account full display name.
Definition: qgsapplication.cpp:1246
QgsProject::topologicalEditingChanged
void topologicalEditingChanged()
Emitted when the topological editing flag has changed.
qgsmessagelog.h
QgsField::alias
QString alias
Definition: qgsfield.h:61
QgsProject::addMapLayer
QgsMapLayer * addMapLayer(QgsMapLayer *mapLayer, bool addToLegend=true, bool takeOwnership=true)
Add a layer to the map of loaded layers.
Definition: qgsproject.cpp:3886
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50
QgsProjectViewSettings::useProjectScales
bool useProjectScales() const
Returns true if project mapScales() are enabled.
Definition: qgsprojectviewsettings.cpp:129
QgsMapLayer::type
QgsMapLayerType type
Definition: qgsmaplayer.h:80