43  if ( !file.open( QIODevice::ReadOnly ) )
 
   45    errorMessage = QStringLiteral( 
"Can not open file" );
 
   51  if ( !doc.setContent( &file, &message ) )
 
   53    errorMessage = message;
 
   57  const QFileInfo fileinfo( file );
 
   58  QDir::setCurrent( fileinfo.absoluteDir().path() );
 
   79    QVector<QDomNode> clonedSorted;
 
   80    const auto constSortedLayerNodes = sortedLayerNodes;
 
   81    for ( 
const QDomNode &node : constSortedLayerNodes )
 
   83      clonedSorted << node.cloneNode();
 
   85    QDomNode layersNode = doc.elementsByTagName( QStringLiteral( 
"maplayers" ) ).at( 0 );
 
   87    QDomNode childNode = layersNode.firstChild();
 
   88    for ( 
int i = 0; ! childNode.isNull(); i++ )
 
   90      layersNode.replaceChild( clonedSorted.at( i ), childNode );
 
   91      childNode = childNode.nextSibling();
 
   98  const QDomNodeList treeLayerNodes = doc.elementsByTagName( QStringLiteral( 
"layer-tree-layer" ) );
 
   99  for ( 
int i = 0; i < treeLayerNodes.length(); ++i )
 
  101    const QDomNode treeLayerNode = treeLayerNodes.item( i );
 
  102    QDomElement treeLayerElem = treeLayerNode.toElement();
 
  103    const QString oldid = treeLayerElem.attribute( QStringLiteral( 
"id" ) );
 
  104    const QString layername = treeLayerElem.attribute( QStringLiteral( 
"name" ) );
 
  106    treeLayerElem.setAttribute( QStringLiteral( 
"id" ), newid );
 
  109    const QDomNodeList ids = doc.elementsByTagName( QStringLiteral( 
"id" ) );
 
  110    QDomNode idnode = ids.at( 0 );
 
  111    for ( 
int j = 0; ! idnode.isNull() ; ++j )
 
  113      idnode = ids.at( j );
 
  114      const QDomElement idElem = idnode.toElement();
 
  115      if ( idElem.text() == oldid )
 
  117        idElem.firstChild().setNodeValue( newid );
 
  122    const QDomNodeList vectorJoinNodes = doc.elementsByTagName( QStringLiteral( 
"join" ) ); 
 
  123    for ( 
int j = 0; j < vectorJoinNodes.size(); ++j )
 
  125      const QDomNode joinNode = vectorJoinNodes.at( j );
 
  126      const QDomElement joinElement = joinNode.toElement();
 
  127      if ( joinElement.attribute( QStringLiteral( 
"joinLayerId" ) ) == oldid )
 
  129        joinNode.toElement().setAttribute( QStringLiteral( 
"joinLayerId" ), newid );
 
  134    const QDomNodeList dataDeps = doc.elementsByTagName( QStringLiteral( 
"dataDependencies" ) );
 
  135    for ( 
int i = 0; i < dataDeps.size(); i++ )
 
  137      const QDomNodeList layers = dataDeps.at( i ).childNodes();
 
  138      for ( 
int j = 0; j < layers.size(); j++ )
 
  140        QDomElement elt = layers.at( j ).toElement();
 
  141        if ( elt.attribute( QStringLiteral( 
"id" ) ) == oldid )
 
  143          elt.setAttribute( QStringLiteral( 
"id" ), newid );
 
  149    const QDomNodeList widgetConfig = doc.elementsByTagName( QStringLiteral( 
"editWidget" ) );
 
  150    for ( 
int i = 0; i < widgetConfig.size(); i++ )
 
  152      const QDomNodeList config = widgetConfig.at( i ).childNodes();
 
  153      for ( 
int j = 0; j < config.size(); j++ )
 
  155        const QDomNodeList optMap = config.at( j ).childNodes();
 
  156        for ( 
int z = 0; z < optMap.size(); z++ )
 
  158          const QDomNodeList opts = optMap.at( z ).childNodes();
 
  159          for ( 
int k = 0; k < opts.size(); k++ )
 
  161            QDomElement opt = opts.at( k ).toElement();
 
  162            if ( opt.attribute( QStringLiteral( 
"value" ) ) == oldid )
 
  164              opt.setAttribute( QStringLiteral( 
"value" ), newid );
 
  172  QDomElement layerTreeElem = doc.documentElement().firstChildElement( QStringLiteral( 
"layer-tree-group" ) );
 
  173  bool loadInLegend = 
true;
 
  174  if ( !layerTreeElem.isNull() )
 
  177    loadInLegend = 
false;
 
  180  const QList<QgsMapLayer *> layers = QgsLayerDefinition::loadLayerDefinitionLayersInternal( doc, context, errorMessage );
 
  185  const auto constLayers = layers;
 
  188    layer->resolveReferences( project );
 
  193  const QList<QgsLayerTreeNode *> nodes = root->
