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