Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgslabel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslabel.cpp - render vector labels
3  -------------------
4  begin : August 2004
5  copyright : (C) 2004 by Radim Blazek
6  email : blazek@itc.it
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include <cmath>
18 #include <limits>
19 
20 #include <QString>
21 #include <QFont>
22 #include <QFontMetrics>
23 
24 #include <QPainter>
25 #include <QDomNode>
26 #include <QDomElement>
27 
28 #include "qgis.h"
29 #include "qgsfeature.h"
30 #include "qgsgeometry.h"
31 #include "qgsfield.h"
32 #include "qgslogger.h"
33 #include "qgsrectangle.h"
34 #include "qgsmaptopixel.h"
35 #include "qgscoordinatetransform.h"
36 #include "qgsrendercontext.h"
37 
38 #include "qgslabelattributes.h"
39 #include "qgslabel.h"
40 
41 // use M_PI define PI 3.141592654
42 #ifdef WIN32
43 #undef M_PI
44 #define M_PI 4*atan(1.0)
45 #endif
46 
47 static const char * const ident_ =
48  "$Id$";
49 
51  : mMinScale( 0 ),
52  mMaxScale( 100000000 ),
53  mScaleBasedVisibility( false )
54 {
55  mField = fields;
57  for ( int i = 0; i < LabelFieldCount; i++ )
58  {
59  mLabelFieldIdx[i] = -1;
60  }
62 }
63 
65 {
66  delete mLabelAttributes;
67 }
68 
69 QString QgsLabel::fieldValue( int attr, QgsFeature &feature )
70 {
71  if ( mLabelFieldIdx[attr] == -1 )
72  {
73  return QString();
74  }
75 
76  const QgsAttributeMap& attrs = feature.attributeMap();
77  QgsAttributeMap::const_iterator it = attrs.find( mLabelFieldIdx[attr] );
78 
79  if ( it != attrs.end() )
80  {
81  return it->toString();
82  }
83  else
84  {
85  return QString();
86  }
87 }
88 
90  QgsFeature &feature, bool selected,
91  QgsLabelAttributes *classAttributes )
92 {
93  if ( mLabelAttributes->selectedOnly() && !selected )
94  return;
95 
96  QPen pen;
97  QFont font;
98  QString value;
99  QString text;
100 
101  /* Calc scale (not nice) */
102  QgsPoint point;
103  point = renderContext.mapToPixel().transform( 0, 0 );
104  double x1 = point.x();
105  point = renderContext.mapToPixel().transform( 1000, 0 );
106  double x2 = point.x();
107  double scale = ( x2 - x1 ) * 0.001;
108 
109  /* Text */
110  value = fieldValue( Text, feature );
111  if ( value.isEmpty() )
112  {
113  text = mLabelAttributes->text();
114  }
115  else
116  {
117  text = value;
118  }
119 
120  /* Font */
121  value = fieldValue( Family, feature );
122  if ( value.isEmpty() )
123  {
124  font.setFamily( mLabelAttributes->family() );
125  }
126  else
127  {
128  font.setFamily( value );
129  }
130 
131  double size;
132  value = fieldValue( Size, feature );
133  if ( value.isEmpty() )
134  {
135  size = mLabelAttributes->size();
136  }
137  else
138  {
139  size = value.toDouble();
140  }
141  int sizeType;
142  value = fieldValue( SizeType, feature );
143  if ( value.isEmpty() )
144  sizeType = mLabelAttributes->sizeType();
145  else
146  {
147  value = value.toLower();
148  if ( value.compare( "mapunits" ) == 0 )
149  sizeType = QgsLabelAttributes::MapUnits;
150  else
152  }
153  if ( sizeType == QgsLabelAttributes::MapUnits )
154  {
155  size *= scale;
156  }
157  else //point units
158  {
159  double sizeMM = size * 0.3527;
160  size = sizeMM * renderContext.scaleFactor();
161  }
162 
163  //Request font larger (multiplied by rasterScaleFactor) as a workaround for the Qt font bug
164  //and scale the painter down by rasterScaleFactor when drawing the label
165  size *= renderContext.rasterScaleFactor();
166 
167  if (( int )size <= 0 )
168  // skip too small labels
169  return;
170 
171  font.setPixelSize( size );
172 
173  value = fieldValue( Color, feature );
174  if ( value.isEmpty() )
175  {
176  pen.setColor( mLabelAttributes->color() );
177  }
178  else
179  {
180  pen.setColor( QColor( value ) );
181  }
182 
183  value = fieldValue( Bold, feature );
184  if ( value.isEmpty() )
185  {
186  font.setBold( mLabelAttributes->bold() );
187  }
188  else
189  {
190  font.setBold(( bool ) value.toInt() );
191  }
192 
193  value = fieldValue( Italic, feature );
194  if ( value.isEmpty() )
195  {
196  font.setItalic( mLabelAttributes->italic() );
197  }
198  else
199  {
200  font.setItalic(( bool ) value.toInt() );
201  }
202 
203  value = fieldValue( Underline, feature );
204  if ( value.isEmpty() )
205  {
206  font.setUnderline( mLabelAttributes->underline() );
207  }
208  else
209  {
210  font.setUnderline(( bool ) value.toInt() );
211  }
212 
213  value = fieldValue( StrikeOut, feature );
214  if ( value.isEmpty() )
215  {
216  font.setStrikeOut( mLabelAttributes->strikeOut() );
217  }
218  else
219  {
220  font.setStrikeOut(( bool ) value.toInt() );
221  }
222 
223  //
224  QgsPoint overridePoint;
225  bool useOverridePoint = false;
226  value = fieldValue( XCoordinate, feature );
227  if ( !value.isEmpty() )
228  {
229  overridePoint.setX( value.toDouble() );
230  useOverridePoint = true;
231  }
232  value = fieldValue( YCoordinate, feature );
233  if ( !value.isEmpty() )
234  {
235  overridePoint.setY( value.toDouble() );
236  useOverridePoint = true;
237  }
238 
239  /* Alignment */
240  int alignment;
241  QFontMetrics fm( font );
242  int width, height;
243 
245  {
246  QStringList texts = text.split( "\n" );
247 
248  width = 0;
249  for ( int i = 0; i < texts.size(); i++ )
250  {
251  int w = fm.width( texts[i] );
252  if ( w > width )
253  width = w;
254  }
255 
256  height = fm.height() * texts.size();
257  }
258  else
259  {
260  width = fm.width( text );
261  height = fm.height();
262  }
263 
264  int dx = 0;
265  int dy = 0;
266 
267  value = fieldValue( Alignment, feature );
268  if ( value.isEmpty() )
269  {
270  alignment = mLabelAttributes->alignment();
271  }
272  else
273  {
274  value = value.toLower();
275 
276  alignment = 0;
277 
278  if ( value.contains( "left" ) )
279  alignment |= Qt::AlignLeft;
280  else if ( value.contains( "right" ) )
281  alignment |= Qt::AlignRight;
282  else
283  alignment |= Qt::AlignHCenter;
284 
285  if ( value.contains( "bottom" ) )
286  alignment |= Qt::AlignBottom;
287  else if ( value.contains( "top" ) )
288  alignment |= Qt::AlignTop;
289  else
290  alignment |= Qt::AlignVCenter;
291  }
292 
293  if ( alignment & Qt::AlignLeft )
294  {
295  dx = 0;
296  }
297  else if ( alignment & Qt::AlignHCenter )
298  {
299  dx = -width / 2;
300  }
301  else if ( alignment & Qt::AlignRight )
302  {
303  dx = -width;
304  }
305 
306  if ( alignment & Qt::AlignBottom )
307  {
308  dy = 0;
309  }
310  else if ( alignment & Qt::AlignVCenter )
311  {
312  dy = height / 2;
313  }
314  else if ( alignment & Qt::AlignTop )
315  {
316  dy = height;
317  }
318 
319  // Offset
320  double xoffset, yoffset;
321  value = fieldValue( XOffset, feature );
322  if ( value.isEmpty() )
323  {
324  xoffset = mLabelAttributes->xOffset();
325  }
326  else
327  {
328  xoffset = value.toDouble();
329  }
330  value = fieldValue( YOffset, feature );
331  if ( value.isEmpty() )
332  {
333  yoffset = mLabelAttributes->yOffset();
334  }
335  else
336  {
337  yoffset = value.toDouble();
338  }
339 
340  // recalc offset to pixels
342  {
343  xoffset *= scale;
344  yoffset *= scale;
345  }
346  else
347  {
348  xoffset = xoffset * 0.3527 * renderContext.scaleFactor();
349  yoffset = yoffset * 0.3527 * renderContext.scaleFactor();
350  }
351 
352  // Angle
353  double ang;
354  value = fieldValue( Angle, feature );
355  if ( value.isEmpty() )
356  {
357  ang = mLabelAttributes->angle();
358  }
359  else
360  {
361  ang = value.toDouble();
362  }
363 
364 
365  // Work out a suitable position to put the label for the
366  // feature. For multi-geometries, put the same label on each
367  // part.
368  if ( useOverridePoint )
369  {
370  renderLabel( renderContext, overridePoint, text, font, pen, dx, dy,
371  xoffset, yoffset, ang, width, height, alignment );
372  }
373  else
374  {
375  std::vector<labelpoint> points;
376  labelPoint( points, feature );
377  for ( uint i = 0; i < points.size(); ++i )
378  {
379  renderLabel( renderContext, points[i].p, text, font, pen, dx, dy,
380  xoffset, yoffset, mLabelAttributes->angleIsAuto() ? points[i].angle : ang, width, height, alignment );
381  }
382  }
383 }
384 
386  QgsPoint point,
387  QString text, QFont font, QPen pen,
388  int dx, int dy,
389  double xoffset, double yoffset,
390  double ang,
391  int width, int height, int alignment )
392 {
393  QPainter *painter = renderContext.painter();
394 
395  // Convert point to projected units
396  if ( renderContext.coordinateTransform() )
397  {
398  try
399  {
400  point = renderContext.coordinateTransform()->transform( point );
401  }
402  catch ( QgsCsException &cse )
403  {
404  Q_UNUSED( cse ); // unused otherwise
405  QgsDebugMsg( "Caught transform error. Skipping rendering this label" );
406  return;
407  }
408  }
409 
410  // and then to canvas units
411  renderContext.mapToPixel().transform( &point );
412  double x = point.x();
413  double y = point.y();
414 
415  double rad = ang * M_PI / 180;
416 
417  x = x + xoffset * cos( rad ) - yoffset * sin( rad );
418  y = y - xoffset * sin( rad ) - yoffset * cos( rad );
419 
420  painter->save();
421  painter->setFont( font );
422  painter->translate( x, y );
423  //correct oversampled font size back by scaling painter down
424  painter->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() );
425  painter->rotate( -ang );
426 
427  //
428  // Draw a buffer behind the text if one is desired
429  //
431  {
432  double myBufferSize = mLabelAttributes->bufferSize() * 0.3527 * renderContext.scaleFactor() * renderContext.rasterScaleFactor();
433  QPen bufferPen;
435  {
436  bufferPen.setColor( mLabelAttributes->bufferColor() );
437  }
438  else //default to a white buffer
439  {
440  bufferPen.setColor( Qt::white );
441  }
442  painter->setPen( bufferPen );
443 
444  double bufferStepSize; //hack to distinguish pixel devices from logical devices
445  if (( renderContext.scaleFactor() - 1 ) > 1.5 )
446  {
447  bufferStepSize = 1;
448  }
449  else //draw more dense in case of logical devices
450  {
451  bufferStepSize = 1 / renderContext.rasterScaleFactor();
452  }
453 
454  for ( double i = dx - myBufferSize; i <= dx + myBufferSize; i += bufferStepSize )
455  {
456  for ( double j = dy - myBufferSize; j <= dy + myBufferSize; j += bufferStepSize )
457  {
459  painter->drawText( QRectF( i, j - height, width, height ), alignment, text );
460  else
461  painter->drawText( QPointF( i, j ), text );
462  }
463  }
464  }
465 
466  painter->setPen( pen );
468  painter->drawText( dx, dy - height, width, height, alignment, text );
469  else
470  painter->drawText( dx, dy, text );
471  painter->restore();
472 }
473 
475 {
476  for ( uint i = 0; i < LabelFieldCount; i++ )
477  {
478  if ( mLabelFieldIdx[i] == -1 )
479  continue;
480  bool found = false;
481  for ( QgsAttributeList::iterator it = fields.begin(); it != fields.end(); ++it )
482  {
483  if ( *it == mLabelFieldIdx[i] )
484  {
485  found = true;
486  break;
487  }
488  }
489  if ( !found )
490  {
491  fields.append( mLabelFieldIdx[i] );
492  }
493  }
494 }
495 
496 void QgsLabel::setFields( const QgsFieldMap & fields )
497 {
498  mField = fields;
499 }
500 
502 {
503  return mField;
504 }
505 
506 void QgsLabel::setLabelField( int attr, int fieldIndex )
507 {
508  if ( attr >= LabelFieldCount )
509  return;
510 
511  mLabelFieldIdx[attr] = fieldIndex;
512 }
513 
514 QString QgsLabel::labelField( int attr ) const
515 {
516  if ( attr > LabelFieldCount )
517  return QString();
518 
519  int fieldIndex = mLabelFieldIdx[attr];
520  return mField[fieldIndex].name();
521 }
522 
524 {
525  return mLabelAttributes;
526 }
527 // @note this will be deprecated use attributes rather
529 {
530  return mLabelAttributes;
531 }
532 
533 void QgsLabel::labelPoint( std::vector<labelpoint>& points, QgsFeature & feature )
534 {
535  QgsGeometry *geometry = feature.geometry();
536  unsigned char *geom = geometry->asWkb();
537  size_t geomlen = geometry->wkbSize();
538  QGis::WkbType wkbType = geometry->wkbType();
539  labelpoint point;
540 
541  switch ( wkbType )
542  {
543  case QGis::WKBPoint25D:
544  case QGis::WKBPoint:
546  case QGis::WKBLineString:
547  case QGis::WKBPolygon25D:
548  case QGis::WKBPolygon:
549  {
550  labelPoint( point, geom, geomlen );
551  points.push_back( point );
552  }
553  break;
554 
556  case QGis::WKBMultiPoint:
561  // Return a position for each individual in the multi-feature
562  {
563  Q_ASSERT( 1 + sizeof( wkbType ) + sizeof( int ) <= geomlen );
564  geom += 1 + sizeof( wkbType );
565  int nFeatures = *( unsigned int * )geom;
566  geom += sizeof( int );
567 
568  unsigned char *feature = geom;
569  for ( int i = 0; i < nFeatures && feature; ++i )
570  {
571  feature = labelPoint( point, feature, geom + geomlen - feature );
572  points.push_back( point );
573  }
574  }
575  break;
576  default:
577  QgsDebugMsg( "Unknown geometry type of " + QString::number( wkbType ) );
578  }
579 }
580 
581 unsigned char* QgsLabel::labelPoint( labelpoint& point, unsigned char *geom, size_t geomlen )
582 {
583  // verify that local types match sizes as WKB spec
584  Q_ASSERT( sizeof( int ) == 4 );
585  Q_ASSERT( sizeof( QGis::WkbType ) == 4 );
586  Q_ASSERT( sizeof( double ) == 8 );
587 
588  if ( geom == NULL )
589  {
590  QgsDebugMsg( "empty wkb" );
591  return NULL;
592  }
593 
594  QGis::WkbType wkbType;
595 #ifndef QT_NO_DEBUG
596  unsigned char *geomend = geom + geomlen;
597 #endif
598  Q_ASSERT( geom + 1 + sizeof( wkbType ) <= geomend );
599 
600  geom++; // skip endianness
601  memcpy( &wkbType, geom, sizeof( wkbType ) );
602  geom += sizeof( wkbType );
603 
604  int dims = 2;
605 
606  switch ( wkbType )
607  {
608  case QGis::WKBPoint25D:
609  case QGis::WKBPoint:
610  {
611  Q_ASSERT( geom + 2*sizeof( double ) <= geomend );
612  double *pts = ( double * )geom;
613  point.p.set( pts[0], pts[1] );
614  point.angle = 0.0;
615  geom += 2 * sizeof( double );
616  }
617  break;
618 
620  dims = 3;
621  case QGis::WKBLineString: // Line center
622  {
623  Q_ASSERT( geom + sizeof( int ) <= geomend );
624  int nPoints = *( unsigned int * )geom;
625  geom += sizeof( int );
626 
627  Q_ASSERT( geom + nPoints*sizeof( double )*dims <= geomend );
628 
629  // get line center
630  double *pts = ( double * )geom;
631  double tl = 0.0;
632  for ( int i = 1; i < nPoints; i++ )
633  {
634  double dx = pts[dims*i] - pts[dims*( i-1 )];
635  double dy = pts[dims*i+1] - pts[dims*( i-1 )+1];
636  tl += sqrt( dx * dx + dy * dy );
637  }
638  tl /= 2.0;
639 
640  // find line center
641  double l = 0.0;
642  for ( int i = 1; i < nPoints; i++ )
643  {
644  double dx = pts[dims*i] - pts[dims*( i-1 )];
645  double dy = pts[dims*i+1] - pts[dims*( i-1 )+1];
646  double dl = sqrt( dx * dx + dy * dy );
647 
648  if ( l + dl > tl )
649  {
650  double k = ( tl - l ) / dl;
651 
652  point.p.set( pts[dims*( i-1 )] + k * dx,
653  pts[dims*( i-1 )+1] + k * dy );
654  point.angle = atan2( dy, dx ) * 180.0 * M_1_PI;
655  break;
656  }
657 
658  l += dl;
659  }
660 
661  geom += nPoints * sizeof( double ) * dims;
662  }
663  break;
664 
665  case QGis::WKBPolygon25D:
666  dims = 3;
667  case QGis::WKBPolygon: // centroid of outer ring
668  {
669  Q_ASSERT( geom + sizeof( int ) <= geomend );
670  int nRings = *( unsigned int * )geom;
671  geom += sizeof( int );
672 
673  for ( int i = 0; i < nRings; ++i )
674  {
675  Q_ASSERT( geom + sizeof( int ) <= geomend );
676  int nPoints = *( unsigned int * )geom;
677  geom += sizeof( int );
678 
679  Q_ASSERT( geom + nPoints*sizeof( double )*dims <= geomend );
680 
681  if ( i == 0 )
682  {
683  double sx = 0.0, sy = 0.0;
684  double *pts = ( double* ) geom;
685  for ( int j = 0; j < nPoints - 1; j++ )
686  {
687  sx += pts[dims*j];
688  sy += pts[dims*j+1];
689  }
690  point.p.set( sx / ( nPoints - 1 ),
691  sy / ( nPoints - 1 ) );
692  point.angle = 0.0;
693  }
694 
695  geom += nPoints * sizeof( double ) * dims;
696  }
697  }
698  break;
699 
700  default:
701  // To get here is a bug because our caller should be filtering
702  // on wkb type.
703  QgsDebugMsg( "unsupported wkb type" );
704  return NULL;
705  }
706 
707  return geom;
708 }
709 
710 bool QgsLabel::readLabelField( QDomElement &el, int attr, QString prefix = "field" )
711 {
712  QString name = prefix + "name";
713 
714  if ( el.hasAttribute( name ) )
715  {
716  name = el.attribute( name );
717 
718  QgsFieldMap::const_iterator field_it = mField.constBegin();
719  for ( ; field_it != mField.constEnd(); ++field_it )
720  {
721  if ( field_it.value().name() == name )
722  {
723  break;
724  }
725  }
726 
727  if ( field_it != mField.constEnd() )
728  {
729  mLabelFieldIdx[attr] = field_it.key();
730  return true;
731  }
732  }
733  else if ( el.hasAttribute( prefix ) )
734  {
735  QString value = el.attribute( prefix );
736  mLabelFieldIdx[attr] = value.isEmpty() ? -1 : value.toInt();
737  return true;
738  }
739 
740  mLabelFieldIdx[attr] = -1;
741  return false;
742 }
743 
744 
745 void QgsLabel::readXML( const QDomNode& node )
746 {
747  QgsDebugMsg( " called for layer label properties, got node " + node.nodeName() );
748 
749  QDomNode scratchNode; // Dom node re-used to get current QgsLabel attribute
750  QDomElement el;
751 
752  int red, green, blue;
753  int type;
754 
755  /* Text */
756  scratchNode = node.namedItem( "label" );
757 
758  if ( scratchNode.isNull() )
759  {
760  QgsDebugMsg( "couldn't find QgsLabel ``label'' attribute" );
761  }
762  else
763  {
764  el = scratchNode.toElement();
765  mLabelAttributes->setText( el.attribute( "text", "" ) );
766  readLabelField( el, Text );
767  }
768 
769  /* Family */
770  scratchNode = node.namedItem( "family" );
771 
772  if ( scratchNode.isNull() )
773  {
774  QgsDebugMsg( "couldn't find QgsLabel ``family'' attribute" );
775  }
776  else
777  {
778  el = scratchNode.toElement();
779  mLabelAttributes->setFamily( el.attribute( "name", "" ) );
780  readLabelField( el, Family );
781  }
782 
783  /* Size */
784  scratchNode = node.namedItem( "size" );
785 
786  if ( scratchNode.isNull() )
787  {
788  QgsDebugMsg( "couldn't find QgsLabel ``size'' attribute" );
789  }
790  else
791  {
792  el = scratchNode.toElement();
793  if ( !el.hasAttribute( "unitfield" ) && !el.hasAttribute( "unitfieldname" ) )
794  {
795  type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
796  mLabelAttributes->setSize( el.attribute( "value", "0.0" ).toDouble(), type );
797  }
798  else
799  {
800  readLabelField( el, SizeType, "unitfield" );
801  }
802  readLabelField( el, Size );
803  }
804 
805  /* Bold */
806  scratchNode = node.namedItem( "bold" );
807 
808  if ( scratchNode.isNull() )
809  {
810  QgsDebugMsg( "couldn't find QgsLabel ``bold'' attribute" );
811  }
812  else
813  {
814  el = scratchNode.toElement();
815  mLabelAttributes->setBold(( bool )el.attribute( "on", "0" ).toInt() );
816  readLabelField( el, Bold );
817  }
818 
819  /* Italic */
820  scratchNode = node.namedItem( "italic" );
821 
822  if ( scratchNode.isNull() )
823  {
824  QgsDebugMsg( "couldn't find QgsLabel ``italic'' attribute" );
825  }
826  else
827  {
828  el = scratchNode.toElement();
829  mLabelAttributes->setItalic(( bool )el.attribute( "on", "0" ).toInt() );
830  readLabelField( el, Italic );
831  }
832 
833  /* Underline */
834  scratchNode = node.namedItem( "underline" );
835 
836  if ( scratchNode.isNull() )
837  {
838  QgsDebugMsg( "couldn't find QgsLabel ``underline'' attribute" );
839  }
840  else
841  {
842  el = scratchNode.toElement();
843  mLabelAttributes->setUnderline(( bool )el.attribute( "on", "0" ).toInt() );
844  readLabelField( el, Underline );
845  }
846 
847  /* Strikeout */
848  scratchNode = node.namedItem( "strikeout" );
849 
850  if ( scratchNode.isNull() )
851  {
852  QgsDebugMsg( "couldn't find QgsLabel ``strikeout'' attribute" );
853  }
854  else
855  {
856  el = scratchNode.toElement();
857  mLabelAttributes->setStrikeOut(( bool )el.attribute( "on", "0" ).toInt() );
858  readLabelField( el, StrikeOut );
859  }
860 
861  /* Color */
862  scratchNode = node.namedItem( "color" );
863 
864  if ( scratchNode.isNull() )
865  {
866  QgsDebugMsg( "couldn't find QgsLabel ``color'' attribute" );
867  }
868  else
869  {
870  el = scratchNode.toElement();
871 
872  red = el.attribute( "red", "0" ).toInt();
873  green = el.attribute( "green", "0" ).toInt();
874  blue = el.attribute( "blue", "0" ).toInt();
875 
876  mLabelAttributes->setColor( QColor( red, green, blue ) );
877 
878  readLabelField( el, Color );
879  }
880 
881  /* X */
882  scratchNode = node.namedItem( "x" );
883 
884  if ( scratchNode.isNull() )
885  {
886  QgsDebugMsg( "couldn't find QgsLabel ``x'' attribute" );
887  }
888  else
889  {
890  el = scratchNode.toElement();
892  }
893 
894  /* Y */
895  scratchNode = node.namedItem( "y" );
896 
897  if ( scratchNode.isNull() )
898  {
899  QgsDebugMsg( "couldn't find QgsLabel ``y'' attribute" );
900  }
901  else
902  {
903  el = scratchNode.toElement();
905  }
906 
907 
908  /* X,Y offset */
909  scratchNode = node.namedItem( "offset" );
910 
911  if ( scratchNode.isNull() )
912  {
913  QgsDebugMsg( "couldn't find QgsLabel ``offset'' attribute" );
914  }
915  else
916  {
917  double xoffset, yoffset;
918 
919  el = scratchNode.toElement();
920 
921  type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
922  xoffset = el.attribute( "x", "0.0" ).toDouble();
923  yoffset = el.attribute( "y", "0.0" ).toDouble();
924 
925  mLabelAttributes->setOffset( xoffset, yoffset, type );
926  readLabelField( el, XOffset, "xfield" );
927  readLabelField( el, YOffset, "yfield" );
928  }
929 
930  /* Angle */
931  scratchNode = node.namedItem( "angle" );
932 
933  if ( scratchNode.isNull() )
934  {
935  QgsDebugMsg( "couldn't find QgsLabel ``angle'' attribute" );
936  }
937  else
938  {
939  el = scratchNode.toElement();
940  mLabelAttributes->setAngle( el.attribute( "value", "0.0" ).toDouble() );
941  readLabelField( el, Angle );
942  mLabelAttributes->setAutoAngle( el.attribute( "auto", "0" ) == "1" );
943  }
944 
945  /* Alignment */
946  scratchNode = node.namedItem( "alignment" );
947 
948  if ( scratchNode.isNull() )
949  {
950  QgsDebugMsg( "couldn't find QgsLabel ``alignment'' attribute" );
951  }
952  else
953  {
954  el = scratchNode.toElement();
955  mLabelAttributes->setAlignment( QgsLabelAttributes::alignmentCode( el.attribute( "value", "" ) ) );
956  readLabelField( el, Alignment );
957  }
958 
959 
960  // Buffer
961  scratchNode = node.namedItem( "buffercolor" );
962 
963  if ( scratchNode.isNull() )
964  {
965  QgsDebugMsg( "couldn't find QgsLabel ``buffercolor'' attribute" );
966  }
967  else
968  {
969  el = scratchNode.toElement();
970 
971  red = el.attribute( "red", "0" ).toInt();
972  green = el.attribute( "green", "0" ).toInt();
973  blue = el.attribute( "blue", "0" ).toInt();
974 
975  mLabelAttributes->setBufferColor( QColor( red, green, blue ) );
977  }
978 
979  scratchNode = node.namedItem( "buffersize" );
980 
981  if ( scratchNode.isNull() )
982  {
983  QgsDebugMsg( "couldn't find QgsLabel ``bffersize'' attribute" );
984  }
985  else
986  {
987  el = scratchNode.toElement();
988 
989  type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
990  mLabelAttributes->setBufferSize( el.attribute( "value", "0.0" ).toDouble(), type );
991  readLabelField( el, BufferSize );
992  }
993 
994  scratchNode = node.namedItem( "bufferenabled" );
995 
996  if ( scratchNode.isNull() )
997  {
998  QgsDebugMsg( "couldn't find QgsLabel ``bufferenabled'' attribute" );
999  }
1000  else
1001  {
1002  el = scratchNode.toElement();
1003 
1004  mLabelAttributes->setBufferEnabled(( bool )el.attribute( "on", "0" ).toInt() );
1006  }
1007 
1008  scratchNode = node.namedItem( "multilineenabled" );
1009 
1010  if ( scratchNode.isNull() )
1011  {
1012  QgsDebugMsg( "couldn't find QgsLabel ``multilineenabled'' attribute" );
1013  }
1014  else
1015  {
1016  el = scratchNode.toElement();
1017 
1018  mLabelAttributes->setMultilineEnabled(( bool )el.attribute( "on", "0" ).toInt() );
1020  }
1021 
1022  scratchNode = node.namedItem( "selectedonly" );
1023 
1024  if ( scratchNode.isNull() )
1025  {
1026  QgsDebugMsg( "couldn't find QgsLabel ``selectedonly'' attribute" );
1027  }
1028  else
1029  {
1030  el = scratchNode.toElement();
1031  mLabelAttributes->setSelectedOnly(( bool )el.attribute( "on", "0" ).toInt() );
1032  }
1033 
1034 } // QgsLabel::readXML()
1035 
1036 
1037 
1038 void QgsLabel::writeXML( QDomNode & layer_node, QDomDocument & document ) const
1039 {
1040  QDomElement labelattributes = document.createElement( "labelattributes" );
1041 
1042  // Text
1043  QDomElement label = document.createElement( "label" );
1044  label.setAttribute( "text", mLabelAttributes->text() );
1045  if ( mLabelAttributes->textIsSet() && mLabelFieldIdx[Text] != -1 )
1046  {
1047  label.setAttribute( "fieldname", labelField( Text ) );
1048  }
1049  else
1050  {
1051  label.setAttribute( "fieldname", "" );
1052  }
1053  labelattributes.appendChild( label );
1054 
1055  // Family
1056  QDomElement family = document.createElement( "family" );
1057  if ( mLabelAttributes->familyIsSet() && !mLabelAttributes->family().isNull() )
1058  {
1059  if ( mLabelFieldIdx[Family] != -1 )
1060  {
1061  family.setAttribute( "name", mLabelAttributes->family() );
1062  family.setAttribute( "fieldname", labelField( Family ) );
1063  }
1064  else
1065  {
1066  family.setAttribute( "name", mLabelAttributes->family() );
1067  family.setAttribute( "fieldname", "" );
1068  }
1069  }
1070  else
1071  {
1072  family.setAttribute( "name", "Arial" );
1073  family.setAttribute( "fieldname", "" );
1074  }
1075  labelattributes.appendChild( family );
1076 
1077  // size and units
1078  QDomElement size = document.createElement( "size" );
1079  size.setAttribute( "value", mLabelAttributes->size() );
1080  if ( mLabelAttributes->sizeIsSet() )
1081  {
1082  if ( mLabelFieldIdx[Size] != -1 )
1083  {
1084  if ( mLabelFieldIdx[SizeType] != -1 )
1085  {
1086  size.setAttribute( "unitfieldname", labelField( SizeType ) );
1087  }
1088  else
1089  {
1090  size.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->sizeType() ) );
1091  }
1092  size.setAttribute( "fieldname", labelField( Size ) );
1093  }
1094  else
1095  {
1096  size.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->sizeType() ) );
1097  size.setAttribute( "fieldname", "" );
1098  }
1099  }
1100  else
1101  {
1102  size.setAttribute( "value", "12" );
1103  size.setAttribute( "units", "Points" );
1104  size.setAttribute( "fieldname", "" );
1105  }
1106  labelattributes.appendChild( size );
1107 
1108  // bold
1109  QDomElement bold = document.createElement( "bold" );
1110  if ( mLabelAttributes->boldIsSet() )
1111  {
1112  bold.setAttribute( "on", mLabelAttributes->bold() );
1113  if ( mLabelFieldIdx[Bold] != -1 )
1114  {
1115  bold.setAttribute( "fieldname", labelField( Bold ) );
1116  }
1117  else
1118  {
1119  bold.setAttribute( "fieldname", "" );
1120  }
1121  }
1122  else
1123  {
1124  bold.setAttribute( "on", 0 );
1125  bold.setAttribute( "fieldname", 0 );
1126  }
1127  labelattributes.appendChild( bold );
1128 
1129  // italics
1130  QDomElement italic = document.createElement( "italic" );
1131  if ( mLabelAttributes->italicIsSet() )
1132  {
1133  italic.setAttribute( "on", mLabelAttributes->italic() );
1134  if ( mLabelFieldIdx[Italic] != -1 )
1135  {
1136  italic.setAttribute( "fieldname", labelField( Italic ) );
1137  }
1138  else
1139  {
1140  italic.setAttribute( "fieldname", "" );
1141  }
1142  }
1143  else
1144  {
1145  italic.setAttribute( "on", "0" );
1146  italic.setAttribute( "fieldname", "" );
1147  }
1148  labelattributes.appendChild( italic );
1149 
1150  // underline
1151  QDomElement underline = document.createElement( "underline" );
1153  {
1154  underline.setAttribute( "on", mLabelAttributes->underline() );
1155  if ( mLabelFieldIdx[Underline] != -1 )
1156  {
1157  underline.setAttribute( "fieldname", labelField( Underline ) );
1158  }
1159  else
1160  {
1161  underline.setAttribute( "fieldname", "" );
1162  }
1163  }
1164  else
1165  {
1166  underline.setAttribute( "on", 0 );
1167  underline.setAttribute( "fieldname", "" );
1168  }
1169  labelattributes.appendChild( underline );
1170 
1171  // strikeout
1172  QDomElement strikeOut = document.createElement( "strikeout" );
1174  {
1175  strikeOut.setAttribute( "on", mLabelAttributes->strikeOut() );
1176  if ( mLabelFieldIdx[StrikeOut] != -1 )
1177  {
1178  strikeOut.setAttribute( "fieldname", labelField( StrikeOut ) );
1179  }
1180  else
1181  {
1182  strikeOut.setAttribute( "fieldname", "" );
1183  }
1184  }
1185  else
1186  {
1187  strikeOut.setAttribute( "on", 0 );
1188  strikeOut.setAttribute( "fieldname", "" );
1189  }
1190  labelattributes.appendChild( strikeOut );
1191 
1192  // color
1193  QDomElement color = document.createElement( "color" );
1194  if ( mLabelAttributes->colorIsSet() )
1195  {
1196  color.setAttribute( "red", mLabelAttributes->color().red() );
1197  color.setAttribute( "green", mLabelAttributes->color().green() );
1198  color.setAttribute( "blue", mLabelAttributes->color().blue() );
1199  if ( mLabelFieldIdx[Color] != -1 )
1200  {
1201  color.setAttribute( "fieldname", labelField( Color ) );
1202  }
1203  else
1204  {
1205  color.setAttribute( "fieldname", "" );
1206  }
1207  }
1208  else
1209  {
1210  color.setAttribute( "red", 0 );
1211  color.setAttribute( "green", 0 );
1212  color.setAttribute( "blue", 0 );
1213  color.setAttribute( "fieldname", "" );
1214  }
1215  labelattributes.appendChild( color );
1216 
1217  /* X */
1218  QDomElement x = document.createElement( "x" );
1219  if ( mLabelFieldIdx[XCoordinate] != -1 )
1220  {
1221  x.setAttribute( "fieldname", labelField( XCoordinate ) );
1222  }
1223  else
1224  {
1225  x.setAttribute( "fieldname", "" );
1226  }
1227  labelattributes.appendChild( x );
1228 
1229  /* Y */
1230  QDomElement y = document.createElement( "y" );
1231  if ( mLabelFieldIdx[YCoordinate] != -1 )
1232  {
1233  y.setAttribute( "fieldname", labelField( YCoordinate ) );
1234  }
1235  else
1236  {
1237  y.setAttribute( "fieldname", "" );
1238  }
1239  labelattributes.appendChild( y );
1240 
1241  // offset
1242  if ( mLabelAttributes->offsetIsSet() )
1243  {
1244  QDomElement offset = document.createElement( "offset" );
1245  offset.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->offsetType() ) );
1246  offset.setAttribute( "x", mLabelAttributes->xOffset() );
1247  offset.setAttribute( "xfieldname", labelField( XOffset ) );
1248  offset.setAttribute( "y", mLabelAttributes->yOffset() );
1249  offset.setAttribute( "yfieldname", labelField( YOffset ) );
1250  labelattributes.appendChild( offset );
1251  }
1252 
1253  // Angle
1254  QDomElement angle = document.createElement( "angle" );
1255  if ( mLabelAttributes->angleIsSet() )
1256  {
1257  angle.setAttribute( "value", mLabelAttributes->angle() );
1258  if ( mLabelFieldIdx[Angle] != -1 )
1259  {
1260  angle.setAttribute( "fieldname", labelField( Angle ) );
1261  }
1262  else
1263  {
1264  angle.setAttribute( "fieldname", "" );
1265  }
1266  }
1267  else
1268  {
1269  angle.setAttribute( "value", "" );
1270  angle.setAttribute( "fieldname", "" );
1271  }
1272  angle.setAttribute( "auto", mLabelAttributes->angleIsAuto() ? "1" : "0" );
1273  labelattributes.appendChild( angle );
1274 
1275  // alignment
1277  {
1278  QDomElement alignment = document.createElement( "alignment" );
1279  alignment.setAttribute( "value", QgsLabelAttributes::alignmentName( mLabelAttributes->alignment() ) );
1280  alignment.setAttribute( "fieldname", labelField( Alignment ) );
1281  labelattributes.appendChild( alignment );
1282  }
1283 
1284  // buffer color
1285  QDomElement buffercolor = document.createElement( "buffercolor" );
1287  {
1288  buffercolor.setAttribute( "red", mLabelAttributes->bufferColor().red() );
1289  buffercolor.setAttribute( "green", mLabelAttributes->bufferColor().green() );
1290  buffercolor.setAttribute( "blue", mLabelAttributes->bufferColor().blue() );
1291  if ( mLabelFieldIdx[BufferColor] != -1 )
1292  {
1293  buffercolor.setAttribute( "fieldname", labelField( BufferColor ) );
1294  }
1295  else
1296  {
1297  buffercolor.setAttribute( "fieldname", "" );
1298  }
1299  }
1300  else
1301  {
1302  buffercolor.setAttribute( "red", "" );
1303  buffercolor.setAttribute( "green", "" );
1304  buffercolor.setAttribute( "blue", "" );
1305  buffercolor.setAttribute( "fieldname", "" );
1306  }
1307  labelattributes.appendChild( buffercolor );
1308 
1309  // buffer size
1310  QDomElement buffersize = document.createElement( "buffersize" );
1312  {
1313  buffersize.setAttribute( "value", mLabelAttributes->bufferSize() );
1314  buffersize.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->bufferSizeType() ) );
1315  if ( mLabelFieldIdx[BufferSize] != -1 )
1316  {
1317  buffersize.setAttribute( "fieldname", labelField( BufferSize ) );
1318  }
1319  else
1320  {
1321  buffersize.setAttribute( "fieldname", "" );
1322  }
1323  }
1324  else
1325  {
1326  buffersize.setAttribute( "value", "" );
1327  buffersize.setAttribute( "units", "" );
1328  buffersize.setAttribute( "fieldname", "" );
1329  }
1330  labelattributes.appendChild( buffersize );
1331 
1332  // buffer enabled
1333  QDomElement bufferenabled = document.createElement( "bufferenabled" );
1335  {
1336  bufferenabled.setAttribute( "on", mLabelAttributes->bufferEnabled() );
1337  if ( mLabelFieldIdx[BufferEnabled] != -1 )
1338  {
1339  bufferenabled.setAttribute( "fieldname", labelField( BufferEnabled ) );
1340  }
1341  else
1342  {
1343  bufferenabled.setAttribute( "fieldname", "" );
1344  }
1345  }
1346  else
1347  {
1348  bufferenabled.setAttribute( "on", "" );
1349  bufferenabled.setAttribute( "fieldname", "" );
1350  }
1351  labelattributes.appendChild( bufferenabled );
1352 
1353  // multiline enabled
1354  QDomElement multilineenabled = document.createElement( "multilineenabled" );
1356  {
1357  multilineenabled.setAttribute( "on", mLabelAttributes->multilineEnabled() );
1358  if ( mLabelFieldIdx[MultilineEnabled] != -1 )
1359  {
1360  multilineenabled.setAttribute( "fieldname", labelField( MultilineEnabled ) );
1361  }
1362  else
1363  {
1364  multilineenabled.setAttribute( "fieldname", "" );
1365  }
1366  }
1367  else
1368  {
1369  multilineenabled.setAttribute( "on", "" );
1370  multilineenabled.setAttribute( "fieldname", "" );
1371  }
1372  labelattributes.appendChild( multilineenabled );
1373 
1374  QDomElement selectedonly = document.createElement( "selectedonly" );
1375  if ( mLabelAttributes->selectedOnly() )
1376  {
1377  selectedonly.setAttribute( "on", mLabelAttributes->selectedOnly() );
1378  }
1379  else
1380  {
1381  selectedonly.setAttribute( "on", "" );
1382  }
1383  labelattributes.appendChild( selectedonly );
1384 
1385  layer_node.appendChild( labelattributes );
1386 }
1387 
1388 void QgsLabel::setScaleBasedVisibility( bool theVisibilityFlag )
1389 {
1390  mScaleBasedVisibility = theVisibilityFlag;
1391 }
1392 
1394 {
1395  return mScaleBasedVisibility;
1396 }
1397 
1398 void QgsLabel::setMinScale( float theMinScale )
1399 {
1400  mMinScale = theMinScale;
1401 }
1402 
1403 float QgsLabel::minScale() const
1404 {
1405  return mMinScale;
1406 }
1407 
1408 void QgsLabel::setMaxScale( float theMaxScale )
1409 {
1410  mMaxScale = theMaxScale;
1411 }
1412 
1413 float QgsLabel::maxScale() const
1414 {
1415  return mMaxScale;
1416 }