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 )
445 QString qgsProjectFile = fileName;
447 if ( fileName.endsWith( QLatin1String(
".qgz" ), Qt::CaseInsensitive ) )
449 archive.
unzip( fileName );
454 QFile pFile( qgsProjectFile );
455 ( void )pFile.open( QIODevice::ReadOnly );
456 ( 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.
bool unzip(const QString &zipFilename) override
Clear the current content of this archive and unzip.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
bool readLayerXml(const QDomElement &layerElement, QgsReadWriteContext &context, QgsMapLayer::ReadFlags flags=nullptr)
Sets state from DOM document.
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...
Represents a raster layer.
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...
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.
Class allowing to manage the zip/unzip actions on project file.
DependencySorter(const QDomDocument &doc)
Constructor.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
QString projectFile() const
Returns the current .qgs project file or an empty string if there's none.
#define QgsDebugMsgLevel(str, level)
This class is a base class for nodes in a layer tree.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc.
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.