QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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 "qgspluginlayer.h"
28 #include "qgspluginlayerregistry.h"
30 #include "qgssnappingconfig.h"
31 #include "qgspathresolver.h"
32 #include "qgsprojectstorage.h"
34 #include "qgsprojectversion.h"
35 #include "qgsrasterlayer.h"
36 #include "qgsreadwritecontext.h"
37 #include "qgsrectangle.h"
38 #include "qgsrelationmanager.h"
39 #include "qgsannotationmanager.h"
40 #include "qgsvectorlayerjoininfo.h"
41 #include "qgsmapthemecollection.h"
42 #include "qgslayerdefinition.h"
43 #include "qgsunittypes.h"
44 #include "qgstransaction.h"
45 #include "qgstransactiongroup.h"
46 #include "qgsvectordataprovider.h"
48 #include "qgssettings.h"
49 #include "qgsmaplayerlistutils.h"
50 #include "qgsmeshlayer.h"
51 #include "qgslayoutmanager.h"
52 #include "qgsbookmarkmanager.h"
53 #include "qgsmaplayerstore.h"
54 #include "qgsziputils.h"
55 #include "qgsauxiliarystorage.h"
56 #include "qgssymbollayerutils.h"
57 #include "qgsapplication.h"
59 #include "qgsstyleentityvisitor.h"
60 #include "qgsprojectviewsettings.h"
62 #include "qgsprojecttimesettings.h"
63 #include "qgsvectortilelayer.h"
64 #include "qgsruntimeprofiler.h"
65 #include "qgsannotationlayer.h"
66 
67 #include <algorithm>
68 #include <QApplication>
69 #include <QFileInfo>
70 #include <QDomNode>
71 #include <QObject>
72 #include <QTextStream>
73 #include <QTemporaryFile>
74 #include <QDir>
75 #include <QUrl>
76 
77 
78 #ifdef _MSC_VER
79 #include <sys/utime.h>
80 #else
81 #include <utime.h>
82 #endif
83 
84 // canonical project instance
85 QgsProject *QgsProject::sProject = nullptr;
86 
95 QStringList makeKeyTokens_( const QString &scope, const QString &key )
96 {
97  QStringList keyTokens = QStringList( scope );
98 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
99  keyTokens += key.split( '/', QString::SkipEmptyParts );
100 #else
101  keyTokens += key.split( '/', Qt::SkipEmptyParts );
102 #endif
103 
104  // be sure to include the canonical root node
105  keyTokens.push_front( QStringLiteral( "properties" ) );
106 
107  //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.
108  for ( int i = 0; i < keyTokens.size(); ++i )
109  {
110  QString keyToken = keyTokens.at( i );
111 
112  //invalid chars in XML are found at http://www.w3.org/TR/REC-xml/#NT-NameChar
113  //note : it seems \x10000-\xEFFFF is valid, but it when added to the regexp, a lot of unwanted characters remain
114  QString nameCharRegexp = QStringLiteral( "[^:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x2FF\\x370-\\x37D\\x37F-\\x1FFF\\x200C-\\x200D\\x2070-\\x218F\\x2C00-\\x2FEF\\x3001-\\xD7FF\\xF900-\\xFDCF\\xFDF0-\\xFFFD\\-\\.0-9\\xB7\\x0300-\\x036F\\x203F-\\x2040]" );
115  QString nameStartCharRegexp = QStringLiteral( "^[^:A-Z_a-z\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\x2FF\\x370-\\x37D\\x37F-\\x1FFF\\x200C-\\x200D\\x2070-\\x218F\\x2C00-\\x2FEF\\x3001-\\xD7FF\\xF900-\\xFDCF\\xFDF0-\\xFFFD]" );
116 
117  if ( keyToken.contains( QRegExp( nameCharRegexp ) ) || keyToken.contains( QRegExp( nameStartCharRegexp ) ) )
118  {
119 
120  QString errorString = QObject::tr( "Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
121  QgsMessageLog::logMessage( errorString, QString(), Qgis::Critical );
122 
123  }
124 
125  }
126 
127  return keyTokens;
128 }
129 
130 
131 
141 QgsProjectProperty *findKey_( const QString &scope,
142  const QString &key,
143  QgsProjectPropertyKey &rootProperty )
144 {
145  QgsProjectPropertyKey *currentProperty = &rootProperty;
146  QgsProjectProperty *nextProperty; // link to next property down hierarchy
147 
148  QStringList keySequence = makeKeyTokens_( scope, key );
149 
150  while ( !keySequence.isEmpty() )
151  {
152  // if the current head of the sequence list matches the property name,
153  // then traverse down the property hierarchy
154  if ( keySequence.first() == currentProperty->name() )
155  {
156  // remove front key since we're traversing down a level
157  keySequence.pop_front();
158 
159  if ( 1 == keySequence.count() )
160  {
161  // if we have only one key name left, then return the key found
162  return currentProperty->find( keySequence.front() );
163  }
164  else if ( keySequence.isEmpty() )
165  {
166  // if we're out of keys then the current property is the one we
167  // want; i.e., we're in the rate case of being at the top-most
168  // property node
169  return currentProperty;
170  }
171  else if ( ( nextProperty = currentProperty->find( keySequence.first() ) ) )
172  {
173  if ( nextProperty->isKey() )
174  {
175  currentProperty = static_cast<QgsProjectPropertyKey *>( nextProperty );
176  }
177  else if ( nextProperty->isValue() && 1 == keySequence.count() )
178  {
179  // it may be that this may be one of several property value
180  // nodes keyed by QDict string; if this is the last remaining
181  // key token and the next property is a value node, then
182  // that's the situation, so return the currentProperty
183  return currentProperty;
184  }
185  else
186  {
187  // QgsProjectPropertyValue not Key, so return null
188  return nullptr;
189  }
190  }
191  else
192  {
193  // if the next key down isn't found
194  // then the overall key sequence doesn't exist
195  return nullptr;
196  }
197  }
198  else
199  {
200  return nullptr;
201  }
202  }
203 
204  return nullptr;
205 }
206 
207 
208 
218 QgsProjectProperty *addKey_( const QString &scope,
219  const QString &key,
220  QgsProjectPropertyKey *rootProperty,
221  const QVariant &value,
222  bool &propertiesModified )
223 {
224  QStringList keySequence = makeKeyTokens_( scope, key );
225 
226  // cursor through property key/value hierarchy
227  QgsProjectPropertyKey *currentProperty = rootProperty;
228  QgsProjectProperty *nextProperty; // link to next property down hierarchy
229  QgsProjectPropertyKey *newPropertyKey = nullptr;
230 
231  propertiesModified = false;
232  while ( ! keySequence.isEmpty() )
233  {
234  // if the current head of the sequence list matches the property name,
235  // then traverse down the property hierarchy
236  if ( keySequence.first() == currentProperty->name() )
237  {
238  // remove front key since we're traversing down a level
239  keySequence.pop_front();
240 
241  // if key sequence has one last element, then we use that as the
242  // name to store the value
243  if ( 1 == keySequence.count() )
244  {
245  QgsProjectProperty *property = currentProperty->find( keySequence.front() );
246  if ( !property || property->value() != value )
247  {
248  currentProperty->setValue( keySequence.front(), value );
249  propertiesModified = true;
250  }
251 
252  return currentProperty;
253  }
254  // we're at the top element if popping the keySequence element
255  // will leave it empty; in that case, just add the key
256  else if ( keySequence.isEmpty() )
257  {
258  if ( currentProperty->value() != value )
259  {
260  currentProperty->setValue( value );
261  propertiesModified = true;
262  }
263 
264  return currentProperty;
265  }
266  else if ( ( nextProperty = currentProperty->find( keySequence.first() ) ) )
267  {
268  currentProperty = dynamic_cast<QgsProjectPropertyKey *>( nextProperty );
269 
270  if ( currentProperty )
271  {
272  continue;
273  }
274  else // QgsProjectPropertyValue not Key, so return null
275  {
276  return nullptr;
277  }
278  }
279  else // the next subkey doesn't exist, so add it
280  {
281  if ( ( newPropertyKey = currentProperty->addKey( keySequence.first() ) ) )
282  {
283  currentProperty = newPropertyKey;
284  }
285  continue;
286  }
287  }
288  else
289  {
290  return nullptr;
291  }
292  }
293 
294  return nullptr;
295 }
296 
305 void removeKey_( const QString &scope,
306  const QString &key,
307  QgsProjectPropertyKey &rootProperty )
308 {
309  QgsProjectPropertyKey *currentProperty = &rootProperty;
310 
311  QgsProjectProperty *nextProperty = nullptr; // link to next property down hierarchy
312  QgsProjectPropertyKey *previousQgsPropertyKey = nullptr; // link to previous property up hierarchy
313 
314  QStringList keySequence = makeKeyTokens_( scope, key );
315 
316  while ( ! keySequence.isEmpty() )
317  {
318  // if the current head of the sequence list matches the property name,
319  // then traverse down the property hierarchy
320  if ( keySequence.first() == currentProperty->name() )
321  {
322  // remove front key since we're traversing down a level
323  keySequence.pop_front();
324 
325  // if we have only one key name left, then try to remove the key
326  // with that name
327  if ( 1 == keySequence.count() )
328  {
329  currentProperty->removeKey( keySequence.front() );
330  }
331  // if we're out of keys then the current property is the one we
332  // want to remove, but we can't delete it directly; we need to
333  // delete it from the parent property key container
334  else if ( keySequence.isEmpty() )
335  {
336  previousQgsPropertyKey->removeKey( currentProperty->name() );
337  }
338  else if ( ( nextProperty = currentProperty->find( keySequence.first() ) ) )
339  {
340  previousQgsPropertyKey = currentProperty;
341  currentProperty = dynamic_cast<QgsProjectPropertyKey *>( nextProperty );
342 
343  if ( currentProperty )
344  {
345  continue;
346  }
347  else // QgsProjectPropertyValue not Key, so return null
348  {
349  return;
350  }
351  }
352  else // if the next key down isn't found
353  {
354  // then the overall key sequence doesn't exist
355  return;
356  }
357  }
358  else
359  {
360  return;
361  }
362  }
363 }
364 
365 QgsProject::QgsProject( QObject *parent )
366  : QObject( parent )
367  , mLayerStore( new QgsMapLayerStore( this ) )
368  , mBadLayerHandler( new QgsProjectBadLayerHandler() )
369  , mSnappingConfig( this )
370  , mRelationManager( new QgsRelationManager( this ) )
371  , mAnnotationManager( new QgsAnnotationManager( this ) )
372  , mLayoutManager( new QgsLayoutManager( this ) )
373  , mBookmarkManager( QgsBookmarkManager::createProjectBasedManager( this ) )
374  , mViewSettings( new QgsProjectViewSettings( this ) )
375  , mTimeSettings( new QgsProjectTimeSettings( this ) )
376  , mDisplaySettings( new QgsProjectDisplaySettings( this ) )
377  , mRootGroup( new QgsLayerTree )
378  , mLabelingEngineSettings( new QgsLabelingEngineSettings )
379  , mArchive( new QgsProjectArchive() )
380  , mAuxiliaryStorage( new QgsAuxiliaryStorage() )
381 {
382  mProperties.setName( QStringLiteral( "properties" ) );
383 
384  mMainAnnotationLayer = new QgsAnnotationLayer( QObject::tr( "Annotations" ), QgsAnnotationLayer::LayerOptions( mTransformContext ) );
385  mMainAnnotationLayer->setParent( this );
386 
387  clear();
388 
389  // bind the layer tree to the map layer registry.
390  // whenever layers are added to or removed from the registry,
391  // layer tree will be updated
392  mLayerTreeRegistryBridge = new QgsLayerTreeRegistryBridge( mRootGroup, this, this );
393  connect( this, &QgsProject::layersAdded, this, &QgsProject::onMapLayersAdded );
394  connect( this, &QgsProject::layersRemoved, this, [ = ] { cleanTransactionGroups(); } );
395  connect( this, qgis::overload< const QList<QgsMapLayer *> & >::of( &QgsProject::layersWillBeRemoved ), this, &QgsProject::onMapLayersRemoved );
396 
397  // proxy map layer store signals to this
398  connect( mLayerStore.get(), qgis::overload<const QStringList &>::of( &QgsMapLayerStore::layersWillBeRemoved ),
399  this, [ = ]( const QStringList & layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
400  connect( mLayerStore.get(), qgis::overload< const QList<QgsMapLayer *> & >::of( &QgsMapLayerStore::layersWillBeRemoved ),
401  this, [ = ]( const QList<QgsMapLayer *> &layers ) { mProjectScope.reset(); emit layersWillBeRemoved( layers ); } );
402  connect( mLayerStore.get(), qgis::overload< const QString & >::of( &QgsMapLayerStore::layerWillBeRemoved ),
403  this, [ = ]( const QString & layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
404  connect( mLayerStore.get(), qgis::overload< QgsMapLayer * >::of( &QgsMapLayerStore::layerWillBeRemoved ),
405  this, [ = ]( QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWillBeRemoved( layer ); } );
406  connect( mLayerStore.get(), qgis::overload<const QStringList & >::of( &QgsMapLayerStore::layersRemoved ), this,
407  [ = ]( const QStringList & layers ) { mProjectScope.reset(); emit layersRemoved( layers ); } );
408  connect( mLayerStore.get(), &QgsMapLayerStore::layerRemoved, this,
409  [ = ]( const QString & layer ) { mProjectScope.reset(); emit layerRemoved( layer ); } );
410  connect( mLayerStore.get(), &QgsMapLayerStore::allLayersRemoved, this,
411  [ = ]() { mProjectScope.reset(); emit removeAll(); } );
412  connect( mLayerStore.get(), &QgsMapLayerStore::layersAdded, this,
413  [ = ]( const QList< QgsMapLayer * > &layers ) { mProjectScope.reset(); emit layersAdded( layers ); } );
414  connect( mLayerStore.get(), &QgsMapLayerStore::layerWasAdded, this,
415  [ = ]( QgsMapLayer * layer ) { mProjectScope.reset(); emit layerWasAdded( layer ); } );
416 
417  if ( QgsApplication::instance() )
418  {
420  }
421 
422  connect( mLayerStore.get(), qgis::overload< const QList<QgsMapLayer *> & >::of( &QgsMapLayerStore::layersWillBeRemoved ), this,
423  [ = ]( const QList<QgsMapLayer *> &layers )
424  {
425  for ( const auto &layer : layers )
426  {
427  disconnect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
428  }
429  }
430  );
431  connect( mLayerStore.get(), qgis::overload< const QList<QgsMapLayer *> & >::of( &QgsMapLayerStore::layersAdded ), this,
432  [ = ]( const QList<QgsMapLayer *> &layers )
433  {
434  for ( const auto &layer : layers )
435  {
436  connect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
437  }
438  }
439  );
440 
444 }
445 
446 
448 {
449  mIsBeingDeleted = true;
450 
451  clear();
452  delete mBadLayerHandler;
453  delete mRelationManager;
454  delete mLayerTreeRegistryBridge;
455  delete mRootGroup;
456  if ( this == sProject )
457  {
458  sProject = nullptr;
459  }
460 }
461 
463 {
464  sProject = project;
465 }
466 
467 
469 {
470  if ( !sProject )
471  {
472  sProject = new QgsProject;
473  }
474  return sProject;
475 }
476 
477 void QgsProject::setTitle( const QString &title )
478 {
479  if ( title == mMetadata.title() )
480  return;
481 
482  mMetadata.setTitle( title );
483  mProjectScope.reset();
484  emit metadataChanged();
485 
486  setDirty( true );
487 }
488 
489 QString QgsProject::title() const
490 {
491  return mMetadata.title();
492 }
493 
494 QString QgsProject::saveUser() const
495 {
496  return mSaveUser;
497 }
498 
500 {
501  return mSaveUserFull;
502 }
503 
505 {
506  return mSaveDateTime;
507 }
508 
510 {
511  return mSaveVersion;
512 }
513 
515 {
516  return mDirty;
517 }
518 
519 void QgsProject::setDirty( const bool dirty )
520 {
521  if ( dirty && mDirtyBlockCount > 0 )
522  return;
523 
524  if ( mDirty == dirty )
525  return;
526 
527  mDirty = dirty;
528  emit isDirtyChanged( mDirty );
529 }
530 
531 void QgsProject::setPresetHomePath( const QString &path )
532 {
533  if ( path == mHomePath )
534  return;
535 
536  mHomePath = path;
537  mCachedHomePath.clear();
538  mProjectScope.reset();
539 
540  emit homePathChanged();
541 
542  setDirty( true );
543 }
544 
545 void QgsProject::registerTranslatableContainers( QgsTranslationContext *translationContext, QgsAttributeEditorContainer *parent, const QString &layerId )
546 {
547  const QList<QgsAttributeEditorElement *> elements = parent->children();
548 
549  for ( QgsAttributeEditorElement *element : elements )
550  {
551  if ( element->type() == QgsAttributeEditorElement::AeTypeContainer )
552  {
553  QgsAttributeEditorContainer *container = dynamic_cast<QgsAttributeEditorContainer *>( element );
554 
555  translationContext->registerTranslation( QStringLiteral( "project:layers:%1:formcontainers" ).arg( layerId ), container->name() );
556 
557  if ( !container->children().empty() )
558  registerTranslatableContainers( translationContext, container, layerId );
559  }
560  }
561 }
562 
564 {
565  //register layers
566  const QList<QgsLayerTreeLayer *> layers = mRootGroup->findLayers();
567 
568  for ( const QgsLayerTreeLayer *layer : layers )
569  {
570  translationContext->registerTranslation( QStringLiteral( "project:layers:%1" ).arg( layer->layerId() ), layer->name() );
571 
572  QgsMapLayer *mapLayer = layer->layer();
574  {
575  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mapLayer );
576 
577  //register aliases and fields
578  const QgsFields fields = vlayer->fields();
579  for ( const QgsField &field : fields )
580  {
581  QString fieldName;
582  if ( field.alias().isEmpty() )
583  fieldName = field.name();
584  else
585  fieldName = field.alias();
586 
587  translationContext->registerTranslation( QStringLiteral( "project:layers:%1:fieldaliases" ).arg( vlayer->id() ), fieldName );
588 
589  if ( field.editorWidgetSetup().type() == QLatin1String( "ValueRelation" ) )
590  {
591  translationContext->registerTranslation( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( vlayer->id(), field.name() ), field.editorWidgetSetup().config().value( QStringLiteral( "Value" ) ).toString() );
592  }
593  }
594 
595  //register formcontainers
596  registerTranslatableContainers( translationContext, vlayer->editFormConfig().invisibleRootContainer(), vlayer->id() );
597 
598  }
599  }
600 
601  //register layergroups
602  const QList<QgsLayerTreeGroup *> groupLayers = mRootGroup->findGroups();
603  for ( const QgsLayerTreeGroup *groupLayer : groupLayers )
604  {
605  translationContext->registerTranslation( QStringLiteral( "project:layergroups" ), groupLayer->name() );
606  }
607 
608  //register relations
609  const QList<QgsRelation> &relations = mRelationManager->relations().values();
610  for ( const QgsRelation &relation : relations )
611  {
612  translationContext->registerTranslation( QStringLiteral( "project:relations" ), relation.name() );
613  }
614 }
615 
617 {
618  mDataDefinedServerProperties = properties;
619 }
620 
622 {
623  return mDataDefinedServerProperties;
624 }
625 
626 void QgsProject::setFileName( const QString &name )
627 {
628  if ( name == mFile.fileName() )
629  return;
630 
631  QString oldHomePath = homePath();
632 
633  mFile.setFileName( name );
634  mCachedHomePath.clear();
635  mProjectScope.reset();
636 
637  emit fileNameChanged();
638 
639  QString newHomePath = homePath();
640  if ( newHomePath != oldHomePath )
641  emit homePathChanged();
642 
643  setDirty( true );
644 }
645 
646 QString QgsProject::fileName() const
647 {
648  return mFile.fileName();
649 }
650 
651 void QgsProject::setOriginalPath( const QString &path )
652 {
653  mOriginalPath = path;
654 }
655 
657 {
658  return mOriginalPath;
659 }
660 
661 QFileInfo QgsProject::fileInfo() const
662 {
663  return QFileInfo( mFile );
664 }
665 
667 {
669 }
670 
671 QDateTime QgsProject::lastModified() const
672 {
673  if ( QgsProjectStorage *storage = projectStorage() )
674  {
676  storage->readProjectStorageMetadata( mFile.fileName(), metadata );
677  return metadata.lastModified;
678  }
679  else
680  {
681  return QFileInfo( mFile.fileName() ).lastModified();
682  }
683 }
684 
686 {
687  if ( projectStorage() )
688  return QString();
689 
690  if ( mFile.fileName().isEmpty() )
691  return QString(); // this is to protect ourselves from getting current directory from QFileInfo::absoluteFilePath()
692 
693  return QFileInfo( mFile.fileName() ).absolutePath();
694 }
695 
697 {
698  if ( projectStorage() )
699  return QString();
700 
701  if ( mFile.fileName().isEmpty() )
702  return QString(); // this is to protect ourselves from getting current directory from QFileInfo::absoluteFilePath()
703 
704  return QFileInfo( mFile.fileName() ).absoluteFilePath();
705 }
706 
707 QString QgsProject::baseName() const
708 {
709  if ( QgsProjectStorage *storage = projectStorage() )
710  {
712  storage->readProjectStorageMetadata( mFile.fileName(), metadata );
713  return metadata.name;
714  }
715  else
716  {
717  return QFileInfo( mFile.fileName() ).completeBaseName();
718  }
719 }
720 
722 {
723  return mCrs;
724 }
725 
726 void QgsProject::setCrs( const QgsCoordinateReferenceSystem &crs, bool adjustEllipsoid )
727 {
728  if ( crs != mCrs )
729  {
730  mCrs = crs;
731  writeEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectionsEnabled" ), crs.isValid() ? 1 : 0 );
732  mProjectScope.reset();
733  setDirty( true );
734  emit crsChanged();
735  }
736 
737  if ( adjustEllipsoid )
739 }
740 
741 QString QgsProject::ellipsoid() const
742 {
743  if ( !crs().isValid() )
744  return geoNone();
745 
746  return readEntry( QStringLiteral( "Measure" ), QStringLiteral( "/Ellipsoid" ), geoNone() );
747 }
748 
749 void QgsProject::setEllipsoid( const QString &ellipsoid )
750 {
751  if ( ellipsoid == readEntry( QStringLiteral( "Measure" ), QStringLiteral( "/Ellipsoid" ) ) )
752  return;
753 
754  mProjectScope.reset();
755  writeEntry( QStringLiteral( "Measure" ), QStringLiteral( "/Ellipsoid" ), ellipsoid );
756  emit ellipsoidChanged( ellipsoid );
757 }
758 
760 {
761  return mTransformContext;
762 }
763 
765 {
766  if ( context == mTransformContext )
767  return;
768 
769  mTransformContext = context;
770  mProjectScope.reset();
771 
772  mMainAnnotationLayer->setTransformContext( context );
773  for ( auto &layer : mLayerStore.get()->mapLayers() )
774  {
775  layer->setTransformContext( context );
776  }
778 }
779 
781 {
782  QgsSettings settings;
783 
784  mProjectScope.reset();
785  mFile.setFileName( QString() );
786  mProperties.clearKeys();
787  mSaveUser.clear();
788  mSaveUserFull.clear();
789  mSaveDateTime = QDateTime();
790  mSaveVersion = QgsProjectVersion();
791  mHomePath.clear();
792  mCachedHomePath.clear();
793  mAutoTransaction = false;
794  mEvaluateDefaultValues = false;
795  mDirty = false;
796  mTrustLayerMetadata = false;
797  mCustomVariables.clear();
798  mMetadata = QgsProjectMetadata();
799  if ( !settings.value( QStringLiteral( "projects/anonymize_new_projects" ), false, QgsSettings::Core ).toBool() )
800  {
801  mMetadata.setCreationDateTime( QDateTime::currentDateTime() );
803  }
804  emit metadataChanged();
805 
807  context.readSettings();
808  setTransformContext( context );
809 
810  mEmbeddedLayers.clear();
811  mRelationManager->clear();
812  mAnnotationManager->clear();
813  mLayoutManager->clear();
814  mBookmarkManager->clear();
815  mViewSettings->reset();
816  mTimeSettings->reset();
817  mDisplaySettings->reset();
818  mSnappingConfig.reset();
819  emit snappingConfigChanged( mSnappingConfig );
822 
823  mMapThemeCollection.reset( new QgsMapThemeCollection( this ) );
825 
826  mLabelingEngineSettings->clear();
827 
828  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage() );
829  mArchive->clear();
830 
832 
833  if ( !mIsBeingDeleted )
834  {
835  // possibly other signals should also not be thrown on destruction -- e.g. labelEngineSettingsChanged, etc.
836  emit projectColorsChanged();
837  }
838 
839  // reset some default project properties
840  // XXX THESE SHOULD BE MOVED TO STATUSBAR RELATED SOURCE
841  writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ), true );
842  writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ), 2 );
843  writeEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), false );
844 
845  //copy default units to project
846  writeEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/DistanceUnits" ), settings.value( QStringLiteral( "/qgis/measure/displayunits" ) ).toString() );
847  writeEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/AreaUnits" ), settings.value( QStringLiteral( "/qgis/measure/areaunits" ) ).toString() );
848 
849  int red = settings.value( QStringLiteral( "qgis/default_canvas_color_red" ), 255 ).toInt();
850  int green = settings.value( QStringLiteral( "qgis/default_canvas_color_green" ), 255 ).toInt();
851  int blue = settings.value( QStringLiteral( "qgis/default_canvas_color_blue" ), 255 ).toInt();
852  setBackgroundColor( QColor( red, green, blue ) );
853 
854  red = settings.value( QStringLiteral( "qgis/default_selection_color_red" ), 255 ).toInt();
855  green = settings.value( QStringLiteral( "qgis/default_selection_color_green" ), 255 ).toInt();
856  blue = settings.value( QStringLiteral( "qgis/default_selection_color_blue" ), 0 ).toInt();
857  int alpha = settings.value( QStringLiteral( "qgis/default_selection_color_alpha" ), 255 ).toInt();
858  setSelectionColor( QColor( red, green, blue, alpha ) );
859 
861  mRootGroup->clear();
862  if ( mMainAnnotationLayer )
863  mMainAnnotationLayer->reset();
864 
865  setDirty( false );
866  emit homePathChanged();
867  emit cleared();
868 }
869 
870 // basically a debugging tool to dump property list values
871 void dump_( const QgsProjectPropertyKey &topQgsPropertyKey )
872 {
873  QgsDebugMsgLevel( QStringLiteral( "current properties:" ), 3 );
874  topQgsPropertyKey.dump();
875 }
876 
877 
908 void _getProperties( const QDomDocument &doc, QgsProjectPropertyKey &project_properties )
909 {
910  QDomElement propertiesElem = doc.documentElement().firstChildElement( QStringLiteral( "properties" ) );
911 
912  if ( propertiesElem.isNull() ) // no properties found, so we're done
913  {
914  return;
915  }
916 
917  QDomNodeList scopes = propertiesElem.childNodes();
918 
919  if ( scopes.count() < 1 )
920  {
921  QgsDebugMsg( QStringLiteral( "empty ``properties'' XML tag ... bailing" ) );
922  return;
923  }
924 
925  if ( ! project_properties.readXml( propertiesElem ) )
926  {
927  QgsDebugMsg( QStringLiteral( "Project_properties.readXml() failed" ) );
928  }
929 }
930 
937 QgsPropertyCollection getDataDefinedServerProperties( const QDomDocument &doc, const QgsPropertiesDefinition &dataDefinedServerPropertyDefinitions )
938 {
939  QgsPropertyCollection ddServerProperties;
940  // Read data defined server properties
941  QDomElement ddElem = doc.documentElement().firstChildElement( QStringLiteral( "dataDefinedServerProperties" ) );
942  if ( !ddElem.isNull() )
943  {
944  if ( !ddServerProperties.readXml( ddElem, dataDefinedServerPropertyDefinitions ) )
945  {
946  QgsDebugMsg( QStringLiteral( "dataDefinedServerProperties.readXml() failed" ) );
947  }
948  }
949  return ddServerProperties;
950 }
951 
956 static void _getTitle( const QDomDocument &doc, QString &title )
957 {
958  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "title" ) );
959 
960  title.clear(); // by default the title will be empty
961 
962  if ( !nl.count() )
963  {
964  QgsDebugMsgLevel( QStringLiteral( "unable to find title element" ), 2 );
965  return;
966  }
967 
968  QDomNode titleNode = nl.item( 0 ); // there should only be one, so zeroth element OK
969 
970  if ( !titleNode.hasChildNodes() ) // if not, then there's no actual text
971  {
972  QgsDebugMsgLevel( QStringLiteral( "unable to find title element" ), 2 );
973  return;
974  }
975 
976  QDomNode titleTextNode = titleNode.firstChild(); // should only have one child
977 
978  if ( !titleTextNode.isText() )
979  {
980  QgsDebugMsgLevel( QStringLiteral( "unable to find title element" ), 2 );
981  return;
982  }
983 
984  QDomText titleText = titleTextNode.toText();
985 
986  title = titleText.data();
987 
988 }
989 
990 static void readProjectFileMetadata( const QDomDocument &doc, QString &lastUser, QString &lastUserFull, QDateTime &lastSaveDateTime )
991 {
992  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
993 
994  if ( !nl.count() )
995  {
996  QgsDebugMsg( "unable to find qgis element" );
997  return;
998  }
999 
1000  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element OK
1001 
1002  QDomElement qgisElement = qgisNode.toElement(); // qgis node should be element
1003  lastUser = qgisElement.attribute( QStringLiteral( "saveUser" ), QString() );
1004  lastUserFull = qgisElement.attribute( QStringLiteral( "saveUserFull" ), QString() );
1005  lastSaveDateTime = QDateTime::fromString( qgisElement.attribute( QStringLiteral( "saveDateTime" ), QString() ), Qt::ISODate );
1006 }
1007 
1008 
1009 QgsProjectVersion getVersion( const QDomDocument &doc )
1010 {
1011  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
1012 
1013  if ( !nl.count() )
1014  {
1015  QgsDebugMsg( QStringLiteral( " unable to find qgis element in project file" ) );
1016  return QgsProjectVersion( 0, 0, 0, QString() );
1017  }
1018 
1019  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element OK
1020 
1021  QDomElement qgisElement = qgisNode.toElement(); // qgis node should be element
1022  QgsProjectVersion projectVersion( qgisElement.attribute( QStringLiteral( "version" ) ) );
1023  return projectVersion;
1024 }
1025 
1026 
1028 {
1029  return mSnappingConfig;
1030 }
1031 
1033 {
1034  if ( mSnappingConfig == snappingConfig )
1035  return;
1036 
1037  mSnappingConfig = snappingConfig;
1038  setDirty( true );
1039  emit snappingConfigChanged( mSnappingConfig );
1040 }
1041 
1043 {
1044  if ( mAvoidIntersectionsMode == mode )
1045  return;
1046 
1047  mAvoidIntersectionsMode = mode;
1049 }
1050 
1051 bool QgsProject::_getMapLayers( const QDomDocument &doc, QList<QDomNode> &brokenNodes, QgsProject::ReadFlags flags )
1052 {
1053  // Layer order is set by the restoring the legend settings from project file.
1054  // This is done on the 'readProject( ... )' signal
1055 
1056  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "maplayer" ) );
1057 
1058  // process the map layer nodes
1059 
1060  if ( 0 == nl.count() ) // if we have no layers to process, bail
1061  {
1062  return true; // Decided to return "true" since it's
1063  // possible for there to be a project with no
1064  // layers; but also, more imporantly, this
1065  // would cause the tests/qgsproject to fail
1066  // since the test suite doesn't currently
1067  // support test layers
1068  }
1069 
1070  bool returnStatus = true;
1071 
1072  // order layers based on their dependencies
1073  QgsScopedRuntimeProfile profile( tr( "Sorting layers" ), QStringLiteral( "projectload" ) );
1074  QgsLayerDefinition::DependencySorter depSorter( doc );
1075  if ( depSorter.hasCycle() )
1076  return false;
1077 
1078  // Missing a dependency? We still load all the layers, otherwise the project is completely broken!
1079  if ( depSorter.hasMissingDependency() )
1080  returnStatus = false;
1081 
1082  emit layerLoaded( 0, nl.count() );
1083 
1084  const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
1085  const int totalLayerCount = sortedLayerNodes.count();
1086 
1087  int i = 0;
1088  for ( const QDomNode &node : sortedLayerNodes )
1089  {
1090  const QDomElement element = node.toElement();
1091 
1092  const QString name = translate( QStringLiteral( "project:layers:%1" ).arg( node.namedItem( QStringLiteral( "id" ) ).toElement().text() ), node.namedItem( QStringLiteral( "layername" ) ).toElement().text() );
1093  if ( !name.isNull() )
1094  emit loadingLayer( tr( "Loading layer %1" ).arg( name ) );
1095 
1096  profile.switchTask( name );
1097 
1098  if ( element.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
1099  {
1100  createEmbeddedLayer( element.attribute( QStringLiteral( "id" ) ), readPath( element.attribute( QStringLiteral( "project" ) ) ), brokenNodes, true, flags );
1101  }
1102  else
1103  {
1104  QgsReadWriteContext context;
1105  context.setPathResolver( pathResolver() );
1106  context.setProjectTranslator( this );
1108 
1109  if ( !addLayer( element, brokenNodes, context, flags ) )
1110  {
1111  returnStatus = false;
1112  }
1113  const auto messages = context.takeMessages();
1114  if ( !messages.isEmpty() )
1115  {
1116  emit loadingLayerMessageReceived( tr( "Loading layer %1" ).arg( name ), messages );
1117  }
1118  }
1119  emit layerLoaded( i + 1, totalLayerCount );
1120  i++;
1121  }
1122 
1123  return returnStatus;
1124 }
1125 
1126 bool QgsProject::addLayer( const QDomElement &layerElem, QList<QDomNode> &brokenNodes, QgsReadWriteContext &context, QgsProject::ReadFlags flags )
1127 {
1128  QString type = layerElem.attribute( QStringLiteral( "type" ) );
1129  QgsDebugMsgLevel( "Layer type is " + type, 4 );
1130  std::unique_ptr<QgsMapLayer> mapLayer;
1131 
1132  QgsScopedRuntimeProfile profile( tr( "Create layer" ), QStringLiteral( "projectload" ) );
1133  if ( type == QLatin1String( "vector" ) )
1134  {
1135  mapLayer = qgis::make_unique<QgsVectorLayer>();
1136  // apply specific settings to vector layer
1137  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mapLayer.get() ) )
1138  {
1139  vl->setReadExtentFromXml( mTrustLayerMetadata || ( flags & QgsProject::ReadFlag::FlagTrustLayerMetadata ) );
1140  }
1141  }
1142  else if ( type == QLatin1String( "raster" ) )
1143  {
1144  mapLayer = qgis::make_unique<QgsRasterLayer>();
1145  }
1146  else if ( type == QLatin1String( "mesh" ) )
1147  {
1148  mapLayer = qgis::make_unique<QgsMeshLayer>();
1149  }
1150  else if ( type == QLatin1String( "vector-tile" ) )
1151  {
1152  mapLayer = qgis::make_unique<QgsVectorTileLayer>();
1153  }
1154  else if ( type == QLatin1String( "plugin" ) )
1155  {
1156  QString typeName = layerElem.attribute( QStringLiteral( "name" ) );
1157  mapLayer.reset( QgsApplication::pluginLayerRegistry()->createLayer( typeName ) );
1158  }
1159  else if ( type == QLatin1String( "annotation" ) )
1160  {
1161  QgsAnnotationLayer::LayerOptions options( mTransformContext );
1162  mapLayer = qgis::make_unique<QgsAnnotationLayer>( QString(), options );
1163  }
1164  if ( !mapLayer )
1165  {
1166  QgsDebugMsg( QStringLiteral( "Unable to create layer" ) );
1167  return false;
1168  }
1169 
1170  Q_CHECK_PTR( mapLayer ); // NOLINT
1171 
1172  // This is tricky: to avoid a leak we need to check if the layer was already in the store
1173  // because if it was, the newly created layer will not be added to the store and it would leak.
1174  const QString layerId { layerElem.namedItem( QStringLiteral( "id" ) ).toElement().text() };
1175  Q_ASSERT( ! layerId.isEmpty() );
1176  const bool layerWasStored { layerStore()->mapLayer( layerId ) != nullptr };
1177 
1178  // have the layer restore state that is stored in Dom node
1179  QgsMapLayer::ReadFlags layerFlags = QgsMapLayer::ReadFlags();
1181  layerFlags |= QgsMapLayer::FlagDontResolveLayers;
1182  // Propagate trust layer metadata flag
1183  if ( mTrustLayerMetadata || ( flags & QgsProject::ReadFlag::FlagTrustLayerMetadata ) )
1185 
1186  profile.switchTask( tr( "Load layer source" ) );
1187  bool layerIsValid = mapLayer->readLayerXml( layerElem, context, layerFlags ) && mapLayer->isValid();
1188 
1189  profile.switchTask( tr( "Add layer to project" ) );
1190  QList<QgsMapLayer *> newLayers;
1191  newLayers << mapLayer.get();
1192  if ( layerIsValid || flags & QgsProject::ReadFlag::FlagDontResolveLayers )
1193  {
1194  emit readMapLayer( mapLayer.get(), layerElem );
1195  addMapLayers( newLayers );
1196  }
1197  else
1198  {
1199  // It's a bad layer: do not add to legend (the user will decide if she wants to do so)
1200  addMapLayers( newLayers, false );
1201  newLayers.first();
1202  QgsDebugMsg( "Unable to load " + type + " layer" );
1203  brokenNodes.push_back( layerElem );
1204  }
1205 
1206  // It should be safe to delete the layer now if layer was stored, because all the store
1207  // had to to was to reset the data source in case the validity changed.
1208  if ( ! layerWasStored )
1209  {
1210  mapLayer.release();
1211  }
1212 
1213  return layerIsValid;
1214 }
1215 
1216 bool QgsProject::read( const QString &filename, QgsProject::ReadFlags flags )
1217 {
1218  mFile.setFileName( filename );
1219  mCachedHomePath.clear();
1220  mProjectScope.reset();
1221 
1222  return read( flags );
1223 }
1224 
1225 bool QgsProject::read( QgsProject::ReadFlags flags )
1226 {
1227  QString filename = mFile.fileName();
1228  bool returnValue;
1229 
1230  if ( QgsProjectStorage *storage = projectStorage() )
1231  {
1232  QTemporaryFile inDevice;
1233  if ( !inDevice.open() )
1234  {
1235  setError( tr( "Unable to open %1" ).arg( inDevice.fileName() ) );
1236  return false;
1237  }
1238 
1239  QgsReadWriteContext context;
1240  context.setProjectTranslator( this );
1241  if ( !storage->readProject( filename, &inDevice, context ) )
1242  {
1243  QString err = tr( "Unable to open %1" ).arg( filename );
1244  QList<QgsReadWriteContext::ReadWriteMessage> messages = context.takeMessages();
1245  if ( !messages.isEmpty() )
1246  err += QStringLiteral( "\n\n" ) + messages.last().message();
1247  setError( err );
1248  return false;
1249  }
1250  returnValue = unzip( inDevice.fileName(), flags ); // calls setError() if returning false
1251  }
1252  else
1253  {
1254  if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
1255  {
1256  returnValue = unzip( mFile.fileName(), flags );
1257  }
1258  else
1259  {
1260  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( *this ) );
1261  returnValue = readProjectFile( mFile.fileName(), flags );
1262  }
1263 
1264  //on translation we should not change the filename back
1265  if ( !mTranslator )
1266  {
1267  mFile.setFileName( filename );
1268  mCachedHomePath.clear();
1269  mProjectScope.reset();
1270  }
1271  else
1272  {
1273  //but delete the translator
1274  mTranslator.reset( nullptr );
1275  }
1276  }
1277  emit homePathChanged();
1278  return returnValue;
1279 }
1280 
1281 bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags flags )
1282 {
1283  QFile projectFile( filename );
1284  clearError();
1285 
1286  QgsApplication::profiler()->clear( QStringLiteral( "projectload" ) );
1287  QgsScopedRuntimeProfile profile( tr( "Setting up translations" ), QStringLiteral( "projectload" ) );
1288 
1289  QgsSettings settings;
1290 
1291  QString localeFileName = QStringLiteral( "%1_%2" ).arg( QFileInfo( projectFile.fileName() ).baseName(), settings.value( QStringLiteral( "locale/userLocale" ), QString() ).toString() );
1292 
1293  if ( QFile( QStringLiteral( "%1/%2.qm" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) ).exists() )
1294  {
1295  mTranslator.reset( new QTranslator() );
1296  mTranslator->load( localeFileName, QFileInfo( projectFile.fileName() ).absolutePath() );
1297  }
1298 
1299  profile.switchTask( tr( "Reading project file" ) );
1300  std::unique_ptr<QDomDocument> doc( new QDomDocument( QStringLiteral( "qgis" ) ) );
1301 
1302  if ( !projectFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
1303  {
1304  projectFile.close();
1305 
1306  setError( tr( "Unable to open %1" ).arg( projectFile.fileName() ) );
1307 
1308  return false;
1309  }
1310 
1311  // location of problem associated with errorMsg
1312  int line, column;
1313  QString errorMsg;
1314 
1315  if ( !doc->setContent( &projectFile, &errorMsg, &line, &column ) )
1316  {
1317  // want to make this class as GUI independent as possible; so commented out
1318 #if 0
1319  QMessageBox::critical( 0, tr( "Read Project File" ),
1320  tr( "%1 at line %2 column %3" ).arg( errorMsg ).arg( line ).arg( column ) );
1321 #endif
1322 
1323  QString errorString = tr( "Project file read error in file %1: %2 at line %3 column %4" )
1324  .arg( projectFile.fileName(), errorMsg ).arg( line ).arg( column );
1325 
1326  QgsDebugMsg( errorString );
1327 
1328  projectFile.close();
1329 
1330  setError( tr( "%1 for file %2" ).arg( errorString, projectFile.fileName() ) );
1331 
1332  return false;
1333  }
1334 
1335  projectFile.close();
1336 
1337  QgsDebugMsgLevel( "Opened document " + projectFile.fileName(), 2 );
1338 
1339  // get project version string, if any
1340  QgsProjectVersion fileVersion = getVersion( *doc );
1341  const QgsProjectVersion thisVersion( Qgis::version() );
1342 
1343  profile.switchTask( tr( "Updating project file" ) );
1344  if ( thisVersion > fileVersion )
1345  {
1346  QgsLogger::warning( "Loading a file that was saved with an older "
1347  "version of qgis (saved in " + fileVersion.text() +
1348  ", loaded in " + Qgis::version() +
1349  "). Problems may occur." );
1350 
1351  QgsProjectFileTransform projectFile( *doc, fileVersion );
1352 
1353  // Shows a warning when an old project file is read.
1354  emit oldProjectVersionWarning( fileVersion.text() );
1355 
1356  projectFile.updateRevision( thisVersion );
1357  }
1358 
1359  // start new project, just keep the file name and auxiliary storage
1360  profile.switchTask( tr( "Creating auxiliary storage" ) );
1361  QString fileName = mFile.fileName();
1362  std::unique_ptr<QgsAuxiliaryStorage> aStorage = std::move( mAuxiliaryStorage );
1363  clear();
1364  mAuxiliaryStorage = std::move( aStorage );
1365  mFile.setFileName( fileName );
1366  mCachedHomePath.clear();
1367  mProjectScope.reset();
1368  mSaveVersion = fileVersion;
1369 
1370  // now get any properties
1371  profile.switchTask( tr( "Reading properties" ) );
1372  _getProperties( *doc, mProperties );
1373 
1374  // now get the data defined server properties
1375  mDataDefinedServerProperties = getDataDefinedServerProperties( *doc, dataDefinedServerPropertyDefinitions() );
1376 
1377  QgsDebugMsgLevel( QString::number( mProperties.count() ) + " properties read", 2 );
1378 
1379 #if 0
1380  dump_( mProperties );
1381 #endif
1382 
1383  // get older style project title
1384  QString oldTitle;
1385  _getTitle( *doc, oldTitle );
1386 
1387  readProjectFileMetadata( *doc, mSaveUser, mSaveUserFull, mSaveDateTime );
1388 
1389  QDomNodeList homePathNl = doc->elementsByTagName( QStringLiteral( "homePath" ) );
1390  if ( homePathNl.count() > 0 )
1391  {
1392  QDomElement homePathElement = homePathNl.at( 0 ).toElement();
1393  QString homePath = homePathElement.attribute( QStringLiteral( "path" ) );
1394  if ( !homePath.isEmpty() )
1396  }
1397  else
1398  {
1399  emit homePathChanged();
1400  }
1401 
1402  const QColor backgroundColor( readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), 255 ),
1403  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), 255 ),
1404  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), 255 ) );
1406  const QColor selectionColor( readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorRedPart" ), 255 ),
1407  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorGreenPart" ), 255 ),
1408  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorBluePart" ), 255 ),
1409  readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorAlphaPart" ), 255 ) );
1411 
1412  QgsReadWriteContext context;
1413  context.setPathResolver( pathResolver() );
1414  context.setProjectTranslator( this );
1415 
1416  //crs
1417  QgsCoordinateReferenceSystem projectCrs;
1418  if ( readNumEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectionsEnabled" ), 0 ) )
1419  {
1420  // first preference - dedicated projectCrs node
1421  QDomNode srsNode = doc->documentElement().namedItem( QStringLiteral( "projectCrs" ) );
1422  if ( !srsNode.isNull() )
1423  {
1424  projectCrs.readXml( srsNode );
1425  }
1426 
1427  if ( !projectCrs.isValid() )
1428  {
1429  QString projCrsString = readEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectCRSProj4String" ) );
1430  long currentCRS = readNumEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectCRSID" ), -1 );
1431  const QString authid = readEntry( QStringLiteral( "SpatialRefSys" ), QStringLiteral( "/ProjectCrs" ) );
1432 
1433  // authid should be prioritized over all
1434  bool isUserAuthId = authid.startsWith( QLatin1String( "USER:" ), Qt::CaseInsensitive );
1435  if ( !authid.isEmpty() && !isUserAuthId )
1436  projectCrs = QgsCoordinateReferenceSystem( authid );
1437 
1438  // try the CRS
1439  if ( !projectCrs.isValid() && currentCRS >= 0 )
1440  {
1441  projectCrs = QgsCoordinateReferenceSystem::fromSrsId( currentCRS );
1442  }
1443 
1444  // if that didn't produce a match, try the proj.4 string
1445  if ( !projCrsString.isEmpty() && ( authid.isEmpty() || isUserAuthId ) && ( !projectCrs.isValid() || projectCrs.toProj() != projCrsString ) )
1446  {
1447  projectCrs = QgsCoordinateReferenceSystem::fromProj( projCrsString );
1448  }
1449 
1450  // last just take the given id
1451  if ( !projectCrs.isValid() )
1452  {
1453  projectCrs = QgsCoordinateReferenceSystem::fromSrsId( currentCRS );
1454  }
1455  }
1456  }
1457  mCrs = projectCrs;
1458 
1459  QStringList datumErrors;
1460  if ( !mTransformContext.readXml( doc->documentElement(), context, datumErrors ) && !datumErrors.empty() )
1461  {
1462  emit missingDatumTransforms( datumErrors );
1463  }
1464  emit transformContextChanged();
1465 
1466  //add variables defined in project file - do this early in the reading cycle, as other components
1467  //(e.g. layouts) may depend on these variables
1468  QStringList variableNames = readListEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableNames" ) );
1469  QStringList variableValues = readListEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableValues" ) );
1470 
1471  mCustomVariables.clear();
1472  if ( variableNames.length() == variableValues.length() )
1473  {
1474  for ( int i = 0; i < variableNames.length(); ++i )
1475  {
1476  mCustomVariables.insert( variableNames.at( i ), variableValues.at( i ) );
1477  }
1478  }
1479  else
1480  {
1481  QgsMessageLog::logMessage( tr( "Project Variables Invalid" ), tr( "The project contains invalid variable settings." ) );
1482  }
1483 
1484  QDomNodeList nl = doc->elementsByTagName( QStringLiteral( "projectMetadata" ) );
1485  if ( !nl.isEmpty() )
1486  {
1487  QDomElement metadataElement = nl.at( 0 ).toElement();
1488  mMetadata.readMetadataXml( metadataElement );
1489  }
1490  else
1491  {
1492  // older project, no metadata => remove auto generated metadata which is populated on QgsProject::clear()
1493  mMetadata = QgsProjectMetadata();
1494  }
1495  if ( mMetadata.title().isEmpty() && !oldTitle.isEmpty() )
1496  {
1497  // upgrade older title storage to storing within project metadata.
1498  mMetadata.setTitle( oldTitle );
1499  }
1500  emit metadataChanged();
1501 
1502  nl = doc->elementsByTagName( QStringLiteral( "autotransaction" ) );
1503  if ( nl.count() )
1504  {
1505  QDomElement transactionElement = nl.at( 0 ).toElement();
1506  if ( transactionElement.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 )
1507  mAutoTransaction = true;
1508  }
1509 
1510  nl = doc->elementsByTagName( QStringLiteral( "evaluateDefaultValues" ) );
1511  if ( nl.count() )
1512  {
1513  QDomElement evaluateDefaultValuesElement = nl.at( 0 ).toElement();
1514  if ( evaluateDefaultValuesElement.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 )
1515  mEvaluateDefaultValues = true;
1516  }
1517 
1518  // Read trust layer metadata config in the project
1519  nl = doc->elementsByTagName( QStringLiteral( "trust" ) );
1520  if ( nl.count() )
1521  {
1522  QDomElement trustElement = nl.at( 0 ).toElement();
1523  if ( trustElement.attribute( QStringLiteral( "active" ), QStringLiteral( "0" ) ).toInt() == 1 )
1524  mTrustLayerMetadata = true;
1525  }
1526 
1527  // read the layer tree from project file
1528  profile.switchTask( tr( "Loading layer tree" ) );
1529  mRootGroup->setCustomProperty( QStringLiteral( "loading" ), 1 );
1530 
1531  QDomElement layerTreeElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
1532  if ( !layerTreeElem.isNull() )
1533  {
1534  mRootGroup->readChildrenFromXml( layerTreeElem, context );
1535  }
1536  else
1537  {
1538  QgsLayerTreeUtils::readOldLegend( mRootGroup, doc->documentElement().firstChildElement( QStringLiteral( "legend" ) ) );
1539  }
1540 
1541  mLayerTreeRegistryBridge->setEnabled( false );
1542 
1543  // get the map layers
1544  profile.switchTask( tr( "Reading map layers" ) );
1545 
1546  QList<QDomNode> brokenNodes;
1547  bool clean = _getMapLayers( *doc, brokenNodes, flags );
1548 
1549  // review the integrity of the retrieved map layers
1550  if ( !clean )
1551  {
1552  QgsDebugMsg( QStringLiteral( "Unable to get map layers from project file." ) );
1553 
1554  if ( !brokenNodes.isEmpty() )
1555  {
1556  QgsDebugMsg( "there are " + QString::number( brokenNodes.size() ) + " broken layers" );
1557  }
1558 
1559  // we let a custom handler decide what to do with missing layers
1560  // (default implementation ignores them, there's also a GUI handler that lets user choose correct path)
1561  mBadLayerHandler->handleBadLayers( brokenNodes );
1562  }
1563 
1564  mMainAnnotationLayer->readLayerXml( doc->documentElement().firstChildElement( QStringLiteral( "main-annotation-layer" ) ), context );
1565  mMainAnnotationLayer->setTransformContext( mTransformContext );
1566 
1567  // Resolve references to other layers
1568  // Needs to be done here once all dependent layers are loaded
1569  profile.switchTask( tr( "Resolving layer references" ) );
1570  QMap<QString, QgsMapLayer *> layers = mLayerStore->mapLayers();
1571  for ( QMap<QString, QgsMapLayer *>::iterator it = layers.begin(); it != layers.end(); ++it )
1572  {
1573  it.value()->resolveReferences( this );
1574  }
1575 
1576  mLayerTreeRegistryBridge->setEnabled( true );
1577 
1578  // load embedded groups and layers
1579  profile.switchTask( tr( "Loading embedded layers" ) );
1580  loadEmbeddedNodes( mRootGroup, flags );
1581 
1582  // now that layers are loaded, we can resolve layer tree's references to the layers
1583  profile.switchTask( tr( "Resolving references" ) );
1584  mRootGroup->resolveReferences( this );
1585 
1586  if ( !layerTreeElem.isNull() )
1587  {
1588  mRootGroup->readLayerOrderFromXml( layerTreeElem );
1589  }
1590 
1591  // Load pre 3.0 configuration
1592  QDomElement layerTreeCanvasElem = doc->documentElement().firstChildElement( QStringLiteral( "layer-tree-canvas" ) );
1593  if ( !layerTreeCanvasElem.isNull( ) )
1594  {
1595  mRootGroup->readLayerOrderFromXml( layerTreeCanvasElem );
1596  }
1597 
1598  // Convert pre 3.4 to create layers flags
1599  if ( QgsProjectVersion( 3, 4, 0 ) > mSaveVersion )
1600  {
1601  const QStringList requiredLayerIds = readListEntry( QStringLiteral( "RequiredLayers" ), QStringLiteral( "Layers" ) );
1602  for ( const QString &layerId : requiredLayerIds )
1603  {
1604  if ( QgsMapLayer *layer = mapLayer( layerId ) )
1605  {
1606  layer->setFlags( layer->flags() & ~QgsMapLayer::Removable );
1607  }
1608  }
1609  const QStringList disabledLayerIds = readListEntry( QStringLiteral( "Identify" ), QStringLiteral( "/disabledLayers" ) );
1610  for ( const QString &layerId : disabledLayerIds )
1611  {
1612  if ( QgsMapLayer *layer = mapLayer( layerId ) )
1613  {
1614  layer->setFlags( layer->flags() & ~QgsMapLayer::Identifiable );
1615  }
1616  }
1617  }
1618 
1619  // After bad layer handling we might still have invalid layers,
1620  // store them in case the user wanted to handle them later
1621  // or wanted to pass them through when saving
1622  QgsLayerTreeUtils::storeOriginalLayersProperties( mRootGroup, doc.get() );
1623 
1624  mRootGroup->removeCustomProperty( QStringLiteral( "loading" ) );
1625 
1626  profile.switchTask( tr( "Loading map themes" ) );
1627  mMapThemeCollection.reset( new QgsMapThemeCollection( this ) );
1629  mMapThemeCollection->readXml( *doc );
1630 
1631  profile.switchTask( tr( "Loading label settings" ) );
1632  mLabelingEngineSettings->readSettingsFromProject( this );
1634 
1635  profile.switchTask( tr( "Loading annotations" ) );
1636  mAnnotationManager->readXml( doc->documentElement(), context );
1637  if ( !( flags & QgsProject::ReadFlag::FlagDontLoadLayouts ) )
1638  {
1639  profile.switchTask( tr( "Loading layouts" ) );
1640  mLayoutManager->readXml( doc->documentElement(), *doc );
1641  }
1642  profile.switchTask( tr( "Loading bookmarks" ) );
1643  mBookmarkManager->readXml( doc->documentElement(), *doc );
1644 
1645  // reassign change dependencies now that all layers are loaded
1646  QMap<QString, QgsMapLayer *> existingMaps = mapLayers();
1647  for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
1648  {
1649  it.value()->setDependencies( it.value()->dependencies() );
1650  }
1651 
1652  profile.switchTask( tr( "Loading snapping settings" ) );
1653  mSnappingConfig.readProject( *doc );
1654  mAvoidIntersectionsMode = static_cast<AvoidIntersectionsMode>( readNumEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsMode" ), static_cast<int>( AvoidIntersectionsMode::AvoidIntersectionsLayers ) ) );
1655 
1656  profile.switchTask( tr( "Loading view settings" ) );
1657  // restore older project scales settings
1658  mViewSettings->setUseProjectScales( readBoolEntry( QStringLiteral( "Scales" ), QStringLiteral( "/useProjectScales" ) ) );
1659  const QStringList scales = readListEntry( QStringLiteral( "Scales" ), QStringLiteral( "/ScalesList" ) );
1660  QVector<double> res;
1661  for ( const QString &scale : scales )
1662  {
1663  const QStringList parts = scale.split( ':' );
1664  if ( parts.size() != 2 )
1665  continue;
1666 
1667  bool ok = false;
1668  const double denominator = QLocale().toDouble( parts[1], &ok );
1669  if ( ok )
1670  {
1671  res << denominator;
1672  }
1673  }
1674  mViewSettings->setMapScales( res );
1675  QDomElement viewSettingsElement = doc->documentElement().firstChildElement( QStringLiteral( "ProjectViewSettings" ) );
1676  if ( !viewSettingsElement.isNull() )
1677  mViewSettings->readXml( viewSettingsElement, context );
1678 
1679  // restore time settings
1680  profile.switchTask( tr( "Loading temporal settings" ) );
1681  QDomElement timeSettingsElement = doc->documentElement().firstChildElement( QStringLiteral( "ProjectTimeSettings" ) );
1682  if ( !timeSettingsElement.isNull() )
1683  mTimeSettings->readXml( timeSettingsElement, context );
1684 
1685  profile.switchTask( tr( "Loading display settings" ) );
1686  QDomElement displaySettingsElement = doc->documentElement().firstChildElement( QStringLiteral( "ProjectDisplaySettings" ) );
1687  if ( !displaySettingsElement.isNull() )
1688  mDisplaySettings->readXml( displaySettingsElement, context );
1689 
1690  profile.switchTask( tr( "Updating variables" ) );
1691  emit customVariablesChanged();
1692  profile.switchTask( tr( "Updating CRS" ) );
1693  emit crsChanged();
1694  emit ellipsoidChanged( ellipsoid() );
1695 
1696  // read the project: used by map canvas and legend
1697  profile.switchTask( tr( "Reading external settings" ) );
1698  emit readProject( *doc );
1699  emit readProjectWithContext( *doc, context );
1700 
1701  profile.switchTask( tr( "Updating interface" ) );
1702  emit snappingConfigChanged( mSnappingConfig );
1705  emit projectColorsChanged();
1706 
1707  // if all went well, we're allegedly in pristine state
1708  if ( clean )
1709  setDirty( false );
1710 
1711  QgsDebugMsgLevel( QString( "Project save user: %1" ).arg( mSaveUser ), 2 );
1712  QgsDebugMsgLevel( QString( "Project save user: %1" ).arg( mSaveUserFull ), 2 );
1713 
1717 
1718  if ( mTranslator )
1719  {
1720  //project possibly translated -> rename it with locale postfix
1721  QString newFileName( QStringLiteral( "%1/%2.qgs" ).arg( QFileInfo( projectFile.fileName() ).absolutePath(), localeFileName ) );
1722  setFileName( newFileName );
1723 
1724  if ( write() )
1725  {
1726  setTitle( localeFileName );
1727  QgsMessageLog::logMessage( tr( "Translated project saved with locale prefix %1" ).arg( newFileName ), QObject::tr( "Project translation" ), Qgis::Success );
1728  }
1729  else
1730  {
1731  QgsMessageLog::logMessage( tr( "Error saving translated project with locale prefix %1" ).arg( newFileName ), QObject::tr( "Project translation" ), Qgis::Critical );
1732  }
1733  }
1734  return true;
1735 }
1736 
1737 
1738 bool QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup *group, QgsProject::ReadFlags flags )
1739 {
1740  bool valid = true;
1741  const auto constChildren = group->children();
1742  for ( QgsLayerTreeNode *child : constChildren )
1743  {
1744  if ( QgsLayerTree::isGroup( child ) )
1745  {
1746  QgsLayerTreeGroup *childGroup = QgsLayerTree::toGroup( child );
1747  if ( childGroup->customProperty( QStringLiteral( "embedded" ) ).toInt() )
1748  {
1749  // make sure to convert the path from relative to absolute
1750  QString projectPath = readPath( childGroup->customProperty( QStringLiteral( "embedded_project" ) ).toString() );
1751  childGroup->setCustomProperty( QStringLiteral( "embedded_project" ), projectPath );
1752  QgsLayerTreeGroup *newGroup = createEmbeddedGroup( childGroup->name(), projectPath, childGroup->customProperty( QStringLiteral( "embedded-invisible-layers" ) ).toStringList(), flags );
1753  if ( newGroup )
1754  {
1755  QList<QgsLayerTreeNode *> clonedChildren;
1756  const auto constChildren = newGroup->children();
1757  for ( QgsLayerTreeNode *newGroupChild : constChildren )
1758  clonedChildren << newGroupChild->clone();
1759  delete newGroup;
1760 
1761  childGroup->insertChildNodes( 0, clonedChildren );
1762  }
1763  }
1764  else
1765  {
1766  loadEmbeddedNodes( childGroup, flags );
1767  }
1768  }
1769  else if ( QgsLayerTree::isLayer( child ) )
1770  {
1771  if ( child->customProperty( QStringLiteral( "embedded" ) ).toInt() )
1772  {
1773  QList<QDomNode> brokenNodes;
1774  if ( ! createEmbeddedLayer( QgsLayerTree::toLayer( child )->layerId(), readPath( child->customProperty( QStringLiteral( "embedded_project" ) ).toString() ), brokenNodes, true, flags ) )
1775  {
1776  valid = valid && false;
1777  }
1778  }
1779  }
1780 
1781  }
1782 
1783  return valid;
1784 }
1785 
1786 QVariantMap QgsProject::customVariables() const
1787 {
1788  return mCustomVariables;
1789 }
1790 
1791 void QgsProject::setCustomVariables( const QVariantMap &variables )
1792 {
1793  if ( variables == mCustomVariables )
1794  return;
1795 
1796  //write variable to project
1797  QStringList variableNames;
1798  QStringList variableValues;
1799 
1800  QVariantMap::const_iterator it = variables.constBegin();
1801  for ( ; it != variables.constEnd(); ++it )
1802  {
1803  variableNames << it.key();
1804  variableValues << it.value().toString();
1805  }
1806 
1807  writeEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableNames" ), variableNames );
1808  writeEntry( QStringLiteral( "Variables" ), QStringLiteral( "/variableValues" ), variableValues );
1809 
1810  mCustomVariables = variables;
1811  mProjectScope.reset();
1812 
1813  emit customVariablesChanged();
1814 }
1815 
1817 {
1818  *mLabelingEngineSettings = settings;
1820 }
1821 
1823 {
1824  return *mLabelingEngineSettings;
1825 }
1826 
1828 {
1829  mProjectScope.reset();
1830  return mLayerStore.get();
1831 }
1832 
1834 {
1835  return mLayerStore.get();
1836 }
1837 
1838 QList<QgsVectorLayer *> QgsProject::avoidIntersectionsLayers() const
1839 {
1840  QList<QgsVectorLayer *> layers;
1841  QStringList layerIds = readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() );
1842  const auto constLayerIds = layerIds;
1843  for ( const QString &layerId : constLayerIds )
1844  {
1845  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mapLayer( layerId ) ) )
1846  layers << vlayer;
1847  }
1848  return layers;
1849 }
1850 
1851 void QgsProject::setAvoidIntersectionsLayers( const QList<QgsVectorLayer *> &layers )
1852 {
1853  QStringList list;
1854  const auto constLayers = layers;
1855  for ( QgsVectorLayer *layer : constLayers )
1856  list << layer->id();
1857  writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), list );
1859 }
1860 
1862 {
1863  QgsExpressionContext context;
1864 
1867 
1868  return context;
1869 }
1870 
1872 {
1873  // MUCH cheaper to clone than build
1874  if ( mProjectScope )
1875  {
1876  std::unique_ptr< QgsExpressionContextScope > projectScope = qgis::make_unique< QgsExpressionContextScope >( *mProjectScope );
1877  // we can't cache these
1878  projectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_distance_units" ), QgsUnitTypes::toString( distanceUnits() ), true, true ) );
1879  projectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_area_units" ), QgsUnitTypes::toString( areaUnits() ), true, true ) );
1880  return projectScope.release();
1881  }
1882 
1883  mProjectScope = qgis::make_unique< QgsExpressionContextScope >( QObject::tr( "Project" ) );
1884 
1885  const QVariantMap vars = customVariables();
1886 
1887  QVariantMap::const_iterator it = vars.constBegin();
1888 
1889  for ( ; it != vars.constEnd(); ++it )
1890  {
1891  mProjectScope->setVariable( it.key(), it.value(), true );
1892  }
1893 
1894  QString projectPath = projectStorage() ? fileName() : absoluteFilePath();
1895  if ( projectPath.isEmpty() )
1896  projectPath = mOriginalPath;
1897  QString projectFolder = QFileInfo( projectPath ).path();
1898  QString projectFilename = QFileInfo( projectPath ).fileName();
1899  QString projectBasename = baseName();
1900 
1901  //add other known project variables
1902  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_title" ), title(), true, true ) );
1903  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_path" ), QDir::toNativeSeparators( projectPath ), true, true ) );
1904  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_folder" ), QDir::toNativeSeparators( projectFolder ), true, true ) );
1905  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_filename" ), projectFilename, true, true ) );
1906  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_basename" ), projectBasename, true, true ) );
1907  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_home" ), QDir::toNativeSeparators( homePath() ), true, true ) );
1908  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_last_saved" ), mSaveDateTime.isNull() ? QVariant() : QVariant( mSaveDateTime ), true, true ) );
1909  QgsCoordinateReferenceSystem projectCrs = crs();
1910  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs" ), projectCrs.authid(), true, true ) );
1911  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_definition" ), projectCrs.toProj(), true, true ) );
1912  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_description" ), projectCrs.description(), true, true ) );
1913  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_ellipsoid" ), ellipsoid(), true, true ) );
1914  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "_project_transform_context" ), QVariant::fromValue<QgsCoordinateTransformContext>( transformContext() ), true, true ) );
1915  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_units" ), QgsUnitTypes::toString( projectCrs.mapUnits() ), true ) );
1916  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_acronym" ), projectCrs.projectionAcronym(), true ) );
1917  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_ellipsoid" ), projectCrs.ellipsoidAcronym(), true ) );
1918  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_proj4" ), projectCrs.toProj(), true ) );
1919  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_crs_wkt" ), projectCrs.toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ), true ) );
1920 
1921  // metadata
1922  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_author" ), metadata().author(), true, true ) );
1923  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_abstract" ), metadata().abstract(), true, true ) );
1924  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_creation_date" ), metadata().creationDateTime(), true, true ) );
1925  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_identifier" ), metadata().identifier(), true, true ) );
1926 
1927  // keywords
1928  QVariantMap keywords;
1929  QgsAbstractMetadataBase::KeywordMap metadataKeywords = metadata().keywords();
1930  for ( auto it = metadataKeywords.constBegin(); it != metadataKeywords.constEnd(); ++it )
1931  {
1932  keywords.insert( it.key(), it.value() );
1933  }
1934  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "project_keywords" ), keywords, true, true ) );
1935 
1936  // layers
1937  QVariantList layersIds;
1938  QVariantList layers;
1939  const QMap<QString, QgsMapLayer *> layersInProject = mLayerStore->mapLayers();
1940  layersIds.reserve( layersInProject.count() );
1941  layers.reserve( layersInProject.count() );
1942  for ( auto it = layersInProject.constBegin(); it != layersInProject.constEnd(); ++it )
1943  {
1944  layersIds << it.value()->id();
1945  layers << QVariant::fromValue<QgsWeakMapLayerPointer>( QgsWeakMapLayerPointer( it.value() ) );
1946  }
1947  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layer_ids" ), layersIds, true ) );
1948  mProjectScope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "layers" ), layers, true ) );
1949 
1950  mProjectScope->addFunction( QStringLiteral( "project_color" ), new GetNamedProjectColor( this ) );
1951 
1953 }
1954 
1955 void QgsProject::onMapLayersAdded( const QList<QgsMapLayer *> &layers )
1956 {
1957  QMap<QString, QgsMapLayer *> existingMaps = mapLayers();
1958 
1959  bool tgChanged = false;
1960 
1961  const auto constLayers = layers;
1962  for ( QgsMapLayer *layer : constLayers )
1963  {
1964  if ( layer->isValid() )
1965  {
1966  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
1967  if ( vlayer )
1968  {
1969  if ( autoTransaction() )
1970  {
1971  if ( QgsTransaction::supportsTransaction( vlayer ) )
1972  {
1973  const QString connString = QgsTransaction::connectionString( vlayer->source() );
1974  const QString key = vlayer->providerType();
1975 
1976  QgsTransactionGroup *tg = mTransactionGroups.value( qMakePair( key, connString ) );
1977 
1978  if ( !tg )
1979  {
1980  tg = new QgsTransactionGroup();
1981  mTransactionGroups.insert( qMakePair( key, connString ), tg );
1982  tgChanged = true;
1983  }
1984  tg->addLayer( vlayer );
1985  }
1986  }
1988  }
1989 
1990  if ( tgChanged )
1991  emit transactionGroupsChanged();
1992 
1993  connect( layer, &QgsMapLayer::configChanged, this, [ = ] { setDirty(); } );
1994 
1995  // check if we have to update connections for layers with dependencies
1996  for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); ++it )
1997  {
1998  QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
1999  if ( deps.contains( layer->id() ) )
2000  {
2001  // reconnect to change signals
2002  it.value()->setDependencies( deps );
2003  }
2004  }
2005  }
2006  }
2007 
2008  if ( mSnappingConfig.addLayers( layers ) )
2009  emit snappingConfigChanged( mSnappingConfig );
2010 }
2011 
2012 void QgsProject::onMapLayersRemoved( const QList<QgsMapLayer *> &layers )
2013 {
2014  if ( mSnappingConfig.removeLayers( layers ) )
2015  emit snappingConfigChanged( mSnappingConfig );
2016 }
2017 
2018 void QgsProject::cleanTransactionGroups( bool force )
2019 {
2020  bool changed = false;
2021  for ( QMap< QPair< QString, QString>, QgsTransactionGroup *>::Iterator tg = mTransactionGroups.begin(); tg != mTransactionGroups.end(); )
2022  {
2023  if ( tg.value()->isEmpty() || force )
2024  {
2025  delete tg.value();
2026  tg = mTransactionGroups.erase( tg );
2027  changed = true;
2028  }
2029  else
2030  {
2031  ++tg;
2032  }
2033  }
2034  if ( changed )
2035  emit transactionGroupsChanged();
2036 }
2037 
2038 bool QgsProject::readLayer( const QDomNode &layerNode )
2039 {
2040  QgsReadWriteContext context;
2041  context.setPathResolver( pathResolver() );
2042  context.setProjectTranslator( this );
2044  QList<QDomNode> brokenNodes;
2045  if ( addLayer( layerNode.toElement(), brokenNodes, context ) )
2046  {
2047  // have to try to update joins for all layers now - a previously added layer may be dependent on this newly
2048  // added layer for joins
2049  QVector<QgsVectorLayer *> vectorLayers = layers<QgsVectorLayer *>();
2050  const auto constVectorLayers = vectorLayers;
2051  for ( QgsVectorLayer *layer : constVectorLayers )
2052  {
2053  // TODO: should be only done later - and with all layers (other layers may have referenced this layer)
2054  layer->resolveReferences( this );
2055  }
2056 
2057  return true;
2058  }
2059  return false;
2060 }
2061 
2062 bool QgsProject::write( const QString &filename )
2063 {
2064  mFile.setFileName( filename );
2065  mCachedHomePath.clear();
2066  return write();
2067 }
2068 
2070 {
2071  mProjectScope.reset();
2072  if ( QgsProjectStorage *storage = projectStorage() )
2073  {
2074  QgsReadWriteContext context;
2075  // for projects stored in a custom storage, we have to check for the support
2076  // of relative paths since the storage most likely will not be in a file system
2077  QString storageFilePath { storage->filePath( mFile.fileName() ) };
2078  if ( storageFilePath.isEmpty() )
2079  {
2080  writeEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), true );
2081  }
2082  context.setPathResolver( pathResolver() );
2083 
2084  QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
2085  QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
2086 
2087  if ( !zip( tmpZipFilename ) )
2088  return false; // zip() already calls setError() when returning false
2089 
2090  QFile tmpZipFile( tmpZipFilename );
2091  if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
2092  {
2093  setError( tr( "Unable to read file %1" ).arg( tmpZipFilename ) );
2094  return false;
2095  }
2096 
2098  if ( !storage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
2099  {
2100  QString err = tr( "Unable to save project to storage %1" ).arg( mFile.fileName() );
2101  QList<QgsReadWriteContext::ReadWriteMessage> messages = context.takeMessages();
2102  if ( !messages.isEmpty() )
2103  err += QStringLiteral( "\n\n" ) + messages.last().message();
2104  setError( err );
2105  return false;
2106  }
2107 
2108  tmpZipFile.close();
2109  QFile::remove( tmpZipFilename );
2110 
2111  return true;
2112  }
2113 
2114  if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
2115  {
2116  return zip( mFile.fileName() );
2117  }
2118  else
2119  {
2120  // write project file even if the auxiliary storage is not correctly
2121  // saved
2122  const bool asOk = saveAuxiliaryStorage();
2123  const bool writeOk = writeProjectFile( mFile.fileName() );
2124 
2125  // errors raised during writing project file are more important
2126  if ( !asOk && writeOk )
2127  {
2128  const QString err = mAuxiliaryStorage->errorString();
2129  setError( tr( "Unable to save auxiliary storage ('%1')" ).arg( err ) );
2130  }
2131 
2132  return asOk && writeOk;
2133  }
2134 }
2135 
2136 bool QgsProject::writeProjectFile( const QString &filename )
2137 {
2138  QFile projectFile( filename );
2139  clearError();
2140 
2141  // if we have problems creating or otherwise writing to the project file,
2142  // let's find out up front before we go through all the hand-waving
2143  // necessary to create all the Dom objects
2144  QFileInfo myFileInfo( projectFile );
2145  if ( myFileInfo.exists() && !myFileInfo.isWritable() )
2146  {
2147  setError( tr( "%1 is not writable. Please adjust permissions (if possible) and try again." )
2148  .arg( projectFile.fileName() ) );
2149  return false;
2150  }
2151 
2152  QgsReadWriteContext context;
2153  context.setPathResolver( pathResolver() );
2155 
2156  QDomImplementation DomImplementation;
2157  DomImplementation.setInvalidDataPolicy( QDomImplementation::DropInvalidChars );
2158 
2159  QDomDocumentType documentType =
2160  DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ),
2161  QStringLiteral( "SYSTEM" ) );
2162  std::unique_ptr<QDomDocument> doc( new QDomDocument( documentType ) );
2163 
2164  QDomElement qgisNode = doc->createElement( QStringLiteral( "qgis" ) );
2165  qgisNode.setAttribute( QStringLiteral( "projectname" ), title() );
2166  qgisNode.setAttribute( QStringLiteral( "version" ), Qgis::version() );
2167 
2168  QgsSettings settings;
2169  if ( !settings.value( QStringLiteral( "projects/anonymize_saved_projects" ), false, QgsSettings::Core ).toBool() )
2170  {
2171  QString newSaveUser = QgsApplication::userLoginName();
2172  QString newSaveUserFull = QgsApplication::userFullName();
2173  qgisNode.setAttribute( QStringLiteral( "saveUser" ), newSaveUser );
2174  qgisNode.setAttribute( QStringLiteral( "saveUserFull" ), newSaveUserFull );
2175  mSaveUser = newSaveUser;
2176  mSaveUserFull = newSaveUserFull;
2177  mSaveDateTime = QDateTime::currentDateTime();
2178  qgisNode.setAttribute( QStringLiteral( "saveDateTime" ), mSaveDateTime.toString( Qt::ISODate ) );
2179  }
2180  else
2181  {
2182  mSaveUser.clear();
2183  mSaveUserFull.clear();
2184  mSaveDateTime = QDateTime();
2185  }
2186  doc->appendChild( qgisNode );
2187  mSaveVersion = QgsProjectVersion( Qgis::version() );
2188 
2189  QDomElement homePathNode = doc->createElement( QStringLiteral( "homePath" ) );
2190  homePathNode.setAttribute( QStringLiteral( "path" ), mHomePath );
2191  qgisNode.appendChild( homePathNode );
2192 
2193  // title
2194  QDomElement titleNode = doc->createElement( QStringLiteral( "title" ) );
2195  qgisNode.appendChild( titleNode );
2196 
2197  QDomElement transactionNode = doc->createElement( QStringLiteral( "autotransaction" ) );
2198  transactionNode.setAttribute( QStringLiteral( "active" ), mAutoTransaction ? 1 : 0 );
2199  qgisNode.appendChild( transactionNode );
2200 
2201  QDomElement evaluateDefaultValuesNode = doc->createElement( QStringLiteral( "evaluateDefaultValues" ) );
2202  evaluateDefaultValuesNode.setAttribute( QStringLiteral( "active" ), mEvaluateDefaultValues ? 1 : 0 );
2203  qgisNode.appendChild( evaluateDefaultValuesNode );
2204 
2205  QDomElement trustNode = doc->createElement( QStringLiteral( "trust" ) );
2206  trustNode.setAttribute( QStringLiteral( "active" ), mTrustLayerMetadata ? 1 : 0 );
2207  qgisNode.appendChild( trustNode );
2208 
2209  QDomText titleText = doc->createTextNode( title() ); // XXX why have title TWICE?
2210  titleNode.appendChild( titleText );
2211 
2212  // write project CRS
2213  QDomElement srsNode = doc->createElement( QStringLiteral( "projectCrs" ) );
2214  mCrs.writeXml( srsNode, *doc );
2215  qgisNode.appendChild( srsNode );
2216 
2217  // write layer tree - make sure it is without embedded subgroups
2218  QgsLayerTreeNode *clonedRoot = mRootGroup->clone();
2220  QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ), this ); // convert absolute paths to relative paths if required
2221 
2222  clonedRoot->writeXml( qgisNode, context );
2223  delete clonedRoot;
2224 
2225  mSnappingConfig.writeProject( *doc );
2226  writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsMode" ), static_cast<int>( mAvoidIntersectionsMode ) );
2227 
2228  // let map canvas and legend write their information
2229  emit writeProject( *doc );
2230 
2231  // within top level node save list of layers
2232  const QMap<QString, QgsMapLayer *> &layers = mapLayers();
2233 
2234  QDomElement annotationLayerNode = doc->createElement( QStringLiteral( "main-annotation-layer" ) );
2235  mMainAnnotationLayer->writeLayerXml( annotationLayerNode, *doc, context );
2236  qgisNode.appendChild( annotationLayerNode );
2237 
2238  // Iterate over layers in zOrder
2239  // Call writeXml() on each
2240  QDomElement projectLayersNode = doc->createElement( QStringLiteral( "projectlayers" ) );
2241 
2242  QMap<QString, QgsMapLayer *>::ConstIterator li = layers.constBegin();
2243  while ( li != layers.end() )
2244  {
2245  QgsMapLayer *ml = li.value();
2246 
2247  if ( ml )
2248  {
2249  QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->id() );
2250  if ( emIt == mEmbeddedLayers.constEnd() )
2251  {
2252  QDomElement maplayerElem;
2253  // If layer is not valid, prefer to restore saved properties from invalidLayerProperties. But if that's
2254  // not available, just write what we DO have
2255  if ( ml->isValid() || ml->originalXmlProperties().isEmpty() )
2256  {
2257  // general layer metadata
2258  maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );
2259  ml->writeLayerXml( maplayerElem, *doc, context );
2260  }
2261  else if ( ! ml->originalXmlProperties().isEmpty() )
2262  {
2263  QDomDocument document;
2264  if ( document.setContent( ml->originalXmlProperties() ) )
2265  {
2266  maplayerElem = document.firstChildElement();
2267  }
2268  else
2269  {
2270  QgsDebugMsg( QStringLiteral( "Could not restore layer properties for layer %1" ).arg( ml->id() ) );
2271  }
2272  }
2273 
2274  emit writeMapLayer( ml, maplayerElem, *doc );
2275 
2276  projectLayersNode.appendChild( maplayerElem );
2277  }
2278  else
2279  {
2280  // layer defined in an external project file
2281  // only save embedded layer if not managed by a legend group
2282  if ( emIt.value().second )
2283  {
2284  QDomElement mapLayerElem = doc->createElement( QStringLiteral( "maplayer" ) );
2285  mapLayerElem.setAttribute( QStringLiteral( "embedded" ), 1 );
2286  mapLayerElem.setAttribute( QStringLiteral( "project" ), writePath( emIt.value().first ) );
2287  mapLayerElem.setAttribute( QStringLiteral( "id" ), ml->id() );
2288  projectLayersNode.appendChild( mapLayerElem );
2289  }
2290  }
2291  }
2292  li++;
2293  }
2294 
2295  qgisNode.appendChild( projectLayersNode );
2296 
2297  QDomElement layerOrderNode = doc->createElement( QStringLiteral( "layerorder" ) );
2298  const auto constCustomLayerOrder = mRootGroup->customLayerOrder();
2299  for ( QgsMapLayer *layer : constCustomLayerOrder )
2300  {
2301  QDomElement mapLayerElem = doc->createElement( QStringLiteral( "layer" ) );
2302  mapLayerElem.setAttribute( QStringLiteral( "id" ), layer->id() );
2303  layerOrderNode.appendChild( mapLayerElem );
2304  }
2305  qgisNode.appendChild( layerOrderNode );
2306 
2307  mLabelingEngineSettings->writeSettingsToProject( this );
2308 
2309  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), mBackgroundColor.red() );
2310  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), mBackgroundColor.green() );
2311  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), mBackgroundColor.blue() );
2312 
2313  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorRedPart" ), mSelectionColor.red() );
2314  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorGreenPart" ), mSelectionColor.green() );
2315  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorBluePart" ), mSelectionColor.blue() );
2316  writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorAlphaPart" ), mSelectionColor.alpha() );
2317 
2318  // now add the optional extra properties
2319 #if 0
2320  dump_( mProperties );
2321 #endif
2322 
2323  QgsDebugMsgLevel( QStringLiteral( "there are %1 property scopes" ).arg( static_cast<int>( mProperties.count() ) ), 2 );
2324 
2325  if ( !mProperties.isEmpty() ) // only worry about properties if we
2326  // actually have any properties
2327  {
2328  mProperties.writeXml( QStringLiteral( "properties" ), qgisNode, *doc );
2329  }
2330 
2331  QDomElement ddElem = doc->createElement( QStringLiteral( "dataDefinedServerProperties" ) );
2332  mDataDefinedServerProperties.writeXml( ddElem, dataDefinedServerPropertyDefinitions() );
2333  qgisNode.appendChild( ddElem );
2334 
2335  mMapThemeCollection->writeXml( *doc );
2336 
2337  mTransformContext.writeXml( qgisNode, context );
2338 
2339  QDomElement metadataElem = doc->createElement( QStringLiteral( "projectMetadata" ) );
2340  mMetadata.writeMetadataXml( metadataElem, *doc );
2341  qgisNode.appendChild( metadataElem );
2342 
2343  QDomElement annotationsElem = mAnnotationManager->writeXml( *doc, context );
2344  qgisNode.appendChild( annotationsElem );
2345 
2346  QDomElement layoutElem = mLayoutManager->writeXml( *doc );
2347  qgisNode.appendChild( layoutElem );
2348 
2349  QDomElement bookmarkElem = mBookmarkManager->writeXml( *doc );
2350  qgisNode.appendChild( bookmarkElem );
2351 
2352  QDomElement viewSettingsElem = mViewSettings->writeXml( *doc, context );
2353  qgisNode.appendChild( viewSettingsElem );
2354 
2355  QDomElement timeSettingsElement = mTimeSettings->writeXml( *doc, context );
2356  qgisNode.appendChild( timeSettingsElement );
2357 
2358  QDomElement displaySettingsElem = mDisplaySettings->writeXml( *doc, context );
2359  qgisNode.appendChild( displaySettingsElem );
2360 
2361  // now wrap it up and ship it to the project file
2362  doc->normalize(); // XXX I'm not entirely sure what this does
2363 
2364  // Create backup file
2365  if ( QFile::exists( fileName() ) )
2366  {
2367  QFile backupFile( QStringLiteral( "%1~" ).arg( filename ) );
2368  bool ok = true;
2369  ok &= backupFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
2370  ok &= projectFile.open( QIODevice::ReadOnly );
2371 
2372  QByteArray ba;
2373  while ( ok && !projectFile.atEnd() )
2374  {
2375  ba = projectFile.read( 10240 );
2376  ok &= backupFile.write( ba ) == ba.size();
2377  }
2378 
2379  projectFile.close();
2380  backupFile.close();
2381 
2382  if ( !ok )
2383  {
2384  setError( tr( "Unable to create backup file %1" ).arg( backupFile.fileName() ) );
2385  return false;
2386  }
2387 
2388  QFileInfo fi( fileName() );
2389  struct utimbuf tb = { static_cast<time_t>( fi.lastRead().toSecsSinceEpoch() ), static_cast<time_t>( fi.lastModified().toSecsSinceEpoch() ) };
2390  utime( backupFile.fileName().toUtf8().constData(), &tb );
2391  }
2392 
2393  if ( !projectFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
2394  {
2395  projectFile.close(); // even though we got an error, let's make
2396  // sure it's closed anyway
2397 
2398  setError( tr( "Unable to save to file %1" ).arg( projectFile.fileName() ) );
2399  return false;
2400  }
2401 
2402  QTemporaryFile tempFile;
2403  bool ok = tempFile.open();
2404  if ( ok )
2405  {
2406  QTextStream projectFileStream( &tempFile );
2407  doc->save( projectFileStream, 2 ); // save as utf-8
2408  ok &= projectFileStream.pos() > -1;
2409 
2410  ok &= tempFile.seek( 0 );
2411 
2412  QByteArray ba;
2413  while ( ok && !tempFile.atEnd() )
2414  {
2415  ba = tempFile.read( 10240 );
2416  ok &= projectFile.write( ba ) == ba.size();
2417  }
2418 
2419  ok &= projectFile.error() == QFile::NoError;
2420 
2421  projectFile.close();
2422  }
2423 
2424  tempFile.close();
2425 
2426  if ( !ok )
2427  {
2428  setError( tr( "Unable to save to file %1. Your project "
2429  "may be corrupted on disk. Try clearing some space on the volume and "
2430  "check file permissions before pressing save again." )
2431  .arg( projectFile.fileName() ) );
2432  return false;
2433  }
2434 
2435  setDirty( false ); // reset to pristine state
2436 
2437  emit projectSaved();
2438  return true;
2439 }
2440 
2441 bool QgsProject::writeEntry( const QString &scope, QString const &key, bool value )
2442 {
2443  bool propertiesModified;
2444  bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2445 
2446  if ( propertiesModified )
2447  setDirty( true );
2448 
2449  return success;
2450 }
2451 
2452 bool QgsProject::writeEntry( const QString &scope, const QString &key, double value )
2453 {
2454  bool propertiesModified;
2455  bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2456 
2457  if ( propertiesModified )
2458  setDirty( true );
2459 
2460  return success;
2461 }
2462 
2463 bool QgsProject::writeEntry( const QString &scope, QString const &key, int value )
2464 {
2465  bool propertiesModified;
2466  bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2467 
2468  if ( propertiesModified )
2469  setDirty( true );
2470 
2471  return success;
2472 }
2473 
2474 bool QgsProject::writeEntry( const QString &scope, const QString &key, const QString &value )
2475 {
2476  bool propertiesModified;
2477  bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2478 
2479  if ( propertiesModified )
2480  setDirty( true );
2481 
2482  return success;
2483 }
2484 
2485 bool QgsProject::writeEntry( const QString &scope, const QString &key, const QStringList &value )
2486 {
2487  bool propertiesModified;
2488  bool success = addKey_( scope, key, &mProperties, value, propertiesModified );
2489 
2490  if ( propertiesModified )
2491  setDirty( true );
2492 
2493  return success;
2494 }
2495 
2496 QStringList QgsProject::readListEntry( const QString &scope,
2497  const QString &key,
2498  const QStringList &def,
2499  bool *ok ) const
2500 {
2501  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2502 
2503  QVariant value;
2504 
2505  if ( property )
2506  {
2507  value = property->value();
2508 
2509  bool valid = QVariant::StringList == value.type();
2510  if ( ok )
2511  *ok = valid;
2512 
2513  if ( valid )
2514  {
2515  return value.toStringList();
2516  }
2517  }
2518  else if ( ok )
2519  *ok = false;
2520 
2521 
2522  return def;
2523 }
2524 
2525 
2526 QString QgsProject::readEntry( const QString &scope,
2527  const QString &key,
2528  const QString &def,
2529  bool *ok ) const
2530 {
2531  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2532 
2533  QVariant value;
2534 
2535  if ( property )
2536  {
2537  value = property->value();
2538 
2539  bool valid = value.canConvert( QVariant::String );
2540  if ( ok )
2541  *ok = valid;
2542 
2543  if ( valid )
2544  return value.toString();
2545  }
2546  else if ( ok )
2547  *ok = false;
2548 
2549  return def;
2550 }
2551 
2552 int QgsProject::readNumEntry( const QString &scope, const QString &key, int def,
2553  bool *ok ) const
2554 {
2555  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2556 
2557  QVariant value;
2558 
2559  if ( property )
2560  {
2561  value = property->value();
2562  }
2563 
2564  bool valid = value.canConvert( QVariant::Int );
2565 
2566  if ( ok )
2567  {
2568  *ok = valid;
2569  }
2570 
2571  if ( valid )
2572  {
2573  return value.toInt();
2574  }
2575 
2576  return def;
2577 }
2578 
2579 double QgsProject::readDoubleEntry( const QString &scope, const QString &key,
2580  double def,
2581  bool *ok ) const
2582 {
2583  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2584  if ( property )
2585  {
2586  QVariant value = property->value();
2587 
2588  bool valid = value.canConvert( QVariant::Double );
2589  if ( ok )
2590  *ok = valid;
2591 
2592  if ( valid )
2593  return value.toDouble();
2594  }
2595  else if ( ok )
2596  *ok = false;
2597 
2598  return def;
2599 }
2600 
2601 bool QgsProject::readBoolEntry( const QString &scope, const QString &key, bool def,
2602  bool *ok ) const
2603 {
2604  QgsProjectProperty *property = findKey_( scope, key, mProperties );
2605 
2606  if ( property )
2607  {
2608  QVariant value = property->value();
2609 
2610  bool valid = value.canConvert( QVariant::Bool );
2611  if ( ok )
2612  *ok = valid;
2613 
2614  if ( valid )
2615  return value.toBool();
2616  }
2617  else if ( ok )
2618  *ok = false;
2619 
2620  return def;
2621 }
2622 
2623 bool QgsProject::removeEntry( const QString &scope, const QString &key )
2624 {
2625  if ( findKey_( scope, key, mProperties ) )
2626  {
2627  removeKey_( scope, key, mProperties );
2628  setDirty( true );
2629  }
2630 
2631  return !findKey_( scope, key, mProperties );
2632 }
2633 
2634 
2635 QStringList QgsProject::entryList( const QString &scope, const QString &key ) const
2636 {
2637  QgsProjectProperty *foundProperty = findKey_( scope, key, mProperties );
2638 
2639  QStringList entries;
2640 
2641  if ( foundProperty )
2642  {
2643  QgsProjectPropertyKey *propertyKey = dynamic_cast<QgsProjectPropertyKey *>( foundProperty );
2644 
2645  if ( propertyKey )
2646  { propertyKey->entryList( entries ); }
2647  }
2648 
2649  return entries;
2650 }
2651 
2652 QStringList QgsProject::subkeyList( const QString &scope, const QString &key ) const
2653 {
2654  QgsProjectProperty *foundProperty = findKey_( scope, key, mProperties );
2655 
2656  QStringList entries;
2657 
2658  if ( foundProperty )
2659  {
2660  QgsProjectPropertyKey *propertyKey = dynamic_cast<QgsProjectPropertyKey *>( foundProperty );
2661 
2662  if ( propertyKey )
2663  { propertyKey->subkeyList( entries ); }
2664  }
2665 
2666  return entries;
2667 }
2668 
2670 {
2671  dump_( mProperties );
2672 }
2673 
2675 {
2676  bool absolutePaths = readBoolEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), false );
2677  QString filePath;
2678  if ( ! absolutePaths )
2679  {
2680  // for projects stored in a custom storage, we need to ask to the
2681  // storage for the path, if the storage returns an empty path
2682  // relative paths are not supported
2683  if ( QgsProjectStorage *storage = projectStorage() )
2684  {
2685  filePath = storage->filePath( mFile.fileName() );
2686  }
2687  else
2688  {
2689  filePath = fileName();
2690  }
2691  }
2692  return QgsPathResolver( filePath );
2693 }
2694 
2695 QString QgsProject::readPath( const QString &src ) const
2696 {
2697  return pathResolver().readPath( src );
2698 }
2699 
2700 QString QgsProject::writePath( const QString &src ) const
2701 {
2702  return pathResolver().writePath( src );
2703 }
2704 
2705 void QgsProject::setError( const QString &errorMessage )
2706 {
2707  mErrorMessage = errorMessage;
2708 }
2709 
2710 QString QgsProject::error() const
2711 {
2712  return mErrorMessage;
2713 }
2714 
2715 void QgsProject::clearError()
2716 {
2717  setError( QString() );
2718 }
2719 
2721 {
2722  delete mBadLayerHandler;
2723  mBadLayerHandler = handler;
2724 }
2725 
2726 QString QgsProject::layerIsEmbedded( const QString &id ) const
2727 {
2728  QHash< QString, QPair< QString, bool > >::const_iterator it = mEmbeddedLayers.find( id );
2729  if ( it == mEmbeddedLayers.constEnd() )
2730  {
2731  return QString();
2732  }
2733  return it.value().first;
2734 }
2735 
2736 bool QgsProject::createEmbeddedLayer( const QString &layerId, const QString &projectFilePath, QList<QDomNode> &brokenNodes,
2737  bool saveFlag, QgsProject::ReadFlags flags )
2738 {
2739  QgsDebugCall;
2740 
2741  static QString sPrevProjectFilePath;
2742  static QDateTime sPrevProjectFileTimestamp;
2743  static QDomDocument sProjectDocument;
2744 
2745  QString qgsProjectFile = projectFilePath;
2746  QgsProjectArchive archive;
2747  if ( projectFilePath.endsWith( QLatin1String( ".qgz" ), Qt::CaseInsensitive ) )
2748  {
2749  archive.unzip( projectFilePath );
2750  qgsProjectFile = archive.projectFile();
2751  }
2752 
2753  QDateTime projectFileTimestamp = QFileInfo( projectFilePath ).lastModified();
2754 
2755  if ( projectFilePath != sPrevProjectFilePath || projectFileTimestamp != sPrevProjectFileTimestamp )
2756  {
2757  sPrevProjectFilePath.clear();
2758 
2759  QFile projectFile( qgsProjectFile );
2760  if ( !projectFile.open( QIODevice::ReadOnly ) )
2761  {
2762  return false;
2763  }
2764 
2765  if ( !sProjectDocument.setContent( &projectFile ) )
2766  {
2767  return false;
2768  }
2769 
2770  sPrevProjectFilePath = projectFilePath;
2771  sPrevProjectFileTimestamp = projectFileTimestamp;
2772  }
2773 
2774  // does project store paths absolute or relative?
2775  bool useAbsolutePaths = true;
2776 
2777  QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral( "properties" ) );
2778  if ( !propertiesElem.isNull() )
2779  {
2780  QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral( "Paths" ) ).firstChildElement( QStringLiteral( "Absolute" ) );
2781  if ( !absElem.isNull() )
2782  {
2783  useAbsolutePaths = absElem.text().compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
2784  }
2785  }
2786 
2787  QgsReadWriteContext embeddedContext;
2788  if ( !useAbsolutePaths )
2789  embeddedContext.setPathResolver( QgsPathResolver( projectFilePath ) );
2790  embeddedContext.setProjectTranslator( this );
2791  embeddedContext.setTransformContext( transformContext() );
2792 
2793  QDomElement projectLayersElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral( "projectlayers" ) );
2794  if ( projectLayersElem.isNull() )
2795  {
2796  return false;
2797  }
2798 
2799  QDomNodeList mapLayerNodes = projectLayersElem.elementsByTagName( QStringLiteral( "maplayer" ) );
2800  for ( int i = 0; i < mapLayerNodes.size(); ++i )
2801  {
2802  // get layer id
2803  QDomElement mapLayerElem = mapLayerNodes.at( i ).toElement();
2804  QString id = mapLayerElem.firstChildElement( QStringLiteral( "id" ) ).text();
2805  if ( id == layerId )
2806  {
2807  // layer can be embedded only once
2808  if ( mapLayerElem.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
2809  {
2810  return false;
2811  }
2812 
2813  mEmbeddedLayers.insert( layerId, qMakePair( projectFilePath, saveFlag ) );
2814 
2815  if ( addLayer( mapLayerElem, brokenNodes, embeddedContext, flags ) )
2816  {
2817  return true;
2818  }
2819  else
2820  {
2821  mEmbeddedLayers.remove( layerId );
2822  return false;
2823  }
2824  }
2825  }
2826 
2827  return false;
2828 }
2829 
2830 
2831 QgsLayerTreeGroup *QgsProject::createEmbeddedGroup( const QString &groupName, const QString &projectFilePath, const QStringList &invisibleLayers, QgsProject::ReadFlags flags )
2832 {
2833  QString qgsProjectFile = projectFilePath;
2834  QgsProjectArchive archive;
2835  if ( projectFilePath.endsWith( QLatin1String( ".qgz" ), Qt::CaseInsensitive ) )
2836  {
2837  archive.unzip( projectFilePath );
2838  qgsProjectFile = archive.projectFile();
2839  }
2840 
2841  // open project file, get layer ids in group, add the layers
2842  QFile projectFile( qgsProjectFile );
2843  if ( !projectFile.open( QIODevice::ReadOnly ) )
2844  {
2845  return nullptr;
2846  }
2847 
2848  QDomDocument projectDocument;
2849  if ( !projectDocument.setContent( &projectFile ) )
2850  {
2851  return nullptr;
2852  }
2853 
2854  QgsReadWriteContext context;
2855  context.setPathResolver( pathResolver() );
2856  context.setProjectTranslator( this );
2858 
2860 
2861  QDomElement layerTreeElem = projectDocument.documentElement().firstChildElement( QStringLiteral( "layer-tree-group" ) );
2862  if ( !layerTreeElem.isNull() )
2863  {
2864  root->readChildrenFromXml( layerTreeElem, context );
2865  }
2866  else
2867  {
2868  QgsLayerTreeUtils::readOldLegend( root, projectDocument.documentElement().firstChildElement( QStringLiteral( "legend" ) ) );
2869  }
2870 
2871  QgsLayerTreeGroup *group = root->findGroup( groupName );
2872  if ( !group || group->customProperty( QStringLiteral( "embedded" ) ).toBool() )
2873  {
2874  // embedded groups cannot be embedded again
2875  delete root;
2876  return nullptr;
2877  }
2878 
2879  // clone the group sub-tree (it is used already in a tree, we cannot just tear it off)
2880  QgsLayerTreeGroup *newGroup = QgsLayerTree::toGroup( group->clone() );
2881  delete root;
2882  root = nullptr;
2883 
2884  newGroup->setCustomProperty( QStringLiteral( "embedded" ), 1 );
2885  newGroup->setCustomProperty( QStringLiteral( "embedded_project" ), projectFilePath );
2886 
2887  // set "embedded" to all children + load embedded layers
2888  mLayerTreeRegistryBridge->setEnabled( false );
2889  initializeEmbeddedSubtree( projectFilePath, newGroup, flags );
2890  mLayerTreeRegistryBridge->setEnabled( true );
2891 
2892  // consider the layers might be identify disabled in its project
2893  const auto constFindLayerIds = newGroup->findLayerIds();
2894  for ( const QString &layerId : constFindLayerIds )
2895  {
2896  QgsLayerTreeLayer *layer = newGroup->findLayer( layerId );
2897  if ( layer )
2898  {
2899  layer->resolveReferences( this );
2900  layer->setItemVisibilityChecked( !invisibleLayers.contains( layerId ) );
2901  }
2902  }
2903 
2904  return newGroup;
2905 }
2906 
2907 void QgsProject::initializeEmbeddedSubtree( const QString &projectFilePath, QgsLayerTreeGroup *group, QgsProject::ReadFlags flags )
2908 {
2909  const auto constChildren = group->children();
2910  for ( QgsLayerTreeNode *child : constChildren )
2911  {
2912  // all nodes in the subtree will have "embedded" custom property set
2913  child->setCustomProperty( QStringLiteral( "embedded" ), 1 );
2914 
2915  if ( QgsLayerTree::isGroup( child ) )
2916  {
2917  initializeEmbeddedSubtree( projectFilePath, QgsLayerTree::toGroup( child ), flags );
2918  }
2919  else if ( QgsLayerTree::isLayer( child ) )
2920  {
2921  // load the layer into our project
2922  QList<QDomNode> brokenNodes;
2923  createEmbeddedLayer( QgsLayerTree::toLayer( child )->layerId(), projectFilePath, brokenNodes, false, flags );
2924  }
2925  }
2926 }
2927 
2929 {
2930  return mEvaluateDefaultValues;
2931 }
2932 
2933 void QgsProject::setEvaluateDefaultValues( bool evaluateDefaultValues )
2934 {
2935  if ( evaluateDefaultValues == mEvaluateDefaultValues )
2936  return;
2937 
2938  const QMap<QString, QgsMapLayer *> layers = mapLayers();
2939  QMap<QString, QgsMapLayer *>::const_iterator layerIt = layers.constBegin();
2940  for ( ; layerIt != layers.constEnd(); ++layerIt )
2941  {
2942  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layerIt.value() );
2943  if ( vl )
2944  {
2946  }
2947  }
2948 
2949  mEvaluateDefaultValues = evaluateDefaultValues;
2950 }
2951 
2953 {
2954  writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/TopologicalEditing" ), ( enabled ? 1 : 0 ) );
2956 }
2957 
2959 {
2960  return readNumEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/TopologicalEditing" ), 0 );
2961 }
2962 
2964 {
2965  QString distanceUnitString = readEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/DistanceUnits" ), QString() );
2966  if ( !distanceUnitString.isEmpty() )
2967  return QgsUnitTypes::decodeDistanceUnit( distanceUnitString );
2968 
2969  //fallback to QGIS default measurement unit
2970  QgsSettings s;
2971  bool ok = false;
2972  QgsUnitTypes::DistanceUnit type = QgsUnitTypes::decodeDistanceUnit( s.value( QStringLiteral( "/qgis/measure/displayunits" ) ).toString(), &ok );
2973  return ok ? type : QgsUnitTypes::DistanceMeters;
2974 }
2975 
2977 {
2978  writeEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/DistanceUnits" ), QgsUnitTypes::encodeUnit( unit ) );
2979 }
2980 
2982 {
2983  QString areaUnitString = readEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/AreaUnits" ), QString() );
2984  if ( !areaUnitString.isEmpty() )
2985  return QgsUnitTypes::decodeAreaUnit( areaUnitString );
2986 
2987  //fallback to QGIS default area unit
2988  QgsSettings s;
2989  bool ok = false;
2990  QgsUnitTypes::AreaUnit type = QgsUnitTypes::decodeAreaUnit( s.value( QStringLiteral( "/qgis/measure/areaunits" ) ).toString(), &ok );
2991  return ok ? type : QgsUnitTypes::AreaSquareMeters;
2992 }
2993 
2995 {
2996  writeEntry( QStringLiteral( "Measurement" ), QStringLiteral( "/AreaUnits" ), QgsUnitTypes::encodeUnit( unit ) );
2997 }
2998 
2999 QString QgsProject::homePath() const
3000 {
3001  if ( !mCachedHomePath.isEmpty() )
3002  return mCachedHomePath;
3003 
3004  QFileInfo pfi( fileName() );
3005 
3006  if ( !mHomePath.isEmpty() )
3007  {
3008  QFileInfo homeInfo( mHomePath );
3009  if ( !homeInfo.isRelative() )
3010  {
3011  mCachedHomePath = mHomePath;
3012  return mHomePath;
3013  }
3014  }
3015  else if ( !fileName().isEmpty() )
3016  {
3017  mCachedHomePath = pfi.path();
3018 
3019  return mCachedHomePath;
3020  }
3021 
3022  if ( !pfi.exists() )
3023  {
3024  mCachedHomePath = mHomePath;
3025  return mHomePath;
3026  }
3027 
3028  if ( !mHomePath.isEmpty() )
3029  {
3030  // path is relative to project file
3031  mCachedHomePath = QDir::cleanPath( pfi.path() + '/' + mHomePath );
3032  }
3033  else
3034  {
3035  mCachedHomePath = pfi.canonicalPath();
3036  }
3037  return mCachedHomePath;
3038 }
3039 
3041 {
3042  return mHomePath;
3043 }
3044 
3046 {
3047  return mRelationManager;
3048 }
3049 
3051 {
3052  return mLayoutManager.get();
3053 }
3054 
3056 {
3057  return mLayoutManager.get();
3058 }
3059 
3061 {
3062  return mBookmarkManager;
3063 }
3064 
3066 {
3067  return mBookmarkManager;
3068 }
3069 
3071 {
3072  return mViewSettings;
3073 }
3074 
3076 {
3077  return mViewSettings;
3078 }
3079 
3081 {
3082  return mTimeSettings;
3083 }
3084 
3086 {
3087  return mTimeSettings;
3088 }
3089 
3091 {
3092  return mDisplaySettings;
3093 }
3094 
3096 {
3097  return mDisplaySettings;
3098 }
3099 
3101 {
3102  return mRootGroup;
3103 }
3104 
3106 {
3107  return mMapThemeCollection.get();
3108 }
3109 
3111 {
3112  return mAnnotationManager.get();
3113 }
3114 
3116 {
3117  return mAnnotationManager.get();
3118 }
3119 
3120 void QgsProject::setNonIdentifiableLayers( const QList<QgsMapLayer *> &layers )
3121 {
3122  const QMap<QString, QgsMapLayer *> &projectLayers = mapLayers();
3123  for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3124  {
3125  if ( layers.contains( it.value() ) == !it.value()->flags().testFlag( QgsMapLayer::Identifiable ) )
3126  continue;
3127 
3128  if ( layers.contains( it.value() ) )
3129  it.value()->setFlags( it.value()->flags() & ~QgsMapLayer::Identifiable );
3130  else
3131  it.value()->setFlags( it.value()->flags() | QgsMapLayer::Identifiable );
3132  }
3133 
3137 }
3138 
3139 void QgsProject::setNonIdentifiableLayers( const QStringList &layerIds )
3140 {
3141  QList<QgsMapLayer *> nonIdentifiableLayers;
3142  nonIdentifiableLayers.reserve( layerIds.count() );
3143  for ( const QString &layerId : layerIds )
3144  {
3145  QgsMapLayer *layer = mapLayer( layerId );
3146  if ( layer )
3147  nonIdentifiableLayers << layer;
3148  }
3152 }
3153 
3155 {
3156  QStringList nonIdentifiableLayers;
3157 
3158  const QMap<QString, QgsMapLayer *> &layers = mapLayers();
3159  for ( QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin(); it != layers.constEnd(); ++it )
3160  {
3161  if ( !it.value()->flags().testFlag( QgsMapLayer::Identifiable ) )
3162  {
3163  nonIdentifiableLayers.append( it.value()->id() );
3164  }
3165  }
3166  return nonIdentifiableLayers;
3167 }
3168 
3170 {
3171  return mAutoTransaction;
3172 }
3173 
3174 void QgsProject::setAutoTransaction( bool autoTransaction )
3175 {
3176  if ( autoTransaction != mAutoTransaction )
3177  {
3178  mAutoTransaction = autoTransaction;
3179 
3180  if ( autoTransaction )
3181  onMapLayersAdded( mapLayers().values() );
3182  else
3183  cleanTransactionGroups( true );
3184  }
3185 }
3186 
3187 QMap<QPair<QString, QString>, QgsTransactionGroup *> QgsProject::transactionGroups()
3188 {
3189  return mTransactionGroups;
3190 }
3191 
3192 
3193 //
3194 // QgsMapLayerStore methods
3195 //
3196 
3197 
3199 {
3200  return mLayerStore->count();
3201 }
3202 
3204 {
3205  return mLayerStore->validCount();
3206 }
3207 
3208 QgsMapLayer *QgsProject::mapLayer( const QString &layerId ) const
3209 {
3210  return mLayerStore->mapLayer( layerId );
3211 }
3212 
3213 QList<QgsMapLayer *> QgsProject::mapLayersByName( const QString &layerName ) const
3214 {
3215  return mLayerStore->mapLayersByName( layerName );
3216 }
3217 
3218 QList<QgsMapLayer *> QgsProject::mapLayersByShortName( const QString &shortName ) const
3219 {
3220  QList<QgsMapLayer *> layers;
3221  const auto constMapLayers { mLayerStore->mapLayers() };
3222  for ( const auto &l : constMapLayers )
3223  {
3224  if ( ! l->shortName().isEmpty() )
3225  {
3226  if ( l->shortName() == shortName )
3227  layers << l;
3228  }
3229  else if ( l->name() == shortName )
3230  {
3231  layers << l;
3232  }
3233  }
3234  return layers;
3235 }
3236 
3237 bool QgsProject::unzip( const QString &filename, QgsProject::ReadFlags flags )
3238 {
3239  clearError();
3240  std::unique_ptr<QgsProjectArchive> archive( new QgsProjectArchive() );
3241 
3242  // unzip the archive
3243  if ( !archive->unzip( filename ) )
3244  {
3245  setError( tr( "Unable to unzip file '%1'" ).arg( filename ) );
3246  return false;
3247  }
3248 
3249  // test if zip provides a .qgs file
3250  if ( archive->projectFile().isEmpty() )
3251  {
3252  setError( tr( "Zip archive does not provide a project file" ) );
3253  return false;
3254  }
3255 
3256  // load auxiliary storage
3257  if ( !archive->auxiliaryStorageFile().isEmpty() )
3258  {
3259  // database file is already a copy as it's been unzipped. So we don't open
3260  // auxiliary storage in copy mode in this case
3261  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( archive->auxiliaryStorageFile(), false ) );
3262  }
3263  else
3264  {
3265  mAuxiliaryStorage.reset( new QgsAuxiliaryStorage( *this ) );
3266  }
3267 
3268  // read the project file
3269  if ( ! readProjectFile( archive->projectFile(), flags ) )
3270  {
3271  setError( tr( "Cannot read unzipped qgs project file" ) );
3272  return false;
3273  }
3274 
3275  // keep the archive and remove the temporary .qgs file
3276  mArchive = std::move( archive );
3277  mArchive->clearProjectFile();
3278 
3279  return true;
3280 }
3281 
3282 bool QgsProject::zip( const QString &filename )
3283 {
3284  clearError();
3285 
3286  // save the current project in a temporary .qgs file
3287  std::unique_ptr<QgsProjectArchive> archive( new QgsProjectArchive() );
3288  const QString baseName = QFileInfo( filename ).baseName();
3289  const QString qgsFileName = QStringLiteral( "%1.qgs" ).arg( baseName );
3290  QFile qgsFile( QDir( archive->dir() ).filePath( qgsFileName ) );
3291 
3292  bool writeOk = false;
3293  if ( qgsFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
3294  {
3295  writeOk = writeProjectFile( qgsFile.fileName() );
3296  qgsFile.close();
3297  }
3298 
3299  // stop here with an error message
3300  if ( ! writeOk )
3301  {
3302  setError( tr( "Unable to write temporary qgs file" ) );
3303  return false;
3304  }
3305 
3306  // save auxiliary storage
3307  const QFileInfo info( qgsFile );
3308  const QString asFileName = info.path() + QDir::separator() + info.completeBaseName() + "." + QgsAuxiliaryStorage::extension();
3309 
3310  if ( ! saveAuxiliaryStorage( asFileName ) )
3311  {
3312  const QString err = mAuxiliaryStorage->errorString();
3313  setError( tr( "Unable to save auxiliary storage ('%1')" ).arg( err ) );
3314  return false;
3315  }
3316 
3317  // create the archive
3318  archive->addFile( qgsFile.fileName() );
3319  archive->addFile( asFileName );
3320 
3321  // zip
3322  if ( !archive->zip( filename ) )
3323  {
3324  setError( tr( "Unable to perform zip" ) );
3325  return false;
3326  }
3327 
3328  return true;
3329 }
3330 
3332 {
3333  return QgsZipUtils::isZipFile( mFile.fileName() );
3334 }
3335 
3336 QList<QgsMapLayer *> QgsProject::addMapLayers(
3337  const QList<QgsMapLayer *> &layers,
3338  bool addToLegend,
3339  bool takeOwnership )
3340 {
3341  const QList<QgsMapLayer *> myResultList { mLayerStore->addMapLayers( layers, takeOwnership ) };
3342  if ( !myResultList.isEmpty() )
3343  {
3344  // Update transform context
3345  for ( auto &l : myResultList )
3346  {
3347  l->setTransformContext( transformContext() );
3348  }
3349  if ( addToLegend )
3350  {
3351  emit legendLayersAdded( myResultList );
3352  }
3353  }
3354 
3355  if ( mAuxiliaryStorage )
3356  {
3357  for ( QgsMapLayer *mlayer : myResultList )
3358  {
3359  if ( mlayer->type() != QgsMapLayerType::VectorLayer )
3360  continue;
3361 
3362  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mlayer );
3363  if ( vl )
3364  {
3365  vl->loadAuxiliaryLayer( *mAuxiliaryStorage );
3366  }
3367  }
3368  }
3369 
3370  mProjectScope.reset();
3371 
3372  return myResultList;
3373 }
3374 
3375 QgsMapLayer *
3377  bool addToLegend,
3378  bool takeOwnership )
3379 {
3380  QList<QgsMapLayer *> addedLayers;
3381  addedLayers = addMapLayers( QList<QgsMapLayer *>() << layer, addToLegend, takeOwnership );
3382  return addedLayers.isEmpty() ? nullptr : addedLayers[0];
3383 }
3384 
3385 void QgsProject::removeMapLayers( const QStringList &layerIds )
3386 {
3387  mProjectScope.reset();
3388  mLayerStore->removeMapLayers( layerIds );
3389 }
3390 
3391 void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
3392 {
3393  mProjectScope.reset();
3394  mLayerStore->removeMapLayers( layers );
3395 }
3396 
3397 void QgsProject::removeMapLayer( const QString &layerId )
3398 {
3399  mProjectScope.reset();
3400  mLayerStore->removeMapLayer( layerId );
3401 }
3402 
3404 {
3405  mProjectScope.reset();
3406  mLayerStore->removeMapLayer( layer );
3407 }
3408 
3410 {
3411  mProjectScope.reset();
3412  return mLayerStore->takeMapLayer( layer );
3413 }
3414 
3416 {
3417  return mMainAnnotationLayer;
3418 }
3419 
3421 {
3422  mProjectScope.reset();
3423  mLayerStore->removeAllMapLayers();
3424 }
3425 
3427 {
3428  QMap<QString, QgsMapLayer *> layers = mLayerStore->mapLayers();
3429  QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin();
3430  for ( ; it != layers.constEnd(); ++it )
3431  {
3432  it.value()->reload();
3433  }
3434 }
3435 
3436 QMap<QString, QgsMapLayer *> QgsProject::mapLayers( const bool validOnly ) const
3437 {
3438  return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
3439 }
3440 
3441 QgsTransactionGroup *QgsProject::transactionGroup( const QString &providerKey, const QString &connString )
3442 {
3443  return mTransactionGroups.value( qMakePair( providerKey, connString ) );
3444 }
3445 
3447 {
3448  QgsSettings settings;
3449  QgsCoordinateReferenceSystem defaultCrs;
3450 
3451  // TODO QGIS 4.0 -- remove this method, and place it somewhere in app (where it belongs)
3452  // 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)
3453  if ( settings.value( QStringLiteral( "/projections/unknownCrsBehavior" ), QStringLiteral( "NoAction" ), QgsSettings::App ).toString() == QStringLiteral( "UseProjectCrs" )
3454  || settings.value( QStringLiteral( "/projections/unknownCrsBehavior" ), 0, QgsSettings::App ).toString() == 2 )
3455  {
3456  // for new layers if the new layer crs method is set to either prompt or use project, then we use the project crs
3457  defaultCrs = crs();
3458  }
3459  else
3460  {
3461  // global crs
3462  QString layerDefaultCrs = settings.value( QStringLiteral( "/Projections/layerDefaultCrs" ), geoEpsgCrsAuthId() ).toString();
3463  defaultCrs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( layerDefaultCrs );
3464  }
3465 
3466  return defaultCrs;
3467 }
3468 
3470 {
3471  mTrustLayerMetadata = trust;
3472 
3473  auto layers = mapLayers();
3474  for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
3475  {
3476  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
3477  if ( vl )
3478  {
3479  vl->setReadExtentFromXml( trust );
3480  }
3481  }
3482 }
3483 
3484 bool QgsProject::saveAuxiliaryStorage( const QString &filename )
3485 {
3486  const QMap<QString, QgsMapLayer *> layers = mapLayers();
3487  bool empty = true;
3488  for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
3489  {
3490  if ( it.value()->type() != QgsMapLayerType::VectorLayer )
3491  continue;
3492 
3493  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
3494  if ( vl && vl->auxiliaryLayer() )
3495  {
3496  vl->auxiliaryLayer()->save();
3497  empty &= vl->auxiliaryLayer()->auxiliaryFields().isEmpty();
3498  }
3499  }
3500 
3501  if ( !mAuxiliaryStorage->exists( *this ) && filename.isEmpty() && empty )
3502  {
3503  return true; // it's not an error
3504  }
3505  else if ( !filename.isEmpty() )
3506  {
3507  return mAuxiliaryStorage->saveAs( filename );
3508  }
3509  else
3510  {
3511  return mAuxiliaryStorage->saveAs( *this );
3512  }
3513 }
3514 
3515 QgsPropertiesDefinition &QgsProject::dataDefinedServerPropertyDefinitions()
3516 {
3517  static QgsPropertiesDefinition sPropertyDefinitions
3518  {
3519  {
3520  QgsProject::DataDefinedServerProperty::WMSOnlineResource,
3521  QgsPropertyDefinition( "WMSOnlineResource", QObject::tr( "WMS Online Resource" ), QgsPropertyDefinition::String )
3522  },
3523  };
3524  return sPropertyDefinitions;
3525 }
3526 
3528 {
3529  return mAuxiliaryStorage.get();
3530 }
3531 
3533 {
3534  return mAuxiliaryStorage.get();
3535 }
3536 
3538 {
3539  return mMetadata;
3540 }
3541 
3543 {
3544  if ( metadata == mMetadata )
3545  return;
3546 
3547  mMetadata = metadata;
3548  mProjectScope.reset();
3549 
3550  emit metadataChanged();
3551 
3552  setDirty( true );
3553 }
3554 
3555 QSet<QgsMapLayer *> QgsProject::requiredLayers() const
3556 {
3557  QSet<QgsMapLayer *> requiredLayers;
3558 
3559  const QMap<QString, QgsMapLayer *> &layers = mapLayers();
3560  for ( QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin(); it != layers.constEnd(); ++it )
3561  {
3562  if ( !it.value()->flags().testFlag( QgsMapLayer::Removable ) )
3563  {
3564  requiredLayers.insert( it.value() );
3565  }
3566  }
3567  return requiredLayers;
3568 }
3569 
3570 void QgsProject::setRequiredLayers( const QSet<QgsMapLayer *> &layers )
3571 {
3572  const QMap<QString, QgsMapLayer *> &projectLayers = mapLayers();
3573  for ( QMap<QString, QgsMapLayer *>::const_iterator it = projectLayers.constBegin(); it != projectLayers.constEnd(); ++it )
3574  {
3575  if ( layers.contains( it.value() ) == !it.value()->flags().testFlag( QgsMapLayer::Removable ) )
3576  continue;
3577 
3578  if ( layers.contains( it.value() ) )
3579  it.value()->setFlags( it.value()->flags() & ~QgsMapLayer::Removable );
3580  else
3581  it.value()->setFlags( it.value()->flags() | QgsMapLayer::Removable );
3582  }
3583 }
3584 
3586 {
3587  // save colors to project
3588  QStringList customColors;
3589  QStringList customColorLabels;
3590 
3591  QgsNamedColorList::const_iterator colorIt = colors.constBegin();
3592  for ( ; colorIt != colors.constEnd(); ++colorIt )
3593  {
3594  QString color = QgsSymbolLayerUtils::encodeColor( ( *colorIt ).first );
3595  QString label = ( *colorIt ).second;
3596  customColors.append( color );
3597  customColorLabels.append( label );
3598  }
3599  writeEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ), customColors );
3600  writeEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ), customColorLabels );
3601  mProjectScope.reset();
3602  emit projectColorsChanged();
3603 }
3604 
3605 void QgsProject::setBackgroundColor( const QColor &color )
3606 {
3607  if ( mBackgroundColor == color )
3608  return;
3609 
3610  mBackgroundColor = color;
3611  emit backgroundColorChanged();
3612 }
3613 
3615 {
3616  return mBackgroundColor;
3617 }
3618 
3619 void QgsProject::setSelectionColor( const QColor &color )
3620 {
3621  if ( mSelectionColor == color )
3622  return;
3623 
3624  mSelectionColor = color;
3625  emit selectionColorChanged();
3626 }
3627 
3629 {
3630  return mSelectionColor;
3631 }
3632 
3633 void QgsProject::setMapScales( const QVector<double> &scales )
3634 {
3635  mViewSettings->setMapScales( scales );
3636 }
3637 
3638 QVector<double> QgsProject::mapScales() const
3639 {
3640  return mViewSettings->mapScales();
3641 }
3642 
3644 {
3645  mViewSettings->setUseProjectScales( enabled );
3646 }
3647 
3649 {
3650  return mViewSettings->useProjectScales();
3651 }
3652 
3653 void QgsProject::generateTsFile( const QString &locale )
3654 {
3655  QgsTranslationContext translationContext;
3656  translationContext.setProject( this );
3657  translationContext.setFileName( QStringLiteral( "%1/%2.ts" ).arg( absolutePath(), baseName() ) );
3658 
3659  QgsApplication::instance()->collectTranslatableObjects( &translationContext );
3660 
3661  translationContext.writeTsFile( locale );
3662 }
3663 
3664 QString QgsProject::translate( const QString &context, const QString &sourceText, const char *disambiguation, int n ) const
3665 {
3666  if ( !mTranslator )
3667  {
3668  return sourceText;
3669  }
3670 
3671  QString result = mTranslator->translate( context.toUtf8(), sourceText.toUtf8(), disambiguation, n );
3672 
3673  if ( result.isEmpty() )
3674  {
3675  return sourceText;
3676  }
3677  return result;
3678 }
3679 
3681 {
3682  const QMap<QString, QgsMapLayer *> layers = mapLayers( false );
3683  if ( !layers.empty() )
3684  {
3685  for ( auto it = layers.constBegin(); it != layers.constEnd(); ++it )
3686  {
3687  // NOTE: if visitEnter returns false it means "don't visit this layer", not "abort all further visitations"
3688  if ( visitor->visitEnter( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Layer, ( *it )->id(), ( *it )->name() ) ) )
3689  {
3690  if ( !( ( *it )->accept( visitor ) ) )
3691  return false;
3692 
3693  if ( !visitor->visitExit( QgsStyleEntityVisitorInterface::Node( QgsStyleEntityVisitorInterface::NodeType::Layer, ( *it )->id(), ( *it )->name() ) ) )
3694  return false;
3695  }
3696  }
3697  }
3698 
3699  if ( !mLayoutManager->accept( visitor ) )
3700  return false;
3701 
3702  if ( !mAnnotationManager->accept( visitor ) )
3703  return false;
3704 
3705  return true;
3706 }
3707 
3709 GetNamedProjectColor::GetNamedProjectColor( const QgsProject *project )
3710  : QgsScopedExpressionFunction( QStringLiteral( "project_color" ), 1, QStringLiteral( "Color" ) )
3711 {
3712  if ( !project )
3713  return;
3714 
3715  //build up color list from project. Do this in advance for speed
3716  QStringList colorStrings = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Colors" ) );
3717  QStringList colorLabels = project->readListEntry( QStringLiteral( "Palette" ), QStringLiteral( "/Labels" ) );
3718 
3719  //generate list from custom colors
3720  int colorIndex = 0;
3721  for ( QStringList::iterator it = colorStrings.begin();
3722  it != colorStrings.end(); ++it )
3723  {
3724  QColor color = QgsSymbolLayerUtils::decodeColor( *it );
3725  QString label;
3726  if ( colorLabels.length() > colorIndex )
3727  {
3728  label = colorLabels.at( colorIndex );
3729  }
3730 
3731  mColors.insert( label.toLower(), color );
3732  colorIndex++;
3733  }
3734 }
3735 
3736 GetNamedProjectColor::GetNamedProjectColor( const QHash<QString, QColor> &colors )
3737  : QgsScopedExpressionFunction( QStringLiteral( "project_color" ), 1, QStringLiteral( "Color" ) )
3738  , mColors( colors )
3739 {
3740 }
3741 
3742 QVariant GetNamedProjectColor::func( const QVariantList &values, const QgsExpressionContext *, QgsExpression *, const QgsExpressionNodeFunction * )
3743 {
3744  QString colorName = values.at( 0 ).toString().toLower();
3745  if ( mColors.contains( colorName ) )
3746  {
3747  return QStringLiteral( "%1,%2,%3" ).arg( mColors.value( colorName ).red() ).arg( mColors.value( colorName ).green() ).arg( mColors.value( colorName ).blue() );
3748  }
3749  else
3750  return QVariant();
3751 }
3752 
3753 QgsScopedExpressionFunction *GetNamedProjectColor::clone() const
3754 {
3755  return new GetNamedProjectColor( mColors );
3756 }
QgsAttributeEditorElement
This is an abstract base class for any elements of a drag and drop form.
Definition: qgsattributeeditorelement.h:40
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:370
QgsSnappingConfig::readProject
void readProject(const QDomDocument &doc)
Reads the configuration from the specified QGIS project document.
Definition: qgssnappingconfig.cpp:403
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:105
QgsProject::writeEntry
bool writeEntry(const QString &scope, const QString &key, bool value)
Write a boolean value to the project file.
Definition: qgsproject.cpp:2441
QgsVectorLayer::setReadExtentFromXml
void setReadExtentFromXml(bool readExtentFromXml)
Flag allowing to indicate if the extent has to be read from the XML document when data source has no ...
Definition: qgsvectorlayer.cpp:5600
QgsLayerTreeGroup::findLayer
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
Definition: qgslayertreegroup.cpp:195
QgsLayerTreeGroup::findLayers
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Definition: qgslayertreegroup.cpp:223
QgsProject::title
QString title() const
Returns the project's title.
Definition: qgsproject.cpp:489
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:323
QgsProject::customVariables
QVariantMap customVariables() const
A map of custom project variables.
Definition: qgsproject.cpp:1786
QgsProject::setFileName
void setFileName(const QString &name)
Sets the file name associated with the project.
Definition: qgsproject.cpp:626
QgsProjectProperty::isValue
virtual bool isValue() const =0
Returns true if the property is a QgsProjectPropertyValue.
QgsProject::layers
QVector< T > layers() const
Returns a list of registered map layers with a specified layer type.
Definition: qgsproject.h:1070
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:52
QgsProject::projectStorage
QgsProjectStorage * projectStorage() const
Returns pointer to project storage implementation that handles read/write of the project file.
Definition: qgsproject.cpp:666
QgsProject::annotationManager
QgsAnnotationManager * annotationManager()
Returns pointer to the project's annotation manager.
Definition: qgsproject.cpp:3110
QgsLayerTreeUtils::readOldLegend
static bool readOldLegend(QgsLayerTreeGroup *root, const QDomElement &legendElem)
Try to load layer tree from.
Definition: qgslayertreeutils.cpp:28
QgsLayerTreeNode
This class is a base class for nodes in a layer tree.
Definition: qgslayertreenode.h:75
QgsProject::selectionColor
QColor selectionColor
Definition: qgsproject.h:110
QgsMapLayerStore::allLayersRemoved
void allLayersRemoved()
Emitted when all layers are removed, before layersWillBeRemoved() and layerWillBeRemoved() signals ar...
QgsTransactionGroup
Definition: qgstransactiongroup.h:32
QgsProject::avoidIntersectionsLayers
QList< QgsVectorLayer * > avoidIntersectionsLayers
Definition: qgsproject.h:107
QgsLayoutManager
Manages storage of a set of layouts.
Definition: qgslayoutmanager.h:45
Qgis::version
static QString version()
Version string.
Definition: qgis.cpp:276
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
QgsCoordinateReferenceSystem::description
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
Definition: qgscoordinatereferencesystem.cpp:1326
makeKeyTokens_
QStringList makeKeyTokens_(const QString &scope, const QString &key)
Take the given scope and key and convert them to a string list of key tokens that will be used to nav...
Definition: qgsproject.cpp:95
QgsCoordinateTransformContext
Contains information about the context in which a coordinate transform is executed.
Definition: qgscoordinatetransformcontext.h:58
qgsrasterlayer.h
QgsProjectViewSettings::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Returns a DOM element representing the settings.
Definition: qgsprojectviewsettings.cpp:122
qgsruntimeprofiler.h
QgsMapLayer::FlagTrustLayerMetadata
@ FlagTrustLayerMetadata
Trust layer metadata. Improves layer load time by skipping expensive checks like primary key unicity,...
Definition: qgsmaplayer.h:557
QgsCoordinateReferenceSystem::mapUnits
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
Definition: qgscoordinatereferencesystem.h:209
QgsProject::layersWillBeRemoved
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
QgsProject::setAutoTransaction
void setAutoTransaction(bool autoTransaction)
Transactional editing means that on supported datasources (postgres databases) the edit state of all ...
Definition: qgsproject.cpp:3174
QgsMapLayer::configChanged
void configChanged()
Emitted whenever the configuration is changed.
QgsProjectViewSettings::mapScalesChanged
void mapScalesChanged()
Emitted when the list of custom project map scales changes.
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:391
QgsProject::mapThemeCollectionChanged
void mapThemeCollectionChanged()
Emitted when the map theme collection changes.
qgsziputils.h
QgsLayerTreeNode::setItemVisibilityChecked
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
Definition: qgslayertreenode.cpp:78
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsExpressionContextUtils::globalScope
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Definition: qgsexpressioncontextutils.cpp:34
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:35
QgsProjectArchive::unzip
bool unzip(const QString &zipFilename) override
Clear the current content of this archive and unzip.
Definition: qgsarchive.cpp:142
qgsrectangle.h
QgsCoordinateReferenceSystem::projectionAcronym
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
Definition: qgscoordinatereferencesystem.cpp:1361
qgslayertreeregistrybridge.h
QgsProjectMetadata
A structured metadata store for a map layer.
Definition: qgsprojectmetadata.h:54
QgsProject::layersAdded
void layersAdded(const QList< QgsMapLayer * > &layers)
Emitted when one or more layers were added to the registry.
QgsProject::mapScales
Q_DECL_DEPRECATED QVector< double > mapScales() const
Returns the list of custom project map scales.
Definition: qgsproject.cpp:3638
QgsMapLayerType::VectorLayer
@ VectorLayer
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:2635
removeKey_
void removeKey_(const QString &scope, const QString &key, QgsProjectPropertyKey &rootProperty)
Remove a given key.
Definition: qgsproject.cpp:305
QgsLayerTreeGroup::resolveReferences
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Calls resolveReferences() on child tree nodes.
Definition: qgslayertreegroup.cpp:352
QgsProject::metadata
QgsProjectMetadata metadata
Definition: qgsproject.h:108
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:2963
QgsProject::mapLayersByName
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
Definition: qgsproject.cpp:3213
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:3436
QgsProject::setBackgroundColor
void setBackgroundColor(const QColor &color)
Sets the default background color used by default map canvases.
Definition: qgsproject.cpp:3605
QgsCoordinateReferenceSystem::WKT_PREFERRED
@ WKT_PREFERRED
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
Definition: qgscoordinatereferencesystem.h:679
QgsSettings::Core
@ Core
Definition: qgssettings.h:70
QgsProject::ReadFlag::FlagDontLoadLayouts
@ FlagDontLoadLayouts
Don't load print layouts. Improves project read time if layouts are not required, and allows projects...
qgsreadwritecontext.h
qgslabelingenginesettings.h
QgsProject::write
bool write()
Writes the project to its current associated file (see fileName() ).
Definition: qgsproject.cpp:2069
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:51
QgsLayerTree::customLayerOrder
QList< QgsMapLayer * > customLayerOrder() const
The order in which layers will be rendered on the canvas.
Definition: qgslayertree.cpp:35
QgsCoordinateReferenceSystem::fromOgcWmsCrs
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
Definition: qgscoordinatereferencesystem.cpp:200
QgsProjectMetadata::readMetadataXml
bool readMetadataXml(const QDomElement &metadataElement) override
Sets state from DOM document.
Definition: qgsprojectmetadata.cpp:22
QgsTranslationContext::writeTsFile
void writeTsFile(const QString &locale)
Writes the Ts-file.
Definition: qgstranslationcontext.cpp:53
QgsCoordinateReferenceSystem::fromProj
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
Definition: qgscoordinatereferencesystem.cpp:226
QgsProject::cleared
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QgsProjectDisplaySettings
Contains settings and properties relating to how a QgsProject should display values such as map coord...
Definition: qgsprojectdisplaysettings.h:37
QgsProject::setEvaluateDefaultValues
void setEvaluateDefaultValues(bool evaluateDefaultValues)
Defines if default values should be evaluated on provider side when requested and not when committed.
Definition: qgsproject.cpp:2933
QgsProject::pathResolver
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
Definition: qgsproject.cpp:2674
qgssymbollayerutils.h
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:320
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
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:3187
QgsEditorWidgetSetup::config
QVariantMap config() const
Definition: qgseditorwidgetsetup.h:51
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:99
qgslayoutmanager.h
QgsProject::originalPath
QString originalPath() const
Returns the original path associated with the project.
Definition: qgsproject.cpp:656
QgsProject::removeAllMapLayers
void removeAllMapLayers()
Removes all registered layers.
Definition: qgsproject.cpp:3420
qgspathresolver.h
QgsRelationManager::clear
void clear()
Remove any relation managed by this class.
Definition: qgsrelationmanager.cpp:115
QgsProjectStorage::Metadata
Metadata associated with a project.
Definition: qgsprojectstorage.h:47
QgsProject::transformContext
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:101
QgsProject::avoidIntersectionsLayersChanged
void avoidIntersectionsLayersChanged()
Emitted whenever avoidIntersectionsLayers has changed.
QgsProject::setAvoidIntersectionsMode
void setAvoidIntersectionsMode(const AvoidIntersectionsMode mode)
Sets the avoid intersections mode.
Definition: qgsproject.cpp:1042
QgsProject::setCustomVariables
void setCustomVariables(const QVariantMap &customVariables)
A map of custom project variables.
Definition: qgsproject.cpp:1791
geoEpsgCrsAuthId
CONSTLATIN1STRING geoEpsgCrsAuthId()
Geographic coord sys from EPSG authority.
Definition: qgis.h:709
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsProject::setBadLayerHandler
void setBadLayerHandler(QgsProjectBadLayerHandler *handler)
Change handler for missing layers.
Definition: qgsproject.cpp:2720
QgsProject::readProject
void readProject(const QDomDocument &)
Emitted when a project is being read.
QgsTransactionGroup::isEmpty
bool isEmpty() const
Returns true if there are no layers in this transaction group.
Definition: qgstransactiongroup.cpp:191
QgsStyleEntityVisitorInterface
An interface for classes which can visit style entity (e.g.
Definition: qgsstyleentityvisitor.h:34
QgsProject::dataDefinedServerProperties
QgsPropertyCollection dataDefinedServerProperties() const
Returns the data defined properties used for overrides in user defined server parameters.
Definition: qgsproject.cpp:621
qgsunittypes.h
QgsVectorLayer::auxiliaryLayer
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
Definition: qgsvectorlayer.cpp:5293
Qgis::Success
@ Success
Definition: qgis.h:93
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::auxiliaryStorage
const QgsAuxiliaryStorage * auxiliaryStorage() const
Returns the current const auxiliary storage.
Definition: qgsproject.cpp:3527
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsAbstractMetadataBase::title
QString title() const
Returns the human readable name of the resource, typically displayed in search results.
Definition: qgsabstractmetadatabase.cpp:51
QgsProjectViewSettings::setUseProjectScales
void setUseProjectScales(bool enabled)
Sets whether project mapScales() are enabled.
Definition: qgsprojectviewsettings.cpp:66
QgsMapLayer::isValid
bool isValid
Definition: qgsmaplayer.h:91
QgsLayerTree::toLayer
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
QgsApplication::instance
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
Definition: qgsapplication.cpp:411
QgsApplication::projectStorageRegistry
static QgsProjectStorageRegistry * projectStorageRegistry()
Returns registry of available project storage implementations.
Definition: qgsapplication.cpp:2298
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:2526
QgsProject::createEmbeddedLayer
bool createEmbeddedLayer(const QString &layerId, const QString &projectFilePath, QList< QDomNode > &brokenNodes, bool saveFlag=true, QgsProject::ReadFlags flags=QgsProject::ReadFlags())
Creates a maplayer instance defined in an arbitrary project file.
Definition: qgsproject.cpp:2736
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
field
const QgsField & field
Definition: qgsfield.h:456
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsProject::setEllipsoid
void setEllipsoid(const QString &ellipsoid)
Sets the project's ellipsoid from a proj string representation, e.g., "WGS84".
Definition: qgsproject.cpp:749
QgsUnitTypes::DistanceUnit
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
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:3208
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:2601
QgsAttributeEditorContainer::children
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
Definition: qgsattributeeditorelement.h:218
qgsmaplayerstore.h
QgsProject::areaUnits
QgsUnitTypes::AreaUnit areaUnits() const
Convenience function to query default area measurement units for project.
Definition: qgsproject.cpp:2981
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:2018
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:3385
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:57
QgsProject::error
QString error() const
Returns error message from previous read/write.
Definition: qgsproject.cpp:2710
QgsField::name
QString name
Definition: qgsfield.h:59
QgsAnnotationLayer::LayerOptions
Setting options for loading annotation layers.
Definition: qgsannotationlayer.h:50
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::saveUser
QString saveUser() const
Returns the user name that did the last save.
Definition: qgsproject.cpp:494
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:671
QgsAuxiliaryStorage::extension
static QString extension()
Returns the extension used for auxiliary databases.
Definition: qgsauxiliarystorage.cpp:677
QgsLayerTree::toGroup
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
QgsProjectStorage
Abstract interface for project storage - to be implemented by various backends and registered in QgsP...
Definition: qgsprojectstorage.h:38
QgsProject
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:95
QgsProject::setLabelingEngineSettings
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets project's global labeling engine settings.
Definition: qgsproject.cpp:1816
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:62
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:1617
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:726
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.
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:62
qgsauxiliarystorage.h
QgsLayerTreeGroup::findGroups
QList< QgsLayerTreeGroup * > findGroups() const
Find all group layer nodes.
Definition: qgslayertreegroup.cpp:256
qgsapplication.h
QgsBookmarkManager::clear
void clear()
Removes and deletes all bookmarks from the manager.
Definition: qgsbookmarkmanager.cpp:225
QgsProject::labelingEngineSettings
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns project's global labeling engine settings.
Definition: qgsproject.cpp:1822
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:411
QgsProject::~QgsProject
~QgsProject() override
Definition: qgsproject.cpp:447
QgsProject::registerTranslatableObjects
void registerTranslatableObjects(QgsTranslationContext *translationContext)
Registers the objects that require translation into the translationContext.
Definition: qgsproject.cpp:563
QgsMapLayer::dataSourceChanged
void dataSourceChanged()
Emitted whenever the layer's data source has been changed.
QgsProject::setProjectColors
void setProjectColors(const QgsNamedColorList &colors)
Sets the colors for the project's color scheme (see QgsProjectColorScheme).
Definition: qgsproject.cpp:3585
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:685
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3283
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:797
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:3336
QgsProject::writeMapLayer
void writeMapLayer(QgsMapLayer *mapLayer, QDomElement &layerElem, QDomDocument &doc)
Emitted when a layer is being saved.
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:36
QgsUnitTypes::AreaSquareMeters
@ AreaSquareMeters
Square meters.
Definition: qgsunittypes.h:95
QgsEditorWidgetSetup::type
QString type() const
Definition: qgseditorwidgetsetup.h:46
QgsMapLayer::FlagDontResolveLayers
@ FlagDontResolveLayers
Don't resolve layer paths or create data providers for layers.
Definition: qgsmaplayer.h:556
QgsStyleEntityVisitorInterface::NodeType::Layer
@ Layer
Map layer.
QgsProjectDisplaySettings::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
Definition: qgsprojectdisplaysettings.cpp:53
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:192
QgsSnappingConfig::writeProject
void writeProject(QDomDocument &doc)
Writes the configuration to the specified QGIS project document.
Definition: qgssnappingconfig.cpp:518
QgsProject::layerTreeRoot
QgsLayerTree * layerTreeRoot() const
Returns pointer to the root (invisible) node of the project's layer tree.
Definition: qgsproject.cpp:3100
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:222
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
qgsprojectfiletransform.h
QgsAttributeEditorElement::AeTypeContainer
@ AeTypeContainer
A container.
Definition: qgsattributeeditorelement.h:64
QgsDataProvider::EvaluateDefaultValues
@ EvaluateDefaultValues
Evaluate default values on provider side when calling QgsVectorDataProvider::defaultValue( int index ...
Definition: qgsdataprovider.h:92
QgsProject::setPresetHomePath
void setPresetHomePath(const QString &path)
Sets the project's home path.
Definition: qgsproject.cpp:531
QgsLayerTree
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:33
QgsProjectDisplaySettings::reset
void reset()
Resets the settings to a default state.
Definition: qgsprojectdisplaysettings.cpp:34
QgsSnappingConfig::removeLayers
bool removeLayers(const QList< QgsMapLayer * > &layers)
Removes the specified layers from the individual layer configuration.
Definition: qgssnappingconfig.cpp:574
getDataDefinedServerProperties
QgsPropertyCollection getDataDefinedServerProperties(const QDomDocument &doc, const QgsPropertiesDefinition &dataDefinedServerPropertyDefinitions)
Returns the data defined server properties collection found in "doc" to "dataDefinedServerProperties"...
Definition: qgsproject.cpp:937
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:3555
QgsCoordinateReferenceSystem::fromSrsId
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
Definition: qgscoordinatereferencesystem.cpp:240
QgsCoordinateTransformContext::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context, QStringList &missingTransforms)
Reads the context's state from a DOM element.
Definition: qgscoordinatetransformcontext.cpp:269
QgsProject::removeMapLayer
void removeMapLayer(const QString &layerId)
Remove a layer from the registry by layer ID.
Definition: qgsproject.cpp:3397
QgsProject::topologicalEditing
bool topologicalEditing
Definition: qgsproject.h:111
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
QgsProject::AvoidIntersectionsMode
AvoidIntersectionsMode
Flags which control how intersections of pre-existing feature are handled when digitizing new feature...
Definition: qgsproject.h:143
QgsProject::nonIdentifiableLayersChanged
Q_DECL_DEPRECATED void nonIdentifiableLayersChanged(QStringList nonIdentifiableLayers)
Emitted when the list of layer which are excluded from map identification changes.
QgsProject::setAvoidIntersectionsLayers
void setAvoidIntersectionsLayers(const QList< QgsVectorLayer * > &layers)
Sets the list of layers with which intersections should be avoided.
Definition: qgsproject.cpp:1851
QgsProject::setMapScales
Q_DECL_DEPRECATED void setMapScales(const QVector< double > &scales)
Sets the list of custom project map scales.
Definition: qgsproject.cpp:3633
QgsProject::reloadAllLayers
void reloadAllLayers()
Reload all registered layer's provider data caches, synchronising the layer with any changes in the d...
Definition: qgsproject.cpp:3426
QgsRelationManager::relations
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
Definition: qgsrelationmanager.cpp:55
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:2123
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:715
QgsLabelingEngineSettings
Stores global configuration for labeling engine.
Definition: qgslabelingenginesettings.h:31
findKey_
QgsProjectProperty * findKey_(const QString &scope, const QString &key, QgsProjectPropertyKey &rootProperty)
return the property that matches the given key sequence, if any
Definition: qgsproject.cpp:141
QgsTransaction::supportsTransaction
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if the provider of a given layer supports transactions.
Definition: qgstransaction.cpp:189
dump_
void dump_(const QgsProjectPropertyKey &topQgsPropertyKey)
Definition: qgsproject.cpp:871
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:3680
QgsUnitTypes::toString
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
Definition: qgsunittypes.cpp:199
QgsProjectArchive::projectFile
QString projectFile() const
Returns the current .qgs project file or an empty string if there's none.
Definition: qgsarchive.cpp:129
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:462
addKey_
QgsProjectProperty * addKey_(const QString &scope, const QString &key, QgsProjectPropertyKey *rootProperty, const QVariant &value, bool &propertiesModified)
Add the given key and value.
Definition: qgsproject.cpp:218
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:44
QgsProject::useProjectScales
Q_DECL_DEPRECATED bool useProjectScales() const
Returns true if project mapScales() are enabled.
Definition: qgsproject.cpp:3648
QgsCoordinateReferenceSystem::authid
QString authid() const
Returns the authority identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1321
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)
Restore any optional properties found in "doc" to "properties".
Definition: qgsproject.cpp:908
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:28
QgsProject::readPath
QString readPath(const QString &filename) const
Transforms a filename read from the project file to an absolute path.
Definition: qgsproject.cpp:2695
QgsLayerTreeGroup
Layer tree group node serves as a container for layers and further groups.
Definition: qgslayertreegroup.h:35
qgsvectordataprovider.h
QgsProjectMetadata::setAuthor
void setAuthor(const QString &author)
Sets the project author string.
Definition: qgsprojectmetadata.cpp:75
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:1954
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:924
QgsAnnotationManager
Manages storage of a set of QgsAnnotation annotation objects.
Definition: qgsannotationmanager.h:45
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:1846
QgsLayerTreeGroup::insertChildNodes
void insertChildNodes(int index, const QList< QgsLayerTreeNode * > &nodes)
Insert existing nodes at specified position.
Definition: qgslayertreegroup.cpp:99
QgsProject::fileInfo
Q_DECL_DEPRECATED QFileInfo fileInfo() const
Returns QFileInfo object for the project's associated file.
Definition: qgsproject.cpp:661
QgsApplication::profiler
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
Definition: qgsapplication.cpp:482
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:3218
QgsUnitTypes::DistanceMeters
@ DistanceMeters
Meters.
Definition: qgsunittypes.h:69
QgsPropertyDefinition
Definition for a property.
Definition: qgsproperty.h:48
QgsProject::ReadFlag::FlagDontResolveLayers
@ FlagDontResolveLayers
Don't resolve layer paths (i.e. don't load any layer content). Dramatically improves project read tim...
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:3570
QgsProject::setTopologicalEditing
void setTopologicalEditing(bool enabled)
Convenience function to set topological editing.
Definition: qgsproject.cpp:2952
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:148
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:94
QgsSnappingConfig
This is a container for configuration of the snapping of the project.
Definition: qgssnappingconfig.h:34
QgsProject::setDirty
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:519
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:3090
QgsTranslationContext
Used for the collecting of strings from projects for translation and creation of ts files.
Definition: qgstranslationcontext.h:36
QgsRuntimeProfiler::clear
void clear(const QString &group="startup")
clear Clear all profile data.
Definition: qgsruntimeprofiler.cpp:273
QgsProject::layerStore
QgsMapLayerStore * layerStore()
Returns a pointer to the project's internal layer store.
Definition: qgsproject.cpp:1827
QgsWeakMapLayerPointer
QPointer< QgsMapLayer > QgsWeakMapLayerPointer
Weak pointer for QgsMapLayer.
Definition: qgsmaplayer.h:1688
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:2579
QgsProject::AvoidIntersectionsMode::AvoidIntersectionsLayers
@ AvoidIntersectionsLayers
Overlap with features from a specified list of layers when digitizing new features not allowed.
typeName
const QString & typeName
Definition: qgswfsgetfeature.cpp:55
QgsProject::mapThemeCollection
QgsMapThemeCollection * mapThemeCollection
Definition: qgsproject.h:103
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:111
QgsProject::setSnappingConfig
void setSnappingConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration for this project.
Definition: qgsproject.cpp:1032
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:98
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:1868
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:29
QgsCoordinateReferenceSystem::toProj
QString toProj() const
Returns a Proj string representation of this CRS.
Definition: qgscoordinatereferencesystem.cpp:1420
QgsExpressionNodeFunction
An expression node for expression functions.
Definition: qgsexpressionnodeimpl.h:317
QgsProject::transformContextChanged
void transformContextChanged()
Emitted when the project transformContext() is changed.
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:277
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:780
QgsProject::setOriginalPath
void setOriginalPath(const QString &path)
Sets the original path associated with the project.
Definition: qgsproject.cpp:651
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:206
QgsProject::setTitle
void setTitle(const QString &title)
Sets the project's title.
Definition: qgsproject.cpp:477
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:3080
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext.
Definition: qgsexpressioncontext.h:112
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:696
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:616
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:160
QgsProjectViewSettings::reset
void reset()
Resets the settings to a default state.
Definition: qgsprojectviewsettings.cpp:26
qgslayerdefinition.h
QgsProjectTimeSettings
Contains temporal settings and properties for the project, this may be used when animating maps or sh...
Definition: qgsprojecttimesettings.h:37
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:389
QgsProjectMetadata::writeMetadataXml
bool writeMetadataXml(QDomElement &metadataElement, QDomDocument &document) const override
Stores state in a DOM node.
Definition: qgsprojectmetadata.cpp:39
QgsProject::bookmarkManager
const QgsBookmarkManager * bookmarkManager() const
Returns the project's bookmark manager, which manages bookmarks within the project.
Definition: qgsproject.cpp:3060
QgsProject::setTrustLayerMetadata
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:3469
QgsPropertyCollection
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition: qgspropertycollection.h:319
qgstransaction.h
QgsLayerTree::isLayer
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
QgsPathResolver::readPath
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Definition: qgspathresolver.cpp:35
QgsMapLayer::source
QString source() const
Returns the source for the layer.
Definition: qgsmaplayer.cpp:192
QgsProjectFileTransform
Definition: qgsprojectfiletransform.h:42
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:1097
getVersion
QgsProjectVersion getVersion(const QDomDocument &doc)
Returns the version string found in the given DOM document.
Definition: qgsproject.cpp:1009
QgsMapLayer::Identifiable
@ Identifiable
If the layer is identifiable using the identify map tool and as a WMS layer.
Definition: qgsmaplayer.h:148
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:3120
QgsProjectPropertyKey
Project property key node.
Definition: qgsprojectproperty.h:184
QgsLayerTreeGroup::findLayerIds
QStringList findLayerIds() const
Find layer IDs used in all layer nodes.
Definition: qgslayertreegroup.cpp:397
QgsProject::lastSaveDateTime
QDateTime lastSaveDateTime() const
Returns the date and time when the project was last saved.
Definition: qgsproject.cpp:504
QgsProject::read
bool read(const QString &filename, QgsProject::ReadFlags flags=QgsProject::ReadFlags())
Reads given project file from the given file.
Definition: qgsproject.cpp:1216
QgsProject::saveUserFullName
QString saveUserFullName() const
Returns the full user name that did the last save.
Definition: qgsproject.cpp:499
QgsCoordinateTransformContext::writeXml
void writeXml(QDomElement &element, const QgsReadWriteContext &context) const
Writes the context's state to a DOM element.
Definition: qgscoordinatetransformcontext.cpp:371
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:707
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:553
QgsLayerTree::clone
QgsLayerTree * clone() const override
Create a copy of the node. Returns new instance.
Definition: qgslayertree.cpp:155
QgsProjectViewSettings::mapScales
QVector< double > mapScales() const
Returns the list of custom project map scales.
Definition: qgsprojectviewsettings.cpp:61
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:2726
QgsLayerTreeUtils::storeOriginalLayersProperties
static void storeOriginalLayersProperties(QgsLayerTreeGroup *group, const QDomDocument *doc)
Stores in a layer's originalXmlProperties the layer properties information.
Definition: qgslayertreeutils.cpp:315
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:180
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:3446
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsProject::presetHomePath
QString presetHomePath() const
Returns any manual project home path setting, or an empty string if not set.
Definition: qgsproject.cpp:3040
QgsProject::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgsproject.cpp:2700
QgsProject::validCount
int validCount() const
Returns the number of registered valid layers.
Definition: qgsproject.cpp:3203
QgsVectorLayer::editFormConfig
QgsEditFormConfig editFormConfig
Definition: qgsvectorlayer.h:393
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:189
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
QgsAttributeEditorContainer
This is a container for attribute editors, used to group them visually in the attribute form if it is...
Definition: qgsattributeeditorelement.h:172
QgsMapLayer::readLayerXml
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags())
Sets state from DOM document.
Definition: qgsmaplayer.cpp:218
QgsAnnotationLayer
Represents a map layer containing a set of georeferenced annotations, e.g.
Definition: qgsannotationlayer.h:40
QgsProject::snappingConfig
QgsSnappingConfig snappingConfig
Definition: qgsproject.h:104
QgsProjectPropertyKey::isEmpty
bool isEmpty() const
Returns true if this property contains no sub-keys.
Definition: qgsprojectproperty.h:277
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:3409
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:3653
QgsAnnotationLayer::reset
void reset()
Resets the annotation layer to a default state, and clears all items from it.
Definition: qgsannotationlayer.cpp:39
QgsScopedRuntimeProfile
Scoped object for logging of the runtime for a single operation or group of operations.
Definition: qgsruntimeprofiler.h:328
QgsProject::QgsProject
QgsProject(QObject *parent=nullptr)
Create a new QgsProject.
Definition: qgsproject.cpp:365
QgsProjectViewSettings::setMapScales
void setMapScales(const QVector< double > &scales)
Sets the list of custom project map scales.
Definition: qgsprojectviewsettings.cpp:47
qgssettings.h
QgsLayerTreeNode::children
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
Definition: qgslayertreenode.h:112
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
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:514
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
QgsVectorLayer::dataProvider
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
Definition: qgsvectorlayer.cpp:627
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:1871
QgsDataProvider::setProviderProperty
void setProviderProperty(ProviderProperty property, const QVariant &value)
Allows setting arbitrary properties on the provider.
Definition: qgsdataprovider.cpp:46
QgsRelationManager::updateRelationsStatus
void updateRelationsStatus()
Updates relations status.
Definition: qgsrelationmanager.cpp:75
qgspluginlayer.h
QgsLayerTreeGroup::name
QString name() const override
Returns the group's name.
Definition: qgslayertreegroup.cpp:43
QgsProjectViewSettings::readXml
bool readXml(const QDomElement &element, const QgsReadWriteContext &context)
Reads the settings's state from a DOM element.
Definition: qgsprojectviewsettings.cpp:80
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:3542
QgsRelation
Definition: qgsrelation.h:42
QgsAuxiliaryStorage
Class providing some utility methods to manage auxiliary storage.
Definition: qgsauxiliarystorage.h:260
QgsProject::setAreaUnits
void setAreaUnits(QgsUnitTypes::AreaUnit unit)
Sets the default area measurement units for the project.
Definition: qgsproject.cpp:2994
qgslayertreeutils.h
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:410
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:84
QgsLayerTree::readLayerOrderFromXml
void readLayerOrderFromXml(const QDomElement &doc)
Load the layer order from an XML element.
Definition: qgslayertree.cpp:251
Qgis::Critical
@ Critical
Definition: qgis.h:92
QgsProject::isDirtyChanged
void isDirtyChanged(bool dirty)
Emitted when the project dirty status changes.
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:1861
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:149
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:3441
QgsProject::dumpProperties
void dumpProperties() const
Dump out current project properties to stderr.
Definition: qgsproject.cpp:2669
QgsProject::nonIdentifiableLayers
QStringList nonIdentifiableLayers
Definition: qgsproject.h:97
qgsbookmarkmanager.h
QgsCoordinateReferenceSystem::ellipsoidAcronym
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
Definition: qgscoordinatereferencesystem.cpp:1373
QgsProjectArchive
Class allowing to manage the zip/unzip actions on project file.
Definition: qgsarchive.h:116
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:2652
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:93
QgsAuxiliaryLayer::auxiliaryFields
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
Definition: qgsauxiliarystorage.cpp:192
QgsProject::evaluateDefaultValues
bool evaluateDefaultValues() const
Should default values be evaluated on provider side when requested and not when committed.
Definition: qgsproject.cpp:2928
QgsMapThemeCollection
Container class that allows storage of map themes consisting of visible map layers and layer styles.
Definition: qgsmapthemecollection.h:45
QgsProject::oldProjectVersionWarning
void oldProjectVersionWarning(const QString &)
Emitted when an old project file is read.
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:509
QgsProject::setDistanceUnits
void setDistanceUnits(QgsUnitTypes::DistanceUnit unit)
Sets the default distance measurement units for the project.
Definition: qgsproject.cpp:2976
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:3050
qgsmaplayerlistutils.h
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:2496
qgslogger.h
QgsProject::autoTransaction
bool autoTransaction() const
Transactional editing means that on supported datasources (postgres databases) the edit state of all ...
Definition: qgsproject.cpp:3169
QgsLayerTreeGroup::clone
QgsLayerTreeGroup * clone() const override
Returns a clone of the group.
Definition: qgslayertreegroup.cpp:347
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
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:119
QgsProject::count
int count() const
Returns the number of registered layers.
Definition: qgsproject.cpp:3198
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:559
qgsprojectversion.h
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsProject::readLayer
bool readLayer(const QDomNode &layerNode)
Reads the layer described in the associated DOM node.
Definition: qgsproject.cpp:2038
QgsAnnotationLayer::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context) override
Sets the coordinate transform context to transformContext.
Definition: qgsannotationlayer.cpp:126
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:194
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:545
QgsLayerTreeGroup::findGroup
QgsLayerTreeGroup * findGroup(const QString &name)
Find group node with specified name.
Definition: qgslayertreegroup.cpp:236
QgsApplication::pluginLayerRegistry
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
Definition: qgsapplication.cpp:2228
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:796
qgsprojectdisplaysettings.h
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:3070
QgsScopedExpressionFunction
Expression function for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:38
QgsLayerTree::isGroup
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
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:102
QgsLayerTreeRegistryBridge
Listens to the updates in map layer registry and does changes in layer tree.
Definition: qgslayertreeregistrybridge.h:45
QgsProject::crs
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:100
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.
Definition: qgspathresolver.h:32
QgsProjectProperty
An Abstract Base Class for QGIS project property hierarchys.
Definition: qgsprojectproperty.h:51
QgsProject::setUseProjectScales
Q_DECL_DEPRECATED void setUseProjectScales(bool enabled)
Sets whether project mapScales() are enabled.
Definition: qgsproject.cpp:3643
QgsProject::mainAnnotationLayer
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
Definition: qgsproject.cpp:3415
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:3664
QgsProject::setTransformContext
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the project's coordinate transform context, which stores various information regarding which dat...
Definition: qgsproject.cpp:764
qgsproject.h
QgsProject::mapScalesChanged
Q_DECL_DEPRECATED void mapScalesChanged()
Emitted when the list of custom project map scales changes.
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:3331
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:2552
QgsProject::backgroundColor
QColor backgroundColor
Definition: qgsproject.h:109
QgsTransactionGroup::addLayer
bool addLayer(QgsVectorLayer *layer)
Add a layer to this transaction group.
Definition: qgstransactiongroup.cpp:32
QgsProject::ReadFlag::FlagTrustLayerMetadata
@ FlagTrustLayerMetadata
Trust layer metadata. Improves project read time. Do not use it if layers' extent is not fixed during...
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:5236
QgsProject::removeEntry
bool removeEntry(const QString &scope, const QString &key)
Remove the given key from the specified scope.
Definition: qgsproject.cpp:2623
QgsProject::loadingLayerMessageReceived
void loadingLayerMessageReceived(const QString &layerName, const QList< QgsReadWriteContext::ReadWriteMessage > &messages)
Emitted when loading layers has produced some messages.
QgsProject::setSelectionColor
void setSelectionColor(const QColor &color)
Sets the color used to highlight selected features.
Definition: qgsproject.cpp:3619
QgsProjectMetadata::setCreationDateTime
void setCreationDateTime(const QDateTime &creationDateTime)
Sets the project's creation date/timestamp.
Definition: qgsprojectmetadata.cpp:85
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
QgsApplication::userFullName
static QString userFullName()
Returns the user's operating system login account full display name.
Definition: qgsapplication.cpp:1132
QgsProject::topologicalEditingChanged
void topologicalEditingChanged()
Emitted when the topological editing flag has changed.
qgsmessagelog.h
QgsProject::createEmbeddedGroup
QgsLayerTreeGroup * createEmbeddedGroup(const QString &groupName, const QString &projectFilePath, const QStringList &invisibleLayers, QgsProject::ReadFlags flags=QgsProject::ReadFlags())
Create layer group instance defined in an arbitrary project file.
Definition: qgsproject.cpp:2831
QgsField::alias
QString alias
Definition: qgsfield.h:60
QgsProject::addMapLayer
QgsMapLayer * addMapLayer(QgsMapLayer *mapLayer, bool addToLegend=true, bool takeOwnership=true)
Add a layer to the map of loaded layers.
Definition: qgsproject.cpp:3376
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:75
QgsMapLayer::type
QgsMapLayerType type
Definition: qgsmaplayer.h:90