QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
qgslayerdefinition.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayerdefinition.cpp
3 ---------------------
4 begin : January 2015
5 copyright : (C) 2015 by Nathan Woodrow
6 email : woodrow dot nathan at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15#include "qgslayerdefinition.h"
16
17#include "qgsapplication.h"
18#include "qgsfileutils.h"
19#include "qgsgrouplayer.h"
20#include "qgslayertreegroup.h"
21#include "qgslayertreelayer.h"
22#include "qgslogger.h"
23#include "qgsmaplayer.h"
24#include "qgsmaplayerfactory.h"
25#include "qgsmeshlayer.h"
26#include "qgspathresolver.h"
27#include "qgspluginlayer.h"
29#include "qgspointcloudlayer.h"
30#include "qgsproject.h"
31#include "qgsrasterlayer.h"
32#include "qgsreadwritecontext.h"
33#include "qgstiledscenelayer.h"
34#include "qgsvectorlayer.h"
35#include "qgsvectortilelayer.h"
36
37#include <QDir>
38#include <QFile>
39#include <QFileInfo>
40#include <QString>
41#include <QTextStream>
42
43using namespace Qt::StringLiterals;
44
45bool QgsLayerDefinition::loadLayerDefinition( const QString &path, QgsProject *project, QgsLayerTreeGroup *rootGroup, QString &errorMessage, Qgis::LayerTreeInsertionMethod insertMethod, const QgsLayerTreeRegistryBridge::InsertionPoint *insertPoint )
46{
47 QFile file( path );
48 if ( !file.open( QIODevice::ReadOnly ) )
49 {
50 errorMessage = u"Can not open file"_s;
51 return false;
52 }
53
54 QDomDocument doc;
55 QString message;
56 if ( !doc.setContent( &file, &message ) )
57 {
58 errorMessage = message;
59 return false;
60 }
61
62 const QFileInfo fileinfo( file );
63 QDir::setCurrent( fileinfo.absoluteDir().path() );
64
65 QgsReadWriteContext context;
66 context.setPathResolver( QgsPathResolver( path ) );
67 context.setProjectTranslator( project );
68
69 return loadLayerDefinition( doc, project, rootGroup, errorMessage, context, insertMethod, insertPoint );
70}
71
72bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsProject *project, QgsLayerTreeGroup *rootGroup, QString &errorMessage, QgsReadWriteContext &context, Qgis::LayerTreeInsertionMethod insertMethod, const QgsLayerTreeRegistryBridge::InsertionPoint *insertPoint )
73{
74 errorMessage.clear();
75
77
78 // reorder maplayer nodes based on dependencies
79 // dependencies have to be resolved before IDs get changed
80 const DependencySorter depSorter( doc );
81 if ( !depSorter.hasMissingDependency() )
82 {
83 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
84 QVector<QDomNode> clonedSorted;
85 const auto constSortedLayerNodes = sortedLayerNodes;
86 for ( const QDomNode &node : constSortedLayerNodes )
87 {
88 clonedSorted << node.cloneNode();
89 }
90 QDomNode layersNode = doc.elementsByTagName( u"maplayers"_s ).at( 0 );
91 // replace old children with new ones
92 QDomNode childNode = layersNode.firstChild();
93 for ( int i = 0; ! childNode.isNull(); i++ )
94 {
95 layersNode.replaceChild( clonedSorted.at( i ), childNode );
96 childNode = childNode.nextSibling();
97 }
98 }
99 // if a dependency is missing, we still try to load layers, since dependencies may already be loaded
100
101 // IDs of layers should be changed otherwise we may have more then one layer with the same id
102 // We have to replace the IDs before we load them because it's too late once they are loaded
103 const QDomNodeList treeLayerNodes = doc.elementsByTagName( u"layer-tree-layer"_s );
104 for ( int i = 0; i < treeLayerNodes.length(); ++i )
105 {
106 const QDomNode treeLayerNode = treeLayerNodes.item( i );
107 QDomElement treeLayerElem = treeLayerNode.toElement();
108 const QString oldid = treeLayerElem.attribute( u"id"_s );
109 const QString layername = treeLayerElem.attribute( u"name"_s );
110 const QString newid = QgsMapLayer::generateId( layername );
111 treeLayerElem.setAttribute( u"id"_s, newid );
112
113 // Replace IDs for map layers
114 const QDomNodeList ids = doc.elementsByTagName( u"id"_s );
115 QDomNode idnode = ids.at( 0 );
116 for ( int j = 0; ! idnode.isNull() ; ++j )
117 {
118 idnode = ids.at( j );
119 const QDomElement idElem = idnode.toElement();
120 if ( idElem.text() == oldid )
121 {
122 idElem.firstChild().setNodeValue( newid );
123 }
124 }
125
126 // change layer IDs for vector joins
127 const QDomNodeList vectorJoinNodes = doc.elementsByTagName( u"join"_s ); // TODO: Find a better way of searching for vectorjoins, there might be other <join> elements within the project.
128 for ( int j = 0; j < vectorJoinNodes.size(); ++j )
129 {
130 const QDomNode joinNode = vectorJoinNodes.at( j );
131 const QDomElement joinElement = joinNode.toElement();
132 if ( joinElement.attribute( u"joinLayerId"_s ) == oldid )
133 {
134 joinNode.toElement().setAttribute( u"joinLayerId"_s, newid );
135 }
136 }
137
138 // change IDs of dependencies
139 const QDomNodeList dataDeps = doc.elementsByTagName( u"dataDependencies"_s );
140 for ( int i = 0; i < dataDeps.size(); i++ )
141 {
142 const QDomNodeList layers = dataDeps.at( i ).childNodes();
143 for ( int j = 0; j < layers.size(); j++ )
144 {
145 QDomElement elt = layers.at( j ).toElement();
146 if ( elt.attribute( u"id"_s ) == oldid )
147 {
148 elt.setAttribute( u"id"_s, newid );
149 }
150 }
151 }
152
153 // Change IDs of widget config values
154 const QDomNodeList widgetConfig = doc.elementsByTagName( u"editWidget"_s );
155 for ( int i = 0; i < widgetConfig.size(); i++ )
156 {
157 const QDomNodeList config = widgetConfig.at( i ).childNodes();
158 for ( int j = 0; j < config.size(); j++ )
159 {
160 const QDomNodeList optMap = config.at( j ).childNodes();
161 for ( int z = 0; z < optMap.size(); z++ )
162 {
163 const QDomNodeList opts = optMap.at( z ).childNodes();
164 for ( int k = 0; k < opts.size(); k++ )
165 {
166 QDomElement opt = opts.at( k ).toElement();
167 if ( opt.attribute( u"value"_s ) == oldid )
168 {
169 opt.setAttribute( u"value"_s, newid );
170 }
171 }
172 }
173 }
174 }
175 }
176
177 QDomElement layerTreeElem = doc.documentElement().firstChildElement( u"layer-tree-group"_s );
178 bool loadInLegend = true;
179 if ( !layerTreeElem.isNull() )
180 {
181 root.readChildrenFromXml( layerTreeElem, context );
182 loadInLegend = false;
183 }
184
185 const QList<QgsMapLayer *> layers = QgsLayerDefinition::loadLayerDefinitionLayersInternal( doc, context, errorMessage );
186
187 project->addMapLayers( layers, loadInLegend );
188
189 // Now that all layers are loaded, refresh the vectorjoins to get the joined fields
190 const auto constLayers = layers;
191 for ( QgsMapLayer *layer : constLayers )
192 {
193 layer->resolveReferences( project );
194 }
195
196 root.resolveReferences( project );
197
198 const QList<QgsLayerTreeNode *> nodes = root.children();
199 root.abandonChildren();
200
201 switch ( insertMethod )
202 {
204 if ( insertPoint )
205 {
206 insertPoint->group->insertChildNodes( insertPoint->position, nodes );
207 }
208 else
209 {
210 rootGroup->insertChildNodes( -1, nodes );
211 }
212 break;
214 rootGroup->insertChildNodes( 0, nodes );
215 break;
216 default: //Keep current behavior for Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup
217 rootGroup->insertChildNodes( -1, nodes );
218 }
219
220 return true;
221}
222
223bool QgsLayerDefinition::exportLayerDefinition( const QString &path, const QList<QgsLayerTreeNode *> &selectedTreeNodes, QString &errorMessage )
224{
225 return exportLayerDefinition( path, selectedTreeNodes, QgsProject::instance()->filePathStorage(), errorMessage ); // skip-keyword-check
226}
227
228bool QgsLayerDefinition::exportLayerDefinition( const QString &p, const QList<QgsLayerTreeNode *> &selectedTreeNodes, Qgis::FilePathType pathType, QString &errorMessage )
229{
230 const QString path = QgsFileUtils::ensureFileNameHasExtension( p, { u"qlr"_s} );
231
232 QFile file( path );
233 if ( !file.open( QFile::WriteOnly | QFile::Truncate ) )
234 {
235 errorMessage = file.errorString();
236 return false;
237 }
238
239 QgsReadWriteContext context;
240 switch ( pathType )
241 {
243 context.setPathResolver( QgsPathResolver( QString() ) );
244 break;
246 context.setPathResolver( QgsPathResolver( path ) );
247 break;
248 }
249
250 const QDomDocument doc( u"qgis-layer-definition"_s );
251 if ( !exportLayerDefinition( doc, selectedTreeNodes, errorMessage, context ) )
252 return false;
253
254 QTextStream qlayerstream( &file );
255 doc.save( qlayerstream, 2 );
256 return true;
257}
258
259bool QgsLayerDefinition::exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode *> &selectedTreeNodes, QString &errorMessage, const QgsReadWriteContext &context )
260{
261 Q_UNUSED( errorMessage )
262 QDomElement qgiselm = doc.createElement( u"qlr"_s );
263 doc.appendChild( qgiselm );
265 for ( QgsLayerTreeNode *node : selectedTreeNodes )
266 {
267 QgsLayerTreeNode *newnode = node->clone();
268 root.addChildNode( newnode );
269 }
270 root.writeXml( qgiselm, context );
271
272 QDomElement layerselm = doc.createElement( u"maplayers"_s );
273 const QList<QgsLayerTreeLayer *> layers = root.findLayers();
274 for ( QgsLayerTreeLayer *layer : layers )
275 {
276 if ( ! layer->layer() )
277 {
278 QgsDebugMsgLevel( u"Not a valid map layer: skipping %1"_s.arg( layer->name( ) ), 4 );
279 continue;
280 }
281 QDomElement layerelm = doc.createElement( u"maplayer"_s );
282 layer->layer()->writeLayerXml( layerelm, doc, context );
283 layerselm.appendChild( layerelm );
284 }
285 qgiselm.appendChild( layerselm );
286 return true;
287}
288
289QDomDocument QgsLayerDefinition::exportLayerDefinitionLayers( const QList<QgsMapLayer *> &layers, const QgsReadWriteContext &context )
290{
291 QDomDocument doc( u"qgis-layer-definition"_s );
292 QDomElement qgiselm = doc.createElement( u"qlr"_s );
293 doc.appendChild( qgiselm );
294 QDomElement layerselm = doc.createElement( u"maplayers"_s );
295 const auto constLayers = layers;
296 for ( QgsMapLayer *layer : constLayers )
297 {
298 QDomElement layerelm = doc.createElement( u"maplayer"_s );
299 layer->writeLayerXml( layerelm, doc, context );
300 layerselm.appendChild( layerelm );
301 }
302 qgiselm.appendChild( layerselm );
303 return doc;
304}
305
306QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument &document, QgsReadWriteContext &context )
307{
308 QString errorMessage;
309 return loadLayerDefinitionLayersInternal( document, context, errorMessage );
310}
311
312QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayersInternal( QDomDocument &document, QgsReadWriteContext &context, QString &errorMessage )
313{
314 QList<QgsMapLayer *> layers;
315 QDomElement layerElem = document.documentElement().firstChildElement( u"projectlayers"_s ).firstChildElement( u"maplayer"_s );
316 // For QLR:
317 if ( layerElem.isNull() )
318 {
319 layerElem = document.documentElement().firstChildElement( u"maplayers"_s ).firstChildElement( u"maplayer"_s );
320 }
321
322 while ( ! layerElem.isNull() )
323 {
324 const QString type = layerElem.attribute( u"type"_s );
325 QgsMapLayer *layer = nullptr;
326
327 bool ok = false;
328 const Qgis::LayerType layerType = QgsMapLayerFactory::typeFromString( type, ok );
329 if ( ok )
330 {
331 switch ( layerType )
332 {
334 layer = new QgsVectorLayer();
335 break;
336
338 layer = new QgsRasterLayer();
339 break;
340
342 {
343 const QString typeName = layerElem.attribute( u"name"_s );
345 break;
346 }
347
349 layer = new QgsMeshLayer();
350 break;
351
353 layer = new QgsVectorTileLayer;
354 break;
355
357 layer = new QgsPointCloudLayer();
358 break;
359
361 layer = new QgsTiledSceneLayer;
362 break;
363
365 layer = new QgsGroupLayer( QString(), QgsGroupLayer::LayerOptions( QgsCoordinateTransformContext() ) );
366 break;
367
369 break;
370 }
371 }
372
373 if ( layer )
374 {
375 // always add the layer, even if the source is invalid -- this allows users to fix the source
376 // at a later stage and still retain all the layer properties intact
377 layer->readLayerXml( layerElem, context );
378 layers << layer;
379 }
380 else
381 {
382 errorMessage = QObject::tr( "Unsupported layer type: %1" ).arg( type );
383 }
384 layerElem = layerElem.nextSiblingElement( u"maplayer"_s );
385 }
386 return layers;
387}
388
389QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( const QString &qlrfile )
390{
391 QFile file( qlrfile );
392 if ( !file.open( QIODevice::ReadOnly ) )
393 {
394 QgsDebugError( u"Can't open file"_s );
395 return QList<QgsMapLayer *>();
396 }
397
398 QDomDocument doc;
399 if ( !doc.setContent( &file ) )
400 {
401 QgsDebugError( u"Can't set content"_s );
402 return QList<QgsMapLayer *>();
403 }
404
405 QgsReadWriteContext context;
406 context.setPathResolver( QgsPathResolver( qlrfile ) );
407 //no project translator defined here
409}
410
411void QgsLayerDefinition::DependencySorter::init( const QDomDocument &doc )
412{
413 // Determine a loading order of layers based on a graph of dependencies
414 QMap< QString, QVector< QString > > dependencies;
415 QStringList sortedLayers;
416 QList< QPair<QString, QDomNode> > layersToSort;
417 QStringList layerIds;
418
419 QDomElement layerElem = doc.documentElement().firstChildElement( u"projectlayers"_s ).firstChildElement( u"maplayer"_s );
420 // For QLR:
421 if ( layerElem.isNull() )
422 {
423 layerElem = doc.documentElement().firstChildElement( u"maplayers"_s ).firstChildElement( u"maplayer"_s );
424 }
425 // For tests (I don't know if there is a real use case for such a document except for test_qgslayerdefinition.py)
426 if ( layerElem.isNull() )
427 {
428 layerElem = doc.documentElement().firstChildElement( u"maplayer"_s );
429 }
430
431 const QDomElement &firstElement { layerElem };
432
433 QVector<QString> deps; //avoid expensive allocation for list for every iteration
434 while ( !layerElem.isNull() )
435 {
436 deps.resize( 0 ); // preserve capacity - don't use clear
437
438 const QString id = layerElem.namedItem( u"id"_s ).toElement().text();
439 layerIds << id;
440
441 // dependencies for this layer
442 const QDomElement layerDependenciesElem = layerElem.firstChildElement( u"layerDependencies"_s );
443 if ( !layerDependenciesElem.isNull() )
444 {
445 const QDomNodeList dependencyList = layerDependenciesElem.elementsByTagName( u"layer"_s );
446 for ( int j = 0; j < dependencyList.size(); ++j )
447 {
448 const QDomElement depElem = dependencyList.at( j ).toElement();
449 deps << depElem.attribute( u"id"_s );
450 }
451 }
452 dependencies[id] = deps;
453
454 if ( deps.empty() )
455 {
456 sortedLayers << id;
457 mSortedLayerNodes << layerElem;
458 mSortedLayerIds << id;
459 }
460 else
461 {
462 layersToSort << qMakePair( id, layerElem );
463 mDependentLayerIds.insert( id );
464 }
465 layerElem = layerElem.nextSiblingElement( );
466 }
467
468 // check that all dependencies are present
469 const auto constDependencies = dependencies;
470 for ( const QVector< QString > &ids : constDependencies )
471 {
472 const auto constIds = ids;
473 for ( const QString &depId : constIds )
474 {
475 if ( !dependencies.contains( depId ) )
476 {
477 // some dependencies are not satisfied
478 mHasMissingDependency = true;
479 layerElem = firstElement;
480 while ( ! layerElem.isNull() )
481 {
482 mSortedLayerNodes << layerElem;
483 layerElem = layerElem.nextSiblingElement( );
484 }
485 mSortedLayerIds = layerIds;
486 return;
487 }
488 }
489 }
490
491 // cycles should be very rare, since layers with cyclic dependencies may only be created by
492 // manually modifying the project file
493 mHasCycle = false;
494
495 while ( !layersToSort.empty() && !mHasCycle )
496 {
497 QList< QPair<QString, QDomNode> >::iterator it = layersToSort.begin();
498 while ( it != layersToSort.end() )
499 {
500 const QString idToSort = it->first;
501 const QDomNode node = it->second;
502 mHasCycle = true;
503 bool resolved = true;
504 const auto deps { dependencies.value( idToSort ) };
505 for ( const QString &dep : deps )
506 {
507 if ( !sortedLayers.contains( dep ) )
508 {
509 resolved = false;
510 break;
511 }
512 }
513 if ( resolved ) // dependencies for this layer are resolved
514 {
515 sortedLayers << idToSort;
516 mSortedLayerNodes << node;
517 mSortedLayerIds << idToSort;
518 it = layersToSort.erase( it ); // erase and go to the next
519 mHasCycle = false;
520 }
521 else
522 {
523 ++it;
524 }
525 }
526 }
527}
528
530 : mHasCycle( false )
531 , mHasMissingDependency( false )
532{
533 init( doc );
534}
535
537 : mHasCycle( false )
538 , mHasMissingDependency( false )
539{
540 QString qgsProjectFile = fileName;
541 QgsProjectArchive archive;
542 if ( fileName.endsWith( ".qgz"_L1, Qt::CaseInsensitive ) )
543 {
544 archive.unzip( fileName );
545 qgsProjectFile = archive.projectFile();
546 }
547
548 QDomDocument doc;
549 QFile pFile( qgsProjectFile );
550 ( void )pFile.open( QIODevice::ReadOnly );
551 ( void )doc.setContent( &pFile );
552 init( doc );
553}
554
556{
557 return mDependentLayerIds.contains( layerId );
558}
559
560
LayerTreeInsertionMethod
Layer tree insertion methods.
Definition qgis.h:4605
@ TopOfTree
Layers are added at the top of the layer tree.
Definition qgis.h:4607
@ AboveInsertionPoint
Layers are added in the tree above the insertion point.
Definition qgis.h:4606
FilePathType
File path types.
Definition qgis.h:1734
@ Relative
Relative path.
Definition qgis.h:1736
@ Absolute
Absolute path.
Definition qgis.h:1735
LayerType
Types of layers that can be added to a map.
Definition qgis.h:193
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:201
@ Plugin
Plugin based layer.
Definition qgis.h:196
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:202
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:199
@ Vector
Vector layer.
Definition qgis.h:194
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:198
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:197
@ Raster
Raster layer.
Definition qgis.h:195
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:200
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
Handles sorting of dependencies stored in a XML project or layer definition file.
bool hasMissingDependency() const
Whether some dependency is missing.
bool isLayerDependent(const QString &layerId) const
Returns whether the layer associated with thelayerId is dependent from another layer.
DependencySorter(const QDomDocument &doc)
Constructor.
QVector< QDomNode > sortedLayerNodes() const
Gets the layer nodes in an order where they can be loaded incrementally without dependency break.
static QDomDocument exportLayerDefinitionLayers(const QList< QgsMapLayer * > &layers, const QgsReadWriteContext &context)
Returns the given layer as a layer definition document Layer definitions store the data source as wel...
static QList< QgsMapLayer * > loadLayerDefinitionLayers(QDomDocument &document, QgsReadWriteContext &context)
Creates new layers from a layer definition document.
static bool loadLayerDefinition(const QString &path, QgsProject *project, QgsLayerTreeGroup *rootGroup, QString &errorMessage, Qgis::LayerTreeInsertionMethod insertMethod=Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup, const QgsLayerTreeRegistryBridge::InsertionPoint *insertPoint=nullptr)
Loads the QLR at path into QGIS.
static bool exportLayerDefinition(const QString &path, const QList< QgsLayerTreeNode * > &selectedTreeNodes, QString &errorMessage)
Exports the selected layer tree nodes to a QLR file.
Layer tree group node serves as a container for layers and further groups.
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Calls resolveReferences() on child tree nodes.
void readChildrenFromXml(const QDomElement &element, const QgsReadWriteContext &context)
Read children from XML and append them to the group.
void writeXml(QDomElement &parentElement, const QgsReadWriteContext &context) override
Write group (tree) as XML element <layer-tree-group> and add it to the given parent element.
void addChildNode(QgsLayerTreeNode *node)
Append an existing node.
void insertChildNodes(int index, const QList< QgsLayerTreeNode * > &nodes)
Insert existing nodes at specified position.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Layer tree node points to a map layer.
Base class for nodes in a layer tree.
QList< QgsLayerTreeNode * > abandonChildren()
Removes the children, disconnect all the forwarded and external signals and sets their parent to null...
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
virtual QgsLayerTreeNode * clone() const =0
Create a copy of the node. Returns new instance.
static Qgis::LayerType typeFromString(const QString &string, bool &ok)
Returns the map layer type corresponding a string value.
Base class for all map layer types.
Definition qgsmaplayer.h:83
static QString generateId(const QString &layerName)
Generates an unique identifier for this layer, the generate ID is prefixed by layerName.
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=QgsMapLayer::ReadFlags(), QgsDataProvider *preloadedProvider=nullptr)
Sets state from DOM document.
Resolves relative paths into absolute paths and vice versa.
QgsPluginLayer * createLayer(const QString &typeName, const QString &uri=QString())
Returns new layer if corresponding plugin has been found else returns nullptr.
Allows managing the zip/unzip actions on project files.
Definition qgsarchive.h:112
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:113
QList< QgsMapLayer * > addMapLayers(const QList< QgsMapLayer * > &mapLayers, bool addToLegend=true, bool takeOwnership=true)
Add a list of layers to the map of loaded layers.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A container for the context for various read/write operations on objects.
void setProjectTranslator(QgsProjectTranslator *projectTranslator)
Sets the project translator.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
A structure to define the insertion point to the layer tree.