QGIS API Documentation 4.3.0-Master (6402a64e93b)
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 "qgslayertreeutils.h"
23#include "qgslogger.h"
24#include "qgsmaplayer.h"
25#include "qgsmaplayerfactory.h"
26#include "qgsmeshlayer.h"
27#include "qgspathresolver.h"
28#include "qgspluginlayer.h"
30#include "qgspointcloudlayer.h"
31#include "qgsproject.h"
32#include "qgsrasterlayer.h"
33#include "qgsreadwritecontext.h"
34#include "qgstiledscenelayer.h"
35#include "qgsvectorlayer.h"
36#include "qgsvectortilelayer.h"
37
38#include <QDir>
39#include <QFile>
40#include <QFileInfo>
41#include <QString>
42#include <QTextStream>
43
44using namespace Qt::StringLiterals;
45
47 const QString &path, QgsProject *project, QgsLayerTreeGroup *rootGroup, QString &errorMessage, Qgis::LayerTreeInsertionMethod insertMethod, const QgsLayerTreeRegistryBridge::InsertionPoint *insertPoint
48)
49{
50 QFile file( path );
51 if ( !file.open( QIODevice::ReadOnly ) )
52 {
53 errorMessage = u"Can not open file"_s;
54 return false;
55 }
56
57 QDomDocument doc;
58 QString message;
59 if ( !doc.setContent( &file, &message ) )
60 {
61 errorMessage = message;
62 return false;
63 }
64
65 const QFileInfo fileinfo( file );
66 QDir::setCurrent( fileinfo.absoluteDir().path() );
67
68 QgsReadWriteContext context;
69 context.setPathResolver( QgsPathResolver( path ) );
70 context.setProjectTranslator( project );
71
72 return loadLayerDefinition( doc, project, rootGroup, errorMessage, context, insertMethod, insertPoint );
73}
74
76 QDomDocument doc,
77 QgsProject *project,
78 QgsLayerTreeGroup *rootGroup,
79 QString &errorMessage,
80 QgsReadWriteContext &context,
83)
84{
85 errorMessage.clear();
86
88
89 // reorder maplayer nodes based on dependencies
90 // dependencies have to be resolved before IDs get changed
91 const DependencySorter depSorter( doc );
92 if ( !depSorter.hasMissingDependency() )
93 {
94 const QVector<QDomNode> sortedLayerNodes = depSorter.sortedLayerNodes();
95 QVector<QDomNode> clonedSorted;
96 const auto constSortedLayerNodes = sortedLayerNodes;
97 for ( const QDomNode &node : constSortedLayerNodes )
98 {
99 clonedSorted << node.cloneNode();
100 }
101 QDomNode layersNode = doc.elementsByTagName( u"maplayers"_s ).at( 0 );
102 // replace old children with new ones
103 QDomNode childNode = layersNode.firstChild();
104 for ( int i = 0; !childNode.isNull(); i++ )
105 {
106 layersNode.replaceChild( clonedSorted.at( i ), childNode );
107 childNode = childNode.nextSibling();
108 }
109 }
110 // if a dependency is missing, we still try to load layers, since dependencies may already be loaded
111
112 // IDs of layers should be changed otherwise we may have more then one layer with the same id
113 // We have to replace the IDs before we load them because it's too late once they are loaded
114 const QDomNodeList treeLayerNodes = doc.elementsByTagName( u"layer-tree-layer"_s );
115 for ( int i = 0; i < treeLayerNodes.length(); ++i )
116 {
117 const QDomNode treeLayerNode = treeLayerNodes.item( i );
118 QDomElement treeLayerElem = treeLayerNode.toElement();
119 const QString oldid = treeLayerElem.attribute( u"id"_s );
120 const QString layername = treeLayerElem.attribute( u"name"_s );
121 const QString newid = QgsMapLayer::generateId( layername );
122 treeLayerElem.setAttribute( u"id"_s, newid );
123
124 // Replace IDs for map layers
125 const QDomNodeList ids = doc.elementsByTagName( u"id"_s );
126 QDomNode idnode = ids.at( 0 );
127 for ( int j = 0; !idnode.isNull(); ++j )
128 {
129 idnode = ids.at( j );
130 const QDomElement idElem = idnode.toElement();
131 if ( idElem.text() == oldid )
132 {
133 idElem.firstChild().setNodeValue( newid );
134 }
135 }
136
137 // change layer IDs for vector joins
138 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.
139 for ( int j = 0; j < vectorJoinNodes.size(); ++j )
140 {
141 const QDomNode joinNode = vectorJoinNodes.at( j );
142 const QDomElement joinElement = joinNode.toElement();
143 if ( joinElement.attribute( u"joinLayerId"_s ) == oldid )
144 {
145 joinNode.toElement().setAttribute( u"joinLayerId"_s, newid );
146 }
147 }
148
149 // change IDs of dependencies
150 const QDomNodeList dataDeps = doc.elementsByTagName( u"dataDependencies"_s );
151 for ( int i = 0; i < dataDeps.size(); i++ )
152 {
153 const QDomNodeList layers = dataDeps.at( i ).childNodes();
154 for ( int j = 0; j < layers.size(); j++ )
155 {
156 QDomElement elt = layers.at( j ).toElement();
157 if ( elt.attribute( u"id"_s ) == oldid )
158 {
159 elt.setAttribute( u"id"_s, newid );
160 }
161 }
162 }
163
164 // Change IDs of widget config values
165 const QDomNodeList widgetConfig = doc.elementsByTagName( u"editWidget"_s );
166 for ( int i = 0; i < widgetConfig.size(); i++ )
167 {
168 const QDomNodeList config = widgetConfig.at( i ).childNodes();
169 for ( int j = 0; j < config.size(); j++ )
170 {
171 const QDomNodeList optMap = config.at( j ).childNodes();
172 for ( int z = 0; z < optMap.size(); z++ )
173 {
174 const QDomNodeList opts = optMap.at( z ).childNodes();
175 for ( int k = 0; k < opts.size(); k++ )
176 {
177 QDomElement opt = opts.at( k ).toElement();
178 if ( opt.attribute( u"value"_s ) == oldid )
179 {
180 opt.setAttribute( u"value"_s, newid );
181 }
182 }
183 }
184 }
185 }
186 }
187
188 QDomElement layerTreeElem = doc.documentElement().firstChildElement( u"layer-tree-group"_s );
189 bool loadInLegend = true;
190 if ( !layerTreeElem.isNull() )
191 {
192 root.readChildrenFromXml( layerTreeElem, context );
193 // imported groups are new copies, so give them fresh ids like the layer ids above
194 for ( QgsLayerTreeNode *node : root.children() )
196 loadInLegend = false;
197 }
198
199 const QList<QgsMapLayer *> layers = QgsLayerDefinition::loadLayerDefinitionLayersInternal( doc, context, errorMessage );
200
201 project->addMapLayers( layers, loadInLegend );
202
203 // Now that all layers are loaded, refresh the vectorjoins to get the joined fields
204 const auto constLayers = layers;
205 for ( QgsMapLayer *layer : constLayers )
206 {
207 layer->resolveReferences( project );
208 }
209
210 root.resolveReferences( project );
211
212 const QList<QgsLayerTreeNode *> nodes = root.children();
213 root.abandonChildren();
214
215 switch ( insertMethod )
216 {
218 if ( insertPoint )
219 {
220 insertPoint->group->insertChildNodes( insertPoint->position, nodes );
221 }
222 else
223 {
224 rootGroup->insertChildNodes( -1, nodes );
225 }
226 break;
228 rootGroup->insertChildNodes( 0, nodes );
229 break;
230 default: //Keep current behavior for Qgis::LayerTreeInsertionMethod::OptimalInInsertionGroup
231 rootGroup->insertChildNodes( -1, nodes );
232 }
233
234 return true;
235}
236
237bool QgsLayerDefinition::exportLayerDefinition( const QString &path, const QList<QgsLayerTreeNode *> &selectedTreeNodes, QString &errorMessage )
238{
239 return exportLayerDefinition( path, selectedTreeNodes, QgsProject::instance()->filePathStorage(), errorMessage ); // skip-keyword-check
240}
241
242bool QgsLayerDefinition::exportLayerDefinition( const QString &p, const QList<QgsLayerTreeNode *> &selectedTreeNodes, Qgis::FilePathType pathType, QString &errorMessage )
243{
244 const QString path = QgsFileUtils::ensureFileNameHasExtension( p, { u"qlr"_s } );
245
246 QFile file( path );
247 if ( !file.open( QFile::WriteOnly | QFile::Truncate ) )
248 {
249 errorMessage = file.errorString();
250 return false;
251 }
252
253 QgsReadWriteContext context;
254 switch ( pathType )
255 {
257 context.setPathResolver( QgsPathResolver( QString() ) );
258 break;
260 context.setPathResolver( QgsPathResolver( path ) );
261 break;
262 }
263
264 const QDomDocument doc( u"qgis-layer-definition"_s );
265 if ( !exportLayerDefinition( doc, selectedTreeNodes, errorMessage, context ) )
266 return false;
267
268 QTextStream qlayerstream( &file );
269 doc.save( qlayerstream, 2 );
270 return true;
271}
272
273bool QgsLayerDefinition::exportLayerDefinition( QDomDocument doc, const QList<QgsLayerTreeNode *> &selectedTreeNodes, QString &errorMessage, const QgsReadWriteContext &context )
274{
275 Q_UNUSED( errorMessage )
276 QDomElement qgiselm = doc.createElement( u"qlr"_s );
277 doc.appendChild( qgiselm );
279 for ( QgsLayerTreeNode *node : selectedTreeNodes )
280 {
281 QgsLayerTreeNode *newnode = node->clone();
282 root.addChildNode( newnode );
283 }
284 root.writeXml( qgiselm, context );
285
286 QDomElement layerselm = doc.createElement( u"maplayers"_s );
287 const QList<QgsLayerTreeLayer *> layers = root.findLayers();
288 for ( QgsLayerTreeLayer *layer : layers )
289 {
290 if ( !layer->layer() )
291 {
292 QgsDebugMsgLevel( u"Not a valid map layer: skipping %1"_s.arg( layer->name() ), 4 );
293 continue;
294 }
295 QDomElement layerelm = doc.createElement( u"maplayer"_s );
296 layer->layer()->writeLayerXml( layerelm, doc, context );
297 layerselm.appendChild( layerelm );
298 }
299 qgiselm.appendChild( layerselm );
300 return true;
301}
302
303QDomDocument QgsLayerDefinition::exportLayerDefinitionLayers( const QList<QgsMapLayer *> &layers, const QgsReadWriteContext &context )
304{
305 QDomDocument doc( u"qgis-layer-definition"_s );
306 QDomElement qgiselm = doc.createElement( u"qlr"_s );
307 doc.appendChild( qgiselm );
308 QDomElement layerselm = doc.createElement( u"maplayers"_s );
309 const auto constLayers = layers;
310 for ( QgsMapLayer *layer : constLayers )
311 {
312 QDomElement layerelm = doc.createElement( u"maplayer"_s );
313 layer->writeLayerXml( layerelm, doc, context );
314 layerselm.appendChild( layerelm );
315 }
316 qgiselm.appendChild( layerselm );
317 return doc;
318}
319
320QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( QDomDocument &document, QgsReadWriteContext &context )
321{
322 QString errorMessage;
323 return loadLayerDefinitionLayersInternal( document, context, errorMessage );
324}
325
326QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayersInternal( QDomDocument &document, QgsReadWriteContext &context, QString &errorMessage )
327{
328 QList<QgsMapLayer *> layers;
329 QDomElement layerElem = document.documentElement().firstChildElement( u"projectlayers"_s ).firstChildElement( u"maplayer"_s );
330 // For QLR:
331 if ( layerElem.isNull() )
332 {
333 layerElem = document.documentElement().firstChildElement( u"maplayers"_s ).firstChildElement( u"maplayer"_s );
334 }
335
336 while ( !layerElem.isNull() )
337 {
338 const QString type = layerElem.attribute( u"type"_s );
339 QgsMapLayer *layer = nullptr;
340
341 bool ok = false;
342 const Qgis::LayerType layerType = QgsMapLayerFactory::typeFromString( type, ok );
343 if ( ok )
344 {
345 switch ( layerType )
346 {
348 layer = new QgsVectorLayer();
349 break;
350
352 layer = new QgsRasterLayer();
353 break;
354
356 {
357 const QString typeName = layerElem.attribute( u"name"_s );
359 break;
360 }
361
363 layer = new QgsMeshLayer();
364 break;
365
367 layer = new QgsVectorTileLayer;
368 break;
369
371 layer = new QgsPointCloudLayer();
372 break;
373
375 layer = new QgsTiledSceneLayer;
376 break;
377
379 layer = new QgsGroupLayer( QString(), QgsGroupLayer::LayerOptions( QgsCoordinateTransformContext() ) );
380 break;
381
383 break;
384 }
385 }
386
387 if ( layer )
388 {
389 // always add the layer, even if the source is invalid -- this allows users to fix the source
390 // at a later stage and still retain all the layer properties intact
391 layer->readLayerXml( layerElem, context );
392 layers << layer;
393 }
394 else
395 {
396 errorMessage = QObject::tr( "Unsupported layer type: %1" ).arg( type );
397 }
398 layerElem = layerElem.nextSiblingElement( u"maplayer"_s );
399 }
400 return layers;
401}
402
403QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayers( const QString &qlrfile )
404{
405 QFile file( qlrfile );
406 if ( !file.open( QIODevice::ReadOnly ) )
407 {
408 QgsDebugError( u"Can't open file"_s );
409 return QList<QgsMapLayer *>();
410 }
411
412 QDomDocument doc;
413 if ( !doc.setContent( &file ) )
414 {
415 QgsDebugError( u"Can't set content"_s );
416 return QList<QgsMapLayer *>();
417 }
418
419 QgsReadWriteContext context;
420 context.setPathResolver( QgsPathResolver( qlrfile ) );
421 //no project translator defined here
423}
424
425void QgsLayerDefinition::DependencySorter::init( const QDomDocument &doc )
426{
427 // Determine a loading order of layers based on a graph of dependencies
428 QMap< QString, QVector< QString > > dependencies;
429 QStringList sortedLayers;
430 QList< QPair<QString, QDomNode> > layersToSort;
431 QStringList layerIds;
432
433 QDomElement layerElem = doc.documentElement().firstChildElement( u"projectlayers"_s ).firstChildElement( u"maplayer"_s );
434 // For QLR:
435 if ( layerElem.isNull() )
436 {
437 layerElem = doc.documentElement().firstChildElement( u"maplayers"_s ).firstChildElement( u"maplayer"_s );
438 }
439 // For tests (I don't know if there is a real use case for such a document except for test_qgslayerdefinition.py)
440 if ( layerElem.isNull() )
441 {
442 layerElem = doc.documentElement().firstChildElement( u"maplayer"_s );
443 }
444
445 const QDomElement &firstElement { layerElem };
446
447 QVector<QString> deps; //avoid expensive allocation for list for every iteration
448 while ( !layerElem.isNull() )
449 {
450 deps.resize( 0 ); // preserve capacity - don't use clear
451
452 const QString id = layerElem.namedItem( u"id"_s ).toElement().text();
453 layerIds << id;
454
455 // dependencies for this layer
456 const QDomElement layerDependenciesElem = layerElem.firstChildElement( u"layerDependencies"_s );
457 if ( !layerDependenciesElem.isNull() )
458 {
459 const QDomNodeList dependencyList = layerDependenciesElem.elementsByTagName( u"layer"_s );
460 for ( int j = 0; j < dependencyList.size(); ++j )
461 {
462 const QDomElement depElem = dependencyList.at( j ).toElement();
463 deps << depElem.attribute( u"id"_s );
464 }
465 }
466 dependencies[id] = deps;
467
468 if ( deps.empty() )
469 {
470 sortedLayers << id;
471 mSortedLayerNodes << layerElem;
472 mSortedLayerIds << id;
473 }
474 else
475 {
476 layersToSort << qMakePair( id, layerElem );
477 mDependentLayerIds.insert( id );
478 }
479 layerElem = layerElem.nextSiblingElement();
480 }
481
482 // check that all dependencies are present
483 const auto constDependencies = dependencies;
484 for ( const QVector< QString > &ids : constDependencies )
485 {
486 const auto constIds = ids;
487 for ( const QString &depId : constIds )
488 {
489 if ( !dependencies.contains( depId ) )
490 {
491 // some dependencies are not satisfied
492 mHasMissingDependency = true;
493 layerElem = firstElement;
494 while ( !layerElem.isNull() )
495 {
496 mSortedLayerNodes << layerElem;
497 layerElem = layerElem.nextSiblingElement();
498 }
499 mSortedLayerIds = layerIds;
500 return;
501 }
502 }
503 }
504
505 // cycles should be very rare, since layers with cyclic dependencies may only be created by
506 // manually modifying the project file
507 mHasCycle = false;
508
509 while ( !layersToSort.empty() && !mHasCycle )
510 {
511 QList< QPair<QString, QDomNode> >::iterator it = layersToSort.begin();
512 while ( it != layersToSort.end() )
513 {
514 const QString idToSort = it->first;
515 const QDomNode node = it->second;
516 mHasCycle = true;
517 bool resolved = true;
518 const auto deps { dependencies.value( idToSort ) };
519 for ( const QString &dep : deps )
520 {
521 if ( !sortedLayers.contains( dep ) )
522 {
523 resolved = false;
524 break;
525 }
526 }
527 if ( resolved ) // dependencies for this layer are resolved
528 {
529 sortedLayers << idToSort;
530 mSortedLayerNodes << node;
531 mSortedLayerIds << idToSort;
532 it = layersToSort.erase( it ); // erase and go to the next
533 mHasCycle = false;
534 }
535 else
536 {
537 ++it;
538 }
539 }
540 }
541}
542
544 : mHasCycle( false )
545 , mHasMissingDependency( false )
546{
547 init( doc );
548}
549
551 : mHasCycle( false )
552 , mHasMissingDependency( false )
553{
554 QString qgsProjectFile = fileName;
555 QgsProjectArchive archive;
556 if ( fileName.endsWith( ".qgz"_L1, Qt::CaseInsensitive ) )
557 {
558 archive.unzip( fileName );
559 qgsProjectFile = archive.projectFile();
560 }
561
562 QDomDocument doc;
563 QFile pFile( qgsProjectFile );
564 ( void ) pFile.open( QIODevice::ReadOnly );
565 ( void ) doc.setContent( &pFile );
566 init( doc );
567}
568
570{
571 return mDependentLayerIds.contains( layerId );
572}
LayerTreeInsertionMethod
Layer tree insertion methods.
Definition qgis.h:4954
@ TopOfTree
Layers are added at the top of the layer tree.
Definition qgis.h:4956
@ AboveInsertionPoint
Layers are added in the tree above the insertion point.
Definition qgis.h:4955
FilePathType
File path types.
Definition qgis.h:1826
@ Relative
Relative path.
Definition qgis.h:1828
@ Absolute
Absolute path.
Definition qgis.h:1827
LayerType
Types of layers that can be added to a map.
Definition qgis.h:206
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:214
@ Plugin
Plugin based layer.
Definition qgis.h:209
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:215
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:212
@ Vector
Vector layer.
Definition qgis.h:207
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:211
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:210
@ Raster
Raster layer.
Definition qgis.h:208
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:213
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 void regenerateGroupIds(QgsLayerTreeNode *node)
Assigns a new unique id to every group in the sub-tree rooted at node.
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:111
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:114
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:80
#define QgsDebugError(str)
Definition qgslogger.h:71
A structure to define the insertion point to the layer tree.