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 
QgsLayerTreeLayer(QgsMapLayer * layer)24 QgsLayerTreeLayer::QgsLayerTreeLayer( QgsMapLayer *layer )
25   : QgsLayerTreeNode( NodeLayer, true )
26   , mRef( layer )
27   , mLayerName( layer->name() )
28 {
29   attachToLayer();
30 }
31 
QgsLayerTreeLayer(const QString & layerId,const QString & name,const QString & source,const QString & provider)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 
QgsLayerTreeLayer(const QgsLayerTreeLayer & other)39 QgsLayerTreeLayer::QgsLayerTreeLayer( const QgsLayerTreeLayer &other )
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 
resolveReferences(const QgsProject * project,bool looseMatching)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 
attachToLayer()71 void QgsLayerTreeLayer::attachToLayer()
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 
name() const81 QString QgsLayerTreeLayer::name() const
82 {
83   return ( mRef && mUseLayerName ) ? mRef->name() : mLayerName;
84 }
85 
setName(const QString & n)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 
readXml(QDomElement & element,const QgsReadWriteContext & context)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 
readXml(QDomElement & element,const QgsProject * project,const QgsReadWriteContext & context)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 
writeXml(QDomElement & parentElement,const QgsReadWriteContext & context)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 
dump() const183 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 
clone() const188 QgsLayerTreeLayer *QgsLayerTreeLayer::clone() const
189 {
190   return new QgsLayerTreeLayer( *this );
191 }
192 
layerWillBeDeleted()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 
setUseLayerName(const bool use)206 void QgsLayerTreeLayer::setUseLayerName( const bool use )
207 {
208   mUseLayerName = use;
209 }
210 
useLayerName() const211 bool QgsLayerTreeLayer::useLayerName() const
212 {
213   return mUseLayerName;
214 }
215 
layerNameChanged()216 void QgsLayerTreeLayer::layerNameChanged()
217 {
218   Q_ASSERT( mRef );
219   emit nameChanged( this, mRef->name() );
220 }
221 
setLabelExpression(const QString & expression)222 void QgsLayerTreeLayer::setLabelExpression( const QString &expression )
223 {
224   mLabelExpression = expression;
225 }
226 
patchShape() const227 QgsLegendPatchShape QgsLayerTreeLayer::patchShape() const
228 {
229   return mPatchShape;
230 }
231 
setPatchShape(const QgsLegendPatchShape & shape)232 void QgsLayerTreeLayer::setPatchShape( const QgsLegendPatchShape &shape )
233 {
234   mPatchShape = shape;
235 }
236 
237