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