23 #include <QDomElement>
24 #include <QTextStream>
26 static void _readOldLegendGroup(
const QDomElement &groupElem,
QgsLayerTreeGroup *parent );
27 static void _readOldLegendLayer(
const QDomElement &layerElem,
QgsLayerTreeGroup *parent );
31 if ( legendElem.isNull() )
34 const QDomNodeList legendChildren = legendElem.childNodes();
36 for (
int i = 0; i < legendChildren.size(); ++i )
38 const QDomElement currentChildElem = legendChildren.at( i ).toElement();
39 if ( currentChildElem.tagName() == QLatin1String(
"legendlayer" ) )
41 _readOldLegendLayer( currentChildElem, root );
43 else if ( currentChildElem.tagName() == QLatin1String(
"legendgroup" ) )
45 _readOldLegendGroup( currentChildElem, root );
54 static bool _readOldLegendLayerOrderGroup(
const QDomElement &groupElem, QMap<int, QString> &layerIndexes )
56 const QDomNodeList legendChildren = groupElem.childNodes();
58 for (
int i = 0; i < legendChildren.size(); ++i )
60 const QDomElement currentChildElem = legendChildren.at( i ).toElement();
61 if ( currentChildElem.tagName() == QLatin1String(
"legendlayer" ) )
63 const QDomElement layerFileElem = currentChildElem.firstChildElement( QStringLiteral(
"filegroup" ) ).firstChildElement( QStringLiteral(
"legendlayerfile" ) );
65 const int layerIndex = currentChildElem.attribute( QStringLiteral(
"drawingOrder" ) ).toInt();
66 if ( layerIndex == -1 )
68 layerIndexes.insert( layerIndex, layerFileElem.attribute( QStringLiteral(
"layerid" ) ) );
70 else if ( currentChildElem.tagName() == QLatin1String(
"legendgroup" ) )
72 if ( !_readOldLegendLayerOrderGroup( currentChildElem, layerIndexes ) )
83 if ( legendElem.isNull() )
86 hasCustomOrder = legendElem.attribute( QStringLiteral(
"updateDrawingOrder" ) ) == QLatin1String(
"false" );
89 QMap<int, QString> layerIndexes;
92 const bool res = _readOldLegendLayerOrderGroup( legendElem, layerIndexes );
94 if ( !res && hasCustomOrder )
97 const auto constLayerIndexes = layerIndexes;
98 for (
const QString &layerId : constLayerIndexes )
101 order.append( layerId );
108 static QDomElement _writeOldLegendLayer( QDomDocument &doc,
QgsLayerTreeLayer *nodeLayer,
bool hasCustomOrder,
const QList<QgsMapLayer *> &order )
110 int drawingOrder = -1;
111 if ( hasCustomOrder )
112 drawingOrder = order.indexOf( nodeLayer->
layer() );
114 QDomElement layerElem = doc.createElement( QStringLiteral(
"legendlayer" ) );
115 layerElem.setAttribute( QStringLiteral(
"drawingOrder" ), drawingOrder );
116 layerElem.setAttribute( QStringLiteral(
"open" ), nodeLayer->
isExpanded() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
118 layerElem.setAttribute( QStringLiteral(
"name" ), nodeLayer->
name() );
119 layerElem.setAttribute( QStringLiteral(
"showFeatureCount" ), nodeLayer->
customProperty( QStringLiteral(
"showFeatureCount" ) ).toInt() );
121 QDomElement fileGroupElem = doc.createElement( QStringLiteral(
"filegroup" ) );
122 fileGroupElem.setAttribute( QStringLiteral(
"open" ), nodeLayer->
isExpanded() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
123 fileGroupElem.setAttribute( QStringLiteral(
"hidden" ), QStringLiteral(
"false" ) );
125 QDomElement layerFileElem = doc.createElement( QStringLiteral(
"legendlayerfile" ) );
126 layerFileElem.setAttribute( QStringLiteral(
"isInOverview" ), nodeLayer->
customProperty( QStringLiteral(
"overview" ) ).toInt() );
127 layerFileElem.setAttribute( QStringLiteral(
"layerid" ), nodeLayer->
layerId() );
128 layerFileElem.setAttribute( QStringLiteral(
"visible" ), nodeLayer->
isVisible() ? 1 : 0 );
130 layerElem.appendChild( fileGroupElem );
131 fileGroupElem.appendChild( layerFileElem );
136 static void _writeOldLegendGroupChildren( QDomDocument &doc, QDomElement &groupElem,
QgsLayerTreeGroup *nodeGroup,
bool hasCustomOrder,
const QList<QgsMapLayer *> &order );
138 static QDomElement _writeOldLegendGroup( QDomDocument &doc,
QgsLayerTreeGroup *nodeGroup,
bool hasCustomOrder,
const QList<QgsMapLayer *> &order )
140 QDomElement groupElem = doc.createElement( QStringLiteral(
"legendgroup" ) );
141 groupElem.setAttribute( QStringLiteral(
"open" ), nodeGroup->
isExpanded() ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
142 groupElem.setAttribute( QStringLiteral(
"name" ), nodeGroup->
name() );
145 if ( nodeGroup->
customProperty( QStringLiteral(
"embedded" ) ).toInt() )
147 groupElem.setAttribute( QStringLiteral(
"embedded" ), 1 );
148 groupElem.setAttribute( QStringLiteral(
"project" ), nodeGroup->
customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
151 _writeOldLegendGroupChildren( doc, groupElem, nodeGroup, hasCustomOrder, order );
156 static void _writeOldLegendGroupChildren( QDomDocument &doc, QDomElement &groupElem,
QgsLayerTreeGroup *nodeGroup,
bool hasCustomOrder,
const QList<QgsMapLayer *> &order )
158 const auto constChildren = nodeGroup->
children();
163 groupElem.appendChild( _writeOldLegendGroup( doc,
QgsLayerTree::toGroup( node ), hasCustomOrder, order ) );
167 groupElem.appendChild( _writeOldLegendLayer( doc,
QgsLayerTree::toLayer( node ), hasCustomOrder, order ) );
175 QDomElement legendElem = doc.createElement( QStringLiteral(
"legend" ) );
176 legendElem.setAttribute( QStringLiteral(
"updateDrawingOrder" ), hasCustomOrder ? QStringLiteral(
"false" ) : QStringLiteral(
"true" ) );
178 _writeOldLegendGroupChildren( doc, legendElem, root, hasCustomOrder, order );
189 return QStringLiteral(
"Qt::Unchecked" );
190 case Qt::PartiallyChecked:
191 return QStringLiteral(
"Qt::PartiallyChecked" );
193 return QStringLiteral(
"Qt::Checked" );
200 if ( txt == QLatin1String(
"Qt::Unchecked" ) )
201 return Qt::Unchecked;
202 else if ( txt == QLatin1String(
"Qt::PartiallyChecked" ) )
203 return Qt::PartiallyChecked;
210 static void _readOldLegendGroup(
const QDomElement &groupElem,
QgsLayerTreeGroup *parent )
212 const QDomNodeList groupChildren = groupElem.childNodes();
217 groupNode->
setExpanded( groupElem.attribute( QStringLiteral(
"open" ) ) == QLatin1String(
"true" ) );
219 if ( groupElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
222 groupNode->
setCustomProperty( QStringLiteral(
"embedded_project" ), groupElem.attribute( QStringLiteral(
"project" ) ) );
225 for (
int i = 0; i < groupChildren.size(); ++i )
227 const QDomElement currentChildElem = groupChildren.at( i ).toElement();
228 if ( currentChildElem.tagName() == QLatin1String(
"legendlayer" ) )
230 _readOldLegendLayer( currentChildElem, groupNode );
232 else if ( currentChildElem.tagName() == QLatin1String(
"legendgroup" ) )
234 _readOldLegendGroup( currentChildElem, groupNode );
241 static void _readOldLegendLayer(
const QDomElement &layerElem,
QgsLayerTreeGroup *parent )
243 const QDomElement layerFileElem = layerElem.firstChildElement( QStringLiteral(
"filegroup" ) ).firstChildElement( QStringLiteral(
"legendlayerfile" ) );
244 const QString layerId = layerFileElem.attribute( QStringLiteral(
"layerid" ) );
248 layerNode->
setExpanded( layerElem.attribute( QStringLiteral(
"open" ) ) == QLatin1String(
"true" ) );
250 if ( layerFileElem.attribute( QStringLiteral(
"isInOverview" ) ) == QLatin1String(
"1" ) )
253 if ( layerElem.attribute( QStringLiteral(
"embedded" ) ) == QLatin1String(
"1" ) )
256 if ( layerElem.attribute( QStringLiteral(
"showFeatureCount" ) ) == QLatin1String(
"1" ) )
266 const auto constLayerNodes = layerNodes;
281 const auto constLayerNodes = layerNodes;
296 QList<QgsLayerTreeNode *> nodesToRemove;
297 const auto constChildren = group->
children();
305 nodesToRemove << node;
309 const auto constNodesToRemove = nodesToRemove;
316 const QDomElement projectLayersElement { doc->documentElement().firstChildElement( QStringLiteral(
"projectlayers" ) ) };
328 QDomElement layerElement { projectLayersElement.firstChildElement( QStringLiteral(
"maplayer" ) ) };
329 while ( ! layerElement.isNull() )
331 const QString id( layerElement.firstChildElement( QStringLiteral(
"id" ) ).firstChild().nodeValue() );
335 QTextStream stream( &
str );
336 layerElement.save( stream, 4 );
337 l->setOriginalXmlProperties( QStringLiteral(
"<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>\n%1" ).arg(
str ) );
340 layerElement = layerElement.nextSiblingElement( );
346 const QList<QgsLayerTreeNode *> constChildren( node->children( ) );
347 for (
const auto &childNode : constChildren )
354 const QList<QgsLayerTreeNode *> children = group->
children();
370 if ( child->itemVisibilityChecked() == Qt::Unchecked )
389 const auto constChildren = group->
children();
394 if ( child->customProperty( QStringLiteral(
"embedded" ) ).toInt() )
396 child->setCustomProperty( QStringLiteral(
"embedded-invisible-layers" ),
invisibleLayerList( child ) );
410 const auto constChildren = group->
children();
413 if ( !node->customProperty( QStringLiteral(
"embedded_project" ) ).toString().isEmpty() )
416 const QString newPath = project->
writePath( node->customProperty( QStringLiteral(
"embedded_project" ) ).toString() );
417 node->setCustomProperty( QStringLiteral(
"embedded_project" ), newPath );
430 layer.
setCustomProperty( QStringLiteral(
"legend/expressionFilterEnabled" ), enabled && !expr.isEmpty() );
435 const QString expression = layer.
customProperty( QStringLiteral(
"legend/expressionFilter" ), QString() ).toString();
437 *enabled = !expression.isEmpty() && layer.
customProperty( QStringLiteral(
"legend/expressionFilterEnabled" ), QString() ).toBool();
443 const auto constFindLayers = group.
findLayers();
448 if ( exprEnabled && !expr.isEmpty() )
475 return parent->
insertLayer( idx + 1, layerToInsert );
478 static void _collectMapLayers(
const QList<QgsLayerTreeNode *> &nodes, QSet<QgsMapLayer *> &layersSet )
485 if ( nodeLayer->
layer() )
486 layersSet << nodeLayer->
layer();
497 QSet<QgsMapLayer *> layersSet;
498 _collectMapLayers( nodes, layersSet );
512 const QList<QgsLayerTreeNode *> children = tree->
children();
@ UsersCannotToggleEditing
Indicates that users are not allowed to toggle editing for this layer. Note that this does not imply ...
Layer tree group node serves as a container for layers and further groups.
void removeChildNode(QgsLayerTreeNode *node)
Remove a child node from this group.
QString name() const override
Returns the group's name.
void addChildNode(QgsLayerTreeNode *node)
Append an existing node.
void removeAllChildren()
Remove all child nodes.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes.
QgsLayerTreeLayer * findLayer(QgsMapLayer *layer) const
Find layer node representing the map layer.
QgsLayerTreeLayer * insertLayer(int index, QgsMapLayer *layer)
Insert a new layer node for given map layer at specified position.
Layer tree node points to a map layer.
QString layerId() const
Returns the ID for the map layer associated with this node.
QString name() const override
Returns the layer's name.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
This class is a base class for nodes in a layer tree.
@ NodeLayer
Leaf node pointing to a layer.
bool isVisible() const
Returns whether a node is really visible (ie checked and all its ancestors checked as well)
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
void setExpanded(bool expanded)
Sets whether the node should be shown as expanded or collapsed in GUI.
QgsLayerTreeNode * parent()
Gets pointer to the parent. If parent is nullptr, the node is a root node.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
bool isExpanded() const
Returns whether the node should be shown as expanded or collapsed in GUI.
void setItemVisibilityChecked(bool checked)
Check or uncheck a node (independently of its ancestors or children)
bool itemVisibilityChecked() const
Returns whether a node is checked (independently of its ancestors or children)
static bool layersEditable(const QList< QgsLayerTreeLayer * > &layerNodes, bool ignoreLayersWhichCannotBeToggled=false)
Returns true if any of the specified layers is editable.
static QString checkStateToXml(Qt::CheckState state)
Convert Qt::CheckState to QString.
static void replaceChildrenOfEmbeddedGroups(QgsLayerTreeGroup *group)
Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers.
static QgsLayerTreeLayer * insertLayerBelow(QgsLayerTreeGroup *group, const QgsMapLayer *refLayer, QgsMapLayer *layerToInsert)
Insert a QgsMapLayer just below another one.
static void setLegendFilterByExpression(QgsLayerTreeLayer &layer, const QString &expr, bool enabled=true)
Sets the expression filter of a legend layer.
static QString legendFilterByExpression(const QgsLayerTreeLayer &layer, bool *enabled=nullptr)
Returns the expression filter of a legend layer.
static void storeOriginalLayersProperties(QgsLayerTreeGroup *group, const QDomDocument *doc)
Stores in a layer's originalXmlProperties the layer properties information.
static QSet< QgsMapLayer * > collectMapLayersRecursive(const QList< QgsLayerTreeNode * > &nodes)
Returns map layers from the given list of layer tree nodes.
static bool hasLegendFilterExpression(const QgsLayerTreeGroup &group)
Test if one of the layers in a group has an expression filter.
static int countMapLayerInTree(QgsLayerTreeNode *tree, QgsMapLayer *layer)
Returns how many occurrences of a map layer are there in a layer tree.
static QDomElement writeOldLegend(QDomDocument &doc, QgsLayerTreeGroup *root, bool hasCustomOrder, const QList< QgsMapLayer * > &order)
Returns.
static bool readOldLegendLayerOrder(const QDomElement &legendElem, bool &hasCustomOrder, QStringList &order)
Try to load custom layer order from.
static void updateEmbeddedGroupsProjectPath(QgsLayerTreeGroup *group, const QgsProject *project)
Updates an embedded group from a project.
static bool readOldLegend(QgsLayerTreeGroup *root, const QDomElement &legendElem)
Try to load layer tree from.
static QgsLayerTreeGroup * firstGroupWithoutCustomProperty(QgsLayerTreeGroup *group, const QString &property)
Returns the first parent which doesn't have the given custom property or the group itself if it doesn...
static void removeInvalidLayers(QgsLayerTreeGroup *group)
Removes layer nodes that refer to invalid layers.
static Qt::CheckState checkStateFromXml(const QString &txt)
Convert QString to Qt::CheckState.
static QStringList invisibleLayerList(QgsLayerTreeNode *node)
Gets invisible layers.
static bool layersModified(const QList< QgsLayerTreeLayer * > &layerNodes)
Returns true if any of the layers is modified.
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Base class for all map layer types.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
virtual Qgis::MapLayerProperties properties() const
Returns the map layer properties of this layer.
virtual bool isEditable() const
Returns true if the layer can be edited.
virtual bool isModified() const
Returns true if the layer has been modified since last commit/save.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.