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