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() )
 
  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.