QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgssinglesymbolrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssinglesymbolrendererv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 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 
17 
18 #include "qgssymbolv2.h"
19 #include "qgssymbollayerv2utils.h"
20 
21 #include "qgslogger.h"
22 #include "qgsfeature.h"
23 #include "qgsvectorlayer.h"
24 #include "qgssymbollayerv2.h"
25 
26 #include <QDomDocument>
27 #include <QDomElement>
28 
30  : QgsFeatureRendererV2( "singleSymbol" ), mScaleMethod( DEFAULT_SCALE_METHOD ), mRotationFieldIdx( -1 ),
31  mSizeScaleFieldIdx( -1 ), mTempSymbol( NULL )
32 {
33  Q_ASSERT( symbol );
34  mSymbol = symbol;
35 }
36 
38 {
39  delete mSymbol;
40 }
41 
43 {
44  if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
45  return mSymbol;
46 
47  double rotation = 0;
48  double sizeScale = 1;
49  if ( mRotationFieldIdx != -1 )
50  {
51  rotation = feature.attribute( mRotationFieldIdx ).toDouble();
52  }
53  if ( mSizeScaleFieldIdx != -1 )
54  {
55  sizeScale = feature.attribute( mSizeScaleFieldIdx ).toDouble();
56  }
57 
59  {
60  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol );
61  if ( mRotationFieldIdx != -1 )
62  markerSymbol->setAngle( rotation );
63  if ( mSizeScaleFieldIdx != -1 )
64  markerSymbol->setSize( sizeScale * mOrigSize );
65  markerSymbol->setScaleMethod( mScaleMethod );
66  }
67  else if ( mTempSymbol->type() == QgsSymbolV2::Line )
68  {
69  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol );
70  if ( mSizeScaleFieldIdx != -1 )
71  lineSymbol->setWidth( sizeScale * mOrigSize );
72  }
73  else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
74  {
75  QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol );
76  if ( mRotationFieldIdx != -1 )
77  fillSymbol->setAngle( rotation );
78  }
79 
80  return mTempSymbol;
81 }
82 
84 {
85  if ( !mSymbol )
86  {
87  return;
88  }
89  mRotationFieldIdx = mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField );
91 
92  mSymbol->startRender( context, vlayer );
93 
94  if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
95  {
96  // we are going to need a temporary symbol
98 
99  int hints = 0;
100  if ( mRotationFieldIdx != -1 )
102  if ( mSizeScaleFieldIdx != -1 )
104  mTempSymbol->setRenderHints( hints );
105 
106  mTempSymbol->startRender( context, vlayer );
107 
108  if ( mSymbol->type() == QgsSymbolV2::Marker )
109  {
110  mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol )->size();
111  }
112  else if ( mSymbol->type() == QgsSymbolV2::Line )
113  {
114  mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol )->width();
115  }
116  else
117  {
118  mOrigSize = 0;
119  }
120  }
121 }
122 
124 {
125  if ( !mSymbol )
126  {
127  return;
128  }
129  mSymbol->stopRender( context );
130 
131  if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
132  {
133  // we are going to need a temporary symbol
134  mTempSymbol->stopRender( context );
135  delete mTempSymbol;
136  mTempSymbol = NULL;
137  }
138 }
139 
141 {
142  QSet<QString> attributes;
143  if ( mSymbol )
144  {
145  attributes.unite( mSymbol->usedAttributes() );
146  }
147  if ( !mRotationField.isEmpty() )
148  {
149  attributes.insert( mRotationField );
150  }
151  if ( !mSizeScaleField.isEmpty() )
152  {
153  attributes.insert( mSizeScaleField );
154  }
155  return attributes.toList();
156 }
157 
159 {
160  return mSymbol;
161 }
162 
164 {
165  Q_ASSERT( s );
166  delete mSymbol;
167  mSymbol = s;
168 }
169 
171 {
173  setScaleMethodToSymbol( mSymbol, scaleMethod );
174 }
175 
177 {
178  if ( mSymbol )
179  {
180  return QString( "SINGLE: %1" ).arg( mSymbol->dump() );
181  }
182  else
183  {
184  return "";
185  }
186 }
187 
189 {
194  r->setScaleMethod( scaleMethod() );
195  return r;
196 }
197 
198 void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
199 {
200  QgsStringMap props;
201  if ( !mRotationField.isEmpty() )
202  props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
203  if ( !mSizeScaleField.isEmpty() )
204  props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
205 
206  QDomElement ruleElem = doc.createElement( "se:Rule" );
207  element.appendChild( ruleElem );
208 
209  QDomElement nameElem = doc.createElement( "se:Name" );
210  nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
211  ruleElem.appendChild( nameElem );
212 
213  mSymbol->toSld( doc, ruleElem, props );
214 }
215 
217 {
218  QgsSymbolV2List lst;
219  lst.append( mSymbol );
220  return lst;
221 }
222 
224 {
225  QDomElement symbolsElem = element.firstChildElement( "symbols" );
226  if ( symbolsElem.isNull() )
227  return NULL;
228 
229  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
230 
231  if ( !symbolMap.contains( "0" ) )
232  return NULL;
233 
234  QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( symbolMap.take( "0" ) );
235 
236  // delete symbols if there are any more
238 
239  QDomElement rotationElem = element.firstChildElement( "rotation" );
240  if ( !rotationElem.isNull() )
241  r->setRotationField( rotationElem.attribute( "field" ) );
242 
243  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
244  if ( !sizeScaleElem.isNull() )
245  {
246  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
247  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
248  }
249 
250  // TODO: symbol levels
251  return r;
252 }
253 
255 {
256  // XXX this renderer can handle only one Rule!
257 
258  // get the first Rule element
259  QDomElement ruleElem = element.firstChildElement( "Rule" );
260  if ( ruleElem.isNull() )
261  {
262  QgsDebugMsg( "no Rule elements found!" );
263  return NULL;
264  }
265 
266  QString label, description;
267  QgsSymbolLayerV2List layers;
268 
269  // retrieve the Rule element child nodes
270  QDomElement childElem = ruleElem.firstChildElement();
271  while ( !childElem.isNull() )
272  {
273  if ( childElem.localName() == "Name" )
274  {
275  // <se:Name> tag contains the rule identifier,
276  // so prefer title tag for the label property value
277  if ( label.isEmpty() )
278  label = childElem.firstChild().nodeValue();
279  }
280  else if ( childElem.localName() == "Description" )
281  {
282  // <se:Description> can contains a title and an abstract
283  QDomElement titleElem = childElem.firstChildElement( "Title" );
284  if ( !titleElem.isNull() )
285  {
286  label = titleElem.firstChild().nodeValue();
287  }
288 
289  QDomElement abstractElem = childElem.firstChildElement( "Abstract" );
290  if ( !abstractElem.isNull() )
291  {
292  description = abstractElem.firstChild().nodeValue();
293  }
294  }
295  else if ( childElem.localName() == "Abstract" )
296  {
297  // <sld:Abstract> (v1.0)
298  description = childElem.firstChild().nodeValue();
299  }
300  else if ( childElem.localName() == "Title" )
301  {
302  // <sld:Title> (v1.0)
303  label = childElem.firstChild().nodeValue();
304  }
305  else if ( childElem.localName().endsWith( "Symbolizer" ) )
306  {
307  // create symbol layers for this symbolizer
308  QgsSymbolLayerV2Utils::createSymbolLayerV2ListFromSld( childElem, geomType, layers );
309  }
310 
311  childElem = childElem.nextSiblingElement();
312  }
313 
314  if ( layers.size() == 0 )
315  return NULL;
316 
317  // now create the symbol
319  switch ( geomType )
320  {
321  case QGis::Line:
322  symbol = new QgsLineSymbolV2( layers );
323  break;
324 
325  case QGis::Polygon:
326  symbol = new QgsFillSymbolV2( layers );
327  break;
328 
329  case QGis::Point:
330  symbol = new QgsMarkerSymbolV2( layers );
331  break;
332 
333  default:
334  QgsDebugMsg( QString( "invalid geometry type: found %1" ).arg( geomType ) );
335  return NULL;
336  }
337 
338  // and finally return the new renderer
339  return new QgsSingleSymbolRendererV2( symbol );
340 }
341 
342 QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
343 {
344  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
345  rendererElem.setAttribute( "type", "singleSymbol" );
346  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
347 
349  symbols["0"] = mSymbol;
350  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
351  rendererElem.appendChild( symbolsElem );
352 
353  QDomElement rotationElem = doc.createElement( "rotation" );
354  rotationElem.setAttribute( "field", mRotationField );
355  rendererElem.appendChild( rotationElem );
356 
357  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
358  sizeScaleElem.setAttribute( "field", mSizeScaleField );
359  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
360  rendererElem.appendChild( sizeScaleElem );
361 
362  return rendererElem;
363 }
364 
366 {
368  if ( mSymbol )
369  {
370  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol, iconSize );
371  lst << qMakePair( QString(), pix );
372  }
373  return lst;
374 }
375 
377 {
379  lst << qMakePair( QString(), mSymbol );
380  return lst;
381 }