18 #include <QTextStream> 36 if ( !file.open( QIODevice::ReadOnly ) )
38 errorMessage = QStringLiteral(
"Can not open file" );
44 if ( !doc.setContent( &file, &message ) )
46 errorMessage = message;
50 QFileInfo fileinfo( file );
51 QDir::setCurrent( fileinfo.absoluteDir().path() );
55 context.setProjectTranslator( project );
62 Q_UNUSED( errorMessage )
72 QVector<QDomNode> clonedSorted;
73 const auto constSortedLayerNodes = sortedLayerNodes;
74 for (
const QDomNode &node : constSortedLayerNodes )
76 clonedSorted << node.cloneNode();
78 QDomNode layersNode = doc.elementsByTagName( QStringLiteral(
"maplayers" ) ).at( 0 );
80 QDomNodeList childNodes = layersNode.childNodes();
81 for (
int i = 0; i < childNodes.size(); i++ )
83 layersNode.replaceChild( clonedSorted.at( i ), childNodes.at( i ) );
90 QDomNodeList treeLayerNodes = doc.elementsByTagName( QStringLiteral(
"layer-tree-layer" ) );
91 for (
int i = 0; i < treeLayerNodes.size(); ++i )
93 QDomNode treeLayerNode = treeLayerNodes.at( i );
94 QDomElement treeLayerElem = treeLayerNode.toElement();
95 QString oldid = treeLayerElem.attribute( QStringLiteral(
"id" ) );
96 QString layername = treeLayerElem.attribute( QStringLiteral(
"name" ) );
98 treeLayerElem.setAttribute( QStringLiteral(
"id" ), newid );
101 QDomNodeList ids = doc.elementsByTagName( QStringLiteral(
"id" ) );
102 for (
int i = 0; i < ids.size(); ++i )
104 QDomNode idnode = ids.at( i );
105 QDomElement idElem = idnode.toElement();
106 if ( idElem.text() == oldid )
108 idElem.firstChild().setNodeValue( newid );
113 QDomNodeList vectorJoinNodes = doc.elementsByTagName( QStringLiteral(
"join" ) );
114 for (
int j = 0; j < vectorJoinNodes.size(); ++j )
116 QDomNode joinNode = vectorJoinNodes.at( j );
117 QDomElement joinElement = joinNode.toElement();
118 if ( joinElement.attribute( QStringLiteral(
"joinLayerId" ) ) == oldid )
120 joinNode.toElement().setAttribute( QStringLiteral(
"joinLayerId" ), newid );
125 QDomNodeList dataDeps = doc.elementsByTagName( QStringLiteral(
"dataDependencies" ) );
126 for (
int i = 0; i < dataDeps.size(); i++ )
128 QDomNodeList layers = dataDeps.at( i ).childNodes();
129 for (
int j = 0; j < layers.size(); j++ )
131 QDomElement elt = layers.at( j ).toElement();
132 if ( elt.attribute( QStringLiteral(
"id" ) ) == oldid )
134 elt.setAttribute( QStringLiteral(
"id" ), newid );
140 QDomNodeList widgetConfig = doc.elementsByTagName( QStringLiteral(
"editWidget" ) );
141 for (
int i = 0; i < widgetConfig.size(); i++ )
143 QDomNodeList config = widgetConfig.at( i ).childNodes();
144 for (
int j = 0; j < config.size(); j++ )
146 QDomNodeList optMap = config.at( j ).childNodes();
147 for (
int z = 0; z < optMap.size(); z++ )
149 QDomNodeList opts = optMap.at( z ).childNodes();
150 for (
int k = 0; k < opts.size(); k++ )
152 QDomElement opt = opts.at( k ).toElement();
153 if ( opt.attribute( QStringLiteral(
"value" ) ) == oldid )
155 opt.setAttribute( QStringLiteral(
"value" ), newid );
163 QDomElement layerTreeElem = doc.documentElement().firstChildElement( QStringLiteral(
"layer-tree-group" ) );
164 bool loadInLegend =
true;
165 if ( !layerTreeElem.isNull() )
168 loadInLegend =
false;
176 const auto constLayers = layers;
179 if (
QgsVectorLayer *vlayer = qobject_cast< QgsVectorLayer * >( layer ) )
181 vlayer->resolveReferences( project );
187 QList<QgsLayerTreeNode *> nodes = root->
children();
188 const auto constNodes = nodes;
201 if ( !path.endsWith( QLatin1String(
".qlr" ) ) )
202 path = path.append(
".qlr" );
206 if ( !file.open( QFile::WriteOnly | QFile::Truncate ) )
208 errorMessage = file.errorString();
215 QDomDocument doc( QStringLiteral(
"qgis-layer-definition" ) );
219 QTextStream qlayerstream( &file );
220 doc.save( qlayerstream, 2 );
226 Q_UNUSED( errorMessage )
227 QDomElement qgiselm = doc.createElement( QStringLiteral(
"qlr" ) );
228 doc.appendChild( qgiselm );
229 QList<QgsLayerTreeNode *> nodes = selectedTreeNodes;
231 const auto constNodes = nodes;
239 QDomElement layerselm = doc.createElement( QStringLiteral(
"maplayers" ) );
240 QList<QgsLayerTreeLayer *> layers = root->
findLayers();
241 const auto constLayers = layers;
244 if ( ! layer->layer() )
246 QgsDebugMsgLevel( QStringLiteral(
"Not a valid map layer: skipping %1" ).arg( layer->name( ) ), 4 );
249 QDomElement layerelm = doc.createElement( QStringLiteral(
"maplayer" ) );
250 layer->layer()->writeLayerXml( layerelm, doc, context );
251 layerselm.appendChild( layerelm );
253 qgiselm.appendChild( layerselm );
259 QDomDocument doc( QStringLiteral(
"qgis-layer-definition" ) );
260 QDomElement qgiselm = doc.createElement( QStringLiteral(
"qlr" ) );
261 doc.appendChild( qgiselm );
262 QDomElement layerselm = doc.createElement( QStringLiteral(
"maplayers" ) );
263 const auto constLayers = layers;
266 QDomElement layerelm = doc.createElement( QStringLiteral(
"maplayer" ) );
267 layer->writeLayerXml( layerelm, doc, context );
268 layerselm.appendChild( layerelm );
270 qgiselm.appendChild( layerselm );
276 QList<QgsMapLayer *> layers;
277 QDomNodeList layernodes = document.elementsByTagName( QStringLiteral(
"maplayer" ) );
278 for (
int i = 0; i < layernodes.size(); ++i )
280 QDomNode layernode = layernodes.at( i );
281 QDomElement layerElem = layernode.toElement();
283 QString type = layerElem.attribute( QStringLiteral(
"type" ) );
287 if ( type == QLatin1String(
"vector" ) )
291 else if ( type == QLatin1String(
"raster" ) )
295 else if ( type == QLatin1String(
"plugin" ) )
297 QString
typeName = layerElem.attribute( QStringLiteral(
"name" ) );
314 QFile file( qlrfile );
315 if ( !file.open( QIODevice::ReadOnly ) )
317 QgsDebugMsg( QStringLiteral(
"Can't open file" ) );
318 return QList<QgsMapLayer *>();
322 if ( !doc.setContent( &file ) )
324 QgsDebugMsg( QStringLiteral(
"Can't set content" ) );
325 return QList<QgsMapLayer *>();
335 void QgsLayerDefinition::DependencySorter::init(
const QDomDocument &doc )
338 QMap< QString, QVector< QString > > dependencies;
339 QStringList sortedLayers;
340 QList< QPair<QString, QDomNode> > layersToSort;
341 QStringList layerIds;
343 QDomNodeList nl = doc.elementsByTagName( QStringLiteral(
"maplayer" ) );
344 layerIds.reserve( nl.count() );
345 QVector<QString> deps;
346 for (
int i = 0; i < nl.count(); i++ )
349 QDomNode node = nl.item( i );
351 QString
id = node.namedItem( QStringLiteral(
"id" ) ).toElement().text();
355 QDomElement layerDependenciesElem = node.firstChildElement( QStringLiteral(
"layerDependencies" ) );
356 if ( !layerDependenciesElem.isNull() )
358 QDomNodeList dependencyList = layerDependenciesElem.elementsByTagName( QStringLiteral(
"layer" ) );
359 for (
int j = 0; j < dependencyList.size(); ++j )
361 QDomElement depElem = dependencyList.at( j ).toElement();
362 deps << depElem.attribute( QStringLiteral(
"id" ) );
365 dependencies[id] = deps;
370 mSortedLayerNodes << node;
371 mSortedLayerIds << id;
374 layersToSort << qMakePair(
id, node );
378 const auto constDependencies = dependencies;
379 for (
const QVector< QString > &ids : constDependencies )
381 const auto constIds = ids;
382 for (
const QString &depId : constIds )
384 if ( !dependencies.contains( depId ) )
387 mHasMissingDependency =
true;
388 for (
int i = 0; i < nl.size(); i++ )
389 mSortedLayerNodes << nl.at( i );
390 mSortedLayerIds = layerIds;
400 while ( !layersToSort.empty() && !mHasCycle )
402 QList< QPair<QString, QDomNode> >::iterator it = layersToSort.begin();
403 while ( it != layersToSort.end() )
405 QString idToSort = it->first;
406 QDomNode node = it->second;
408 bool resolved =
true;
409 const auto deps { dependencies.value( idToSort ) };
410 for (
const QString &dep : deps )
412 if ( !sortedLayers.contains( dep ) )
420 sortedLayers << idToSort;
421 mSortedLayerNodes << node;
422 mSortedLayerIds << idToSort;
423 it = layersToSort.erase( it );
436 , mHasMissingDependency( false )
443 , mHasMissingDependency( false )
446 QFile pFile( fileName );
447 ( void )pFile.open( QIODevice::ReadOnly );
448 ( void )doc.setContent( &pFile );
Layer tree group node serves as a container for layers and further groups.
The class is used as a container of context for various read/write operations on other objects...
void readChildrenFromXml(QDomElement &element, const QgsReadWriteContext &context)
Read children from XML and append them to the group.
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 QString generateId(const QString &layerName)
Generates an unique identifier for this layer, the generate ID is prefixed by layerName.
QList< QgsMapLayer * > addMapLayers(const QList< QgsMapLayer *> &mapLayers, bool addToLegend=true, bool takeOwnership=true)
Add a list of layers to the map of loaded layers.
Base class for all map layer types.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
bool takeChild(QgsLayerTreeNode *node)
Remove a child from a node.
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...
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
virtual QgsLayerTreeNode * clone() const =0
Create a copy of the node. Returns new instance.
Class used to work with layer dependencies stored in a XML project or layer definition file...
QVector< QDomNode > sortedLayerNodes() const
Gets the layer nodes in an order where they can be loaded incrementally without dependency break...
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...
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context)
Sets state from DOM document.
static QgsPluginLayerRegistry * pluginLayerRegistry()
Returns the application's plugin layer registry, used for managing plugin layer types.
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Calls resolveReferences() on child tree nodes.
DependencySorter(const QDomDocument &doc)
Constructor.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
#define QgsDebugMsgLevel(str, level)
This class is a base class for nodes in a layer tree.
Reads and writes project states.
static QList< QgsMapLayer * > loadLayerDefinitionLayers(QDomDocument &document, QgsReadWriteContext &context)
Creates new layers from a layer definition document.
void insertChildNodes(int index, const QList< QgsLayerTreeNode *> &nodes)
Insert existing nodes at specified position.
bool hasMissingDependency() const
Whether some dependency is missing.
static bool exportLayerDefinition(QString path, const QList< QgsLayerTreeNode *> &selectedTreeNodes, QString &errorMessage)
Export the selected layer tree nodes to a QLR file.
void addChildNode(QgsLayerTreeNode *node)
Append an existing node.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
Resolves relative paths into absolute paths and vice versa.
Represents a vector layer which manages a vector based data sets.
QgsPluginLayer * createLayer(const QString &typeName, const QString &uri=QString())
Returns new layer if corresponding plugin has been found else returns nullptr.
Layer tree node points to a map layer.