children();
 
  212  if ( !file.open( QFile::WriteOnly | QFile::Truncate ) )
 
  214    errorMessage = file.errorString();
 
  229  const QDomDocument doc( QStringLiteral( 
"qgis-layer-definition" ) );
 
  233  QTextStream qlayerstream( &file );
 
  234  doc.save( qlayerstream, 2 );
 
  240  Q_UNUSED( errorMessage )
 
  241  QDomElement qgiselm = doc.createElement( QStringLiteral( 
"qlr" ) );
 
  242  doc.appendChild( qgiselm );
 
  243  const QList<QgsLayerTreeNode *> nodes = selectedTreeNodes;
 
  245  const auto constNodes = nodes;
 
  253  QDomElement layerselm = doc.createElement( QStringLiteral( 
"maplayers" ) );
 
  254  const QList<QgsLayerTreeLayer *> layers = root->
findLayers();
 
  255  const auto constLayers = layers;
 
  258    if ( ! layer->layer() )
 
  260      QgsDebugMsgLevel( QStringLiteral( 
"Not a valid map layer: skipping %1" ).arg( layer->name( ) ), 4 );
 
  263    QDomElement layerelm = doc.createElement( QStringLiteral( 
"maplayer" ) );
 
  264    layer->layer()->writeLayerXml( layerelm, doc, context );
 
  265    layerselm.appendChild( layerelm );
 
  267  qgiselm.appendChild( layerselm );
 
  273  QDomDocument doc( QStringLiteral( 
"qgis-layer-definition" ) );
 
  274  QDomElement qgiselm = doc.createElement( QStringLiteral( 
"qlr" ) );
 
  275  doc.appendChild( qgiselm );
 
  276  QDomElement layerselm = doc.createElement( QStringLiteral( 
"maplayers" ) );
 
  277  const auto constLayers = layers;
 
  280    QDomElement layerelm = doc.createElement( QStringLiteral( 
"maplayer" ) );
 
  281    layer->writeLayerXml( layerelm, doc, context );
 
  282    layerselm.appendChild( layerelm );
 
  284  qgiselm.appendChild( layerselm );
 
  290  QString errorMessage;
 
  291  return loadLayerDefinitionLayersInternal( document, context, errorMessage );
 
  294QList<QgsMapLayer *> QgsLayerDefinition::loadLayerDefinitionLayersInternal( QDomDocument &document, 
QgsReadWriteContext &context, QString &errorMessage )
 
  296  QList<QgsMapLayer *> layers;
 
  297  QDomElement layerElem = document.documentElement().firstChildElement( QStringLiteral( 
"projectlayers" ) ).firstChildElement( QStringLiteral( 
"maplayer" ) );
 
  299  if ( layerElem.isNull() )
 
  301    layerElem = document.documentElement().firstChildElement( QStringLiteral( 
"maplayers" ) ).firstChildElement( QStringLiteral( 
"maplayer" ) );
 
  304  while ( ! layerElem.isNull() )
 
  306    const QString type = layerElem.attribute( QStringLiteral( 
"type" ) );
 
  315        case Qgis::LayerType::Vector:
 
  319        case Qgis::LayerType::Raster:
 
  323        case Qgis::LayerType::Plugin:
 
  325          const QString 
typeName = layerElem.attribute( QStringLiteral( 
"name" ) );
 
  330        case Qgis::LayerType::Mesh:
 
  334        case Qgis::LayerType::VectorTile:
 
  338        case Qgis::LayerType::PointCloud:
 
  342        case Qgis::LayerType::Group:
 
  346        case Qgis::LayerType::Annotation:
 
  360      errorMessage = QObject::tr( 
"Unsupported layer type: %1" ).arg( type );
 
  362    layerElem = layerElem.nextSiblingElement( QStringLiteral( 
"maplayer" ) );
 
  369  QFile file( qlrfile );
 
  370  if ( !file.open( QIODevice::ReadOnly ) )
 
  373    return QList<QgsMapLayer *>();
 
  377  if ( !doc.setContent( &file ) )
 
  380    return QList<QgsMapLayer *>();
 
  389void QgsLayerDefinition::DependencySorter::init( 
const QDomDocument &doc )
 
  392  QMap< QString, QVector< QString > > dependencies;
 
  393  QStringList sortedLayers;
 
  394  QList< QPair<QString, QDomNode> > layersToSort;
 
  395  QStringList layerIds;
 
  397  QDomElement layerElem = doc.documentElement().firstChildElement( QStringLiteral( 
"projectlayers" ) ).firstChildElement( QStringLiteral( 
"maplayer" ) );
 
  399  if ( layerElem.isNull() )
 
  401    layerElem = doc.documentElement().firstChildElement( QStringLiteral( 
"maplayers" ) ).firstChildElement( QStringLiteral( 
"maplayer" ) );
 
  404  if ( layerElem.isNull() )
 
  406    layerElem = doc.documentElement().firstChildElement( QStringLiteral( 
"maplayer" ) );
 
  409  const QDomElement &firstElement { layerElem };
 
  411  QVector<QString> deps; 
 
  412  while ( !layerElem.isNull() )
 
  416    const QString 
id = layerElem.namedItem( QStringLiteral( 
"id" ) ).toElement().text();
 
  420    const QDomElement layerDependenciesElem = layerElem.firstChildElement( QStringLiteral( 
"layerDependencies" ) );
 
  421    if ( !layerDependenciesElem.isNull() )
 
  423      const QDomNodeList dependencyList = layerDependenciesElem.elementsByTagName( QStringLiteral( 
"layer" ) );
 
  424      for ( 
int j = 0; j < dependencyList.size(); ++j )
 
  426        const QDomElement depElem = dependencyList.at( j ).toElement();
 
  427        deps << depElem.attribute( QStringLiteral( 
"id" ) );
 
  430    dependencies[id] = deps;
 
  435      mSortedLayerNodes << layerElem;
 
  436      mSortedLayerIds << id;
 
  440      layersToSort << qMakePair( 
id, layerElem );
 
  441      mDependentLayerIds.insert( 
id );
 
  443    layerElem = layerElem.nextSiblingElement( );
 
  447  const auto constDependencies = dependencies;
 
  448  for ( 
const QVector< QString > &ids : constDependencies )
 
  450    const auto constIds = ids;
 
  451    for ( 
const QString &depId : constIds )
 
  453      if ( !dependencies.contains( depId ) )
 
  456        mHasMissingDependency = 
true;
 
  457        layerElem = firstElement;
 
  458        while ( ! layerElem.isNull() )
 
  460          mSortedLayerNodes << layerElem;
 
  461          layerElem = layerElem.nextSiblingElement( );
 
  463        mSortedLayerIds = layerIds;
 
  473  while ( !layersToSort.empty() && !mHasCycle )
 
  475    QList< QPair<QString, QDomNode> >::iterator it = layersToSort.begin();
 
  476    while ( it != layersToSort.end() )
 
  478      const QString idToSort = it->first;
 
  479      const QDomNode node = it->second;
 
  481      bool resolved = 
true;
 
  482      const auto deps { dependencies.value( idToSort ) };
 
  483      for ( 
const QString &dep : deps )
 
  485        if ( !sortedLayers.contains( dep ) )
 
  493        sortedLayers << idToSort;
 
  494        mSortedLayerNodes << node;
 
  495        mSortedLayerIds << idToSort;
 
  496        it = layersToSort.erase( it ); 
 
  509  , mHasMissingDependency( false )
 
  516  , mHasMissingDependency( false )
 
  518  QString qgsProjectFile = fileName;
 
  520  if ( fileName.endsWith( QLatin1String( 
".qgz" ), Qt::CaseInsensitive ) )
 
  522    archive.
unzip( fileName );
 
  527  QFile pFile( qgsProjectFile );
 
  528  ( void )pFile.open( QIODevice::ReadOnly );
 
  529  ( void )doc.setContent( &pFile );
 
  535  return mDependentLayerIds.contains( layerId );
 
FilePathType
File path types.
 
LayerType
Types of layers that can be added to a map.
 
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
 
Contains information about the context in which a coordinate transform is executed.
 
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
 
A map layer which consists of a set of child layers, where all component layers are rendered as a sin...
 
Class used to work with layer 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 bool loadLayerDefinition(const QString &path, QgsProject *project, QgsLayerTreeGroup *rootGroup, QString &errorMessage)
Loads the QLR at path into QGIS. New layers are added to given project into layer tree specified by r...
 
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 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 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.
 
void readChildrenFromXml(QDomElement &element, const QgsReadWriteContext &context)
Read children from XML and append them to the group.
 
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
 
Layer tree node points to a map layer.
 
This class is a base class for nodes in a layer tree.
 
QList< QgsLayerTreeNode * > abandonChildren()
Removes the childrens, disconnect all the forwarded and external signals and sets their parent to nul...
 
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.
 
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.
 
Represents a mesh layer supporting display of data on structured or unstructured meshes.
 
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.
 
Represents a map layer supporting display of point clouds.
 
Class allowing to manage the zip/unzip actions on project file.
 
QString projectFile() const
Returns the current .qgs project file or an empty string if there's none.
 
bool unzip(const QString &zipFilename) override
Clear the current content of this archive and unzip.
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
 
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.
 
Represents a raster layer.
 
The class is used as a container of context for various read/write operations on other 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.
 
Represents a vector layer which manages a vector based data sets.
 
Implements a map layer that is dedicated to rendering of vector tiles.
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)
 
Setting options for loading group layers.