QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgslayertreelayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreelayer.cpp
3  --------------------------------------
4  Date : May 2014
5  Copyright : (C) 2014 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgslayertreelayer.h"
17 
18 #include "qgslayertreeutils.h"
19 #include "qgsmaplayer.h"
20 #include "qgsproject.h"
21 #include "qgssymbollayerutils.h"
22 
23 
25  : QgsLayerTreeNode( NodeLayer, true )
26  , mRef( layer )
27  , mLayerName( layer->name() )
28 {
29  attachToLayer();
30 }
31 
32 QgsLayerTreeLayer::QgsLayerTreeLayer( const QString &layerId, const QString &name, const QString &source, const QString &provider )
33  : QgsLayerTreeNode( NodeLayer, true )
34  , mRef( layerId, name, source, provider )
35  , mLayerName( name.isEmpty() ? QStringLiteral( "(?)" ) : name )
36 {
37 }
38 
40  : QgsLayerTreeNode( other )
41  , mRef( other.mRef )
42  , mLayerName( other.mLayerName )
43  , mPatchShape( other.mPatchShape )
44  , mPatchSize( other.mPatchSize )
45  , mSplitBehavior( other.mSplitBehavior )
46 {
47  attachToLayer();
48 }
49 
50 void QgsLayerTreeLayer::resolveReferences( const QgsProject *project, bool looseMatching )
51 {
52  if ( mRef )
53  return; // already assigned
54 
55  if ( !looseMatching )
56  {
57  mRef.resolve( project );
58  }
59  else
60  {
61  mRef.resolveWeakly( project );
62  }
63 
64  if ( !mRef )
65  return;
66 
67  attachToLayer();
68  emit layerLoaded();
69 }
70 
72 {
73  if ( !mRef )
74  return;
75 
76  connect( mRef.layer, &QgsMapLayer::nameChanged, this, &QgsLayerTreeLayer::layerNameChanged );
77  connect( mRef.layer, &QgsMapLayer::willBeDeleted, this, &QgsLayerTreeLayer::layerWillBeDeleted );
78 }
79 
80 
81 QString QgsLayerTreeLayer::name() const
82 {
83  return ( mRef && mUseLayerName ) ? mRef->name() : mLayerName;
84 }
85 
86 void QgsLayerTreeLayer::setName( const QString &n )
87 {
88  if ( mRef && mUseLayerName )
89  {
90  if ( mRef->name() == n )
91  return;
92  mRef->setName( n );
93  // no need to emit signal: we will be notified from layer's nameChanged() signal
94  }
95  else
96  {
97  if ( mLayerName == n )
98  return;
99  mLayerName = n;
100  emit nameChanged( this, n );
101  }
102 }
103 
104 QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element, const QgsReadWriteContext &context )
105 {
106  if ( element.tagName() != QLatin1String( "layer-tree-layer" ) )
107  return nullptr;
108 
109  QString layerID = element.attribute( QStringLiteral( "id" ) );
110  QString layerName = element.attribute( QStringLiteral( "name" ) );
111 
112  QString providerKey = element.attribute( QStringLiteral( "providerKey" ) );
113  QString source = context.pathResolver().readPath( element.attribute( QStringLiteral( "source" ) ) );
114 
115  Qt::CheckState checked = QgsLayerTreeUtils::checkStateFromXml( element.attribute( QStringLiteral( "checked" ) ) );
116  bool isExpanded = ( element.attribute( QStringLiteral( "expanded" ), QStringLiteral( "1" ) ) == QLatin1String( "1" ) );
117  QString labelExpression = element.attribute( QStringLiteral( "legend_exp" ) );
118 
119  // needs to have the layer reference resolved later
120  QgsLayerTreeLayer *nodeLayer = new QgsLayerTreeLayer( layerID, layerName, source, providerKey );
121 
122  nodeLayer->readCommonXml( element );
123 
124  nodeLayer->setItemVisibilityChecked( checked != Qt::Unchecked );
125  nodeLayer->setExpanded( isExpanded );
126  nodeLayer->setLabelExpression( labelExpression );
127 
128  const QDomElement patchElem = element.firstChildElement( QStringLiteral( "patch" ) );
129  if ( !patchElem.isNull() )
130  {
131  QgsLegendPatchShape patch;
132  patch.readXml( patchElem, context );
133  nodeLayer->setPatchShape( patch );
134  }
135 
136  nodeLayer->setPatchSize( QgsSymbolLayerUtils::decodeSize( element.attribute( QStringLiteral( "patch_size" ) ) ) );
137 
138  nodeLayer->setLegendSplitBehavior( static_cast< LegendNodesSplitBehavior >( element.attribute( QStringLiteral( "legend_split_behavior" ), QStringLiteral( "0" ) ).toInt() ) );
139 
140  return nodeLayer;
141 }
142 
143 QgsLayerTreeLayer *QgsLayerTreeLayer::readXml( QDomElement &element, const QgsProject *project, const QgsReadWriteContext &context )
144 {
145  QgsLayerTreeLayer *node = readXml( element, context );
146  if ( node )
147  node->resolveReferences( project );
148  return node;
149 }
150 
151 void QgsLayerTreeLayer::writeXml( QDomElement &parentElement, const QgsReadWriteContext &context )
152 {
153  QDomDocument doc = parentElement.ownerDocument();
154  QDomElement elem = doc.createElement( QStringLiteral( "layer-tree-layer" ) );
155  elem.setAttribute( QStringLiteral( "id" ), layerId() );
156  elem.setAttribute( QStringLiteral( "name" ), name() );
157 
158  if ( mRef )
159  {
160  elem.setAttribute( QStringLiteral( "source" ), context.pathResolver().writePath( mRef->publicSource() ) );
161  elem.setAttribute( QStringLiteral( "providerKey" ), mRef->dataProvider() ? mRef->dataProvider()->name() : QString() );
162  }
163 
164  elem.setAttribute( QStringLiteral( "checked" ), mChecked ? QStringLiteral( "Qt::Checked" ) : QStringLiteral( "Qt::Unchecked" ) );
165  elem.setAttribute( QStringLiteral( "expanded" ), mExpanded ? "1" : "0" );
166  elem.setAttribute( QStringLiteral( "legend_exp" ), mLabelExpression );
167 
168  if ( !mPatchShape.isNull() )
169  {
170  QDomElement patchElem = doc.createElement( QStringLiteral( "patch" ) );
171  mPatchShape.writeXml( patchElem, doc, context );
172  elem.appendChild( patchElem );
173  }
174  elem.setAttribute( QStringLiteral( "patch_size" ), QgsSymbolLayerUtils::encodeSize( mPatchSize ) );
175 
176  elem.setAttribute( QStringLiteral( "legend_split_behavior" ), mSplitBehavior );
177 
178  writeCommonXml( elem );
179 
180  parentElement.appendChild( elem );
181 }
182 
183 QString QgsLayerTreeLayer::dump() const
184 {
185  return QStringLiteral( "LAYER: %1 checked=%2 expanded=%3 id=%4\n" ).arg( name() ).arg( mChecked ).arg( mExpanded ).arg( layerId() );
186 }
187 
189 {
190  return new QgsLayerTreeLayer( *this );
191 }
192 
193 void QgsLayerTreeLayer::layerWillBeDeleted()
194 {
195  Q_ASSERT( mRef );
196 
197  emit layerWillBeUnloaded();
198 
199  mLayerName = mRef->name();
200  // in theory we do not even need to do this - the weak ref should clear itself
201  mRef.layer.clear();
202  // layerId stays in the reference
203 
204 }
205 
207 {
208  mUseLayerName = use;
209 }
210 
212 {
213  return mUseLayerName;
214 }
215 
216 void QgsLayerTreeLayer::layerNameChanged()
217 {
218  Q_ASSERT( mRef );
219  emit nameChanged( this, mRef->name() );
220 }
221 
222 void QgsLayerTreeLayer::setLabelExpression( const QString &expression )
223 {
224  mLabelExpression = expression;
225 }
226 
228 {
229  return mPatchShape;
230 }
231 
233 {
234  mPatchShape = shape;
235 }
236 
virtual QString name() const =0
Returns a provider name.
Layer tree node points to a map layer.
QString dump() const override
Returns string with layer tree structure. For debug purposes only.
void resolveReferences(const QgsProject *project, bool looseMatching=false) override
Resolves reference to layer from stored layer ID (if it has not been resolved already)
void writeXml(QDomElement &parentElement, const QgsReadWriteContext &context) override
Write layer tree to XML.
QString layerId() const
Returns the ID for the map layer associated with this node.
QString mLabelExpression
Expression to evaluate in the legend.
void setPatchSize(QSizeF size)
Sets the user (overridden) size for the legend node.
QgsMapLayerRef mRef
Weak reference to the layer (or just it's ID if the reference is not resolved yet)
void layerWillBeUnloaded()
Emitted when a previously available layer got unloaded (from layer registry).
void setName(const QString &n) override
Sets the layer's name.
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
LegendNodesSplitBehavior
Legend node column split behavior.
void setUseLayerName(bool use=true)
Uses the layer's name if use is true, or the name manually set if false.
QgsLegendPatchShape patchShape() const
Returns the symbol patch shape to use when rendering the legend node symbol.
void setLabelExpression(const QString &expression)
set the expression to evaluate
QgsLayerTreeLayer(QgsMapLayer *layer)
bool useLayerName() const
Returns whether the layer's name is used, or the name manually set.
void setPatchShape(const QgsLegendPatchShape &shape)
Sets the symbol patch shape to use when rendering the legend node symbol.
QString name() const override
Returns the layer's name.
void layerLoaded()
Emitted when a previously unavailable layer got loaded.
static QgsLayerTreeLayer * readXml(QDomElement &element, const QgsReadWriteContext &context)
Read layer node from XML.
void setLegendSplitBehavior(LegendNodesSplitBehavior behavior)
Sets the column split behavior for the node.
QString mLayerName
Layer name - only used if layer does not exist or if mUseLayerName is false.
QgsLayerTreeLayer * clone() const override
Create a copy of the node. Returns new instance.
This class is a base class for nodes in a layer tree.
void readCommonXml(QDomElement &element)
Read common XML elements.
void nameChanged(QgsLayerTreeNode *node, QString name)
Emitted when the name of the node is changed.
void setExpanded(bool expanded)
Sets whether the node should be shown as expanded or collapsed in GUI.
void writeCommonXml(QDomElement &element)
Write common XML elements.
bool mExpanded
whether the node should be shown in GUI as expanded
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)
static Qt::CheckState checkStateFromXml(const QString &txt)
Convert QString to Qt::CheckState.
Represents a patch shape for use in map legends.
void readXml(const QDomElement &element, const QgsReadWriteContext &context)
Read settings from a DOM element.
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
void writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Base class for all map layer types.
Definition: qgsmaplayer.h:70
QString name
Definition: qgsmaplayer.h:73
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
void willBeDeleted()
Emitted in the destructor when the layer is about to be deleted, but it is still in a perfectly valid...
void setName(const QString &name)
Set the display name of the layer.
void nameChanged()
Emitted when the name has been changed.
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:99
The class is used as a container of context for various read/write operations on other objects.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
static QString encodeSize(QSizeF size)
Encodes a QSizeF to a string.
static QSizeF decodeSize(const QString &string)
Decodes a QSizeF from a string.
TYPE * resolve(const QgsProject *project)
Resolves the map layer by attempting to find a layer with matching ID within a project.
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
QPointer< TYPE > layer
Weak pointer to map layer.