Quantum GIS API Documentation  1.7.4
src/core/qgslabel.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgslabel.cpp - render vector labels
00003                              -------------------
00004     begin                : August 2004
00005     copyright            : (C) 2004 by Radim Blazek
00006     email                : blazek@itc.it
00007  ***************************************************************************/
00008 /***************************************************************************
00009  *                                                                         *
00010  *   This program is free software; you can redistribute it and/or modify  *
00011  *   it under the terms of the GNU General Public License as published by  *
00012  *   the Free Software Foundation; either version 2 of the License, or     *
00013  *   (at your option) any later version.                                   *
00014  *                                                                         *
00015  ***************************************************************************/
00016 
00017 #include <cmath>
00018 #include <limits>
00019 
00020 #include <QString>
00021 #include <QFont>
00022 #include <QFontMetrics>
00023 
00024 #include <QPainter>
00025 #include <QDomNode>
00026 #include <QDomElement>
00027 
00028 #include "qgis.h"
00029 #include "qgsfeature.h"
00030 #include "qgsgeometry.h"
00031 #include "qgsfield.h"
00032 #include "qgslogger.h"
00033 #include "qgsrectangle.h"
00034 #include "qgsmaptopixel.h"
00035 #include "qgscoordinatetransform.h"
00036 #include "qgsrendercontext.h"
00037 
00038 #include "qgslabelattributes.h"
00039 #include "qgslabel.h"
00040 
00041 // use M_PI define PI 3.141592654
00042 #ifdef WIN32
00043 #undef M_PI
00044 #define M_PI 4*atan(1.0)
00045 #endif
00046 
00047 static const char * const ident_ =
00048   "$Id$";
00049 
00050 QgsLabel::QgsLabel( const QgsFieldMap & fields )
00051     : mMinScale( 0 ),
00052     mMaxScale( 100000000 ),
00053     mScaleBasedVisibility( false )
00054 {
00055   mField = fields;
00056   mLabelFieldIdx.resize( LabelFieldCount );
00057   for ( int i = 0; i < LabelFieldCount; i++ )
00058   {
00059     mLabelFieldIdx[i] = -1;
00060   }
00061   mLabelAttributes = new QgsLabelAttributes( true );
00062 }
00063 
00064 QgsLabel::~QgsLabel()
00065 {
00066   delete mLabelAttributes;
00067 }
00068 
00069 QString QgsLabel::fieldValue( int attr, QgsFeature &feature )
00070 {
00071   if ( mLabelFieldIdx[attr] == -1 )
00072   {
00073     return QString();
00074   }
00075 
00076   const QgsAttributeMap& attrs = feature.attributeMap();
00077   QgsAttributeMap::const_iterator it = attrs.find( mLabelFieldIdx[attr] );
00078 
00079   if ( it != attrs.end() )
00080   {
00081     return it->toString();
00082   }
00083   else
00084   {
00085     return QString();
00086   }
00087 }
00088 
00089 void QgsLabel::renderLabel( QgsRenderContext &renderContext,
00090                             QgsFeature &feature, bool selected,
00091                             QgsLabelAttributes *classAttributes )
00092 {
00093   if ( mLabelAttributes->selectedOnly() && !selected )
00094     return;
00095 
00096   QPen pen;
00097   QFont font;
00098   QString value;
00099   QString text;
00100 
00101   /* Calc scale (not nice) */
00102   QgsPoint point;
00103   point = renderContext.mapToPixel().transform( 0, 0 );
00104   double x1 = point.x();
00105   point = renderContext.mapToPixel().transform( 1000, 0 );
00106   double x2 = point.x();
00107   double scale = ( x2 - x1 ) * 0.001;
00108 
00109   /* Text */
00110   value = fieldValue( Text, feature );
00111   if ( value.isEmpty() )
00112   {
00113     text = mLabelAttributes->text();
00114   }
00115   else
00116   {
00117     text = value;
00118   }
00119 
00120   /* Font */
00121   value = fieldValue( Family, feature );
00122   if ( value.isEmpty() )
00123   {
00124     font.setFamily( mLabelAttributes->family() );
00125   }
00126   else
00127   {
00128     font.setFamily( value );
00129   }
00130 
00131   double size;
00132   value = fieldValue( Size, feature );
00133   if ( value.isEmpty() )
00134   {
00135     size =  mLabelAttributes->size();
00136   }
00137   else
00138   {
00139     size =  value.toDouble();
00140   }
00141   int sizeType;
00142   value = fieldValue( SizeType, feature );
00143   if ( value.isEmpty() )
00144     sizeType = mLabelAttributes->sizeType();
00145   else
00146   {
00147     value = value.toLower();
00148     if ( value.compare( "mapunits" ) == 0 )
00149       sizeType = QgsLabelAttributes::MapUnits;
00150     else
00151       sizeType = QgsLabelAttributes::PointUnits;
00152   }
00153   if ( sizeType == QgsLabelAttributes::MapUnits )
00154   {
00155     size *= scale;
00156   }
00157   else //point units
00158   {
00159     double sizeMM = size * 0.3527;
00160     size = sizeMM * renderContext.scaleFactor();
00161   }
00162 
00163   //Request font larger (multiplied by rasterScaleFactor) as a workaround for the Qt font bug
00164   //and scale the painter down by rasterScaleFactor when drawing the label
00165   size *= renderContext.rasterScaleFactor();
00166 
00167   if (( int )size <= 0 )
00168     // skip too small labels
00169     return;
00170 
00171   font.setPixelSize( size );
00172 
00173   value = fieldValue( Color, feature );
00174   if ( value.isEmpty() )
00175   {
00176     pen.setColor( mLabelAttributes->color() );
00177   }
00178   else
00179   {
00180     pen.setColor( QColor( value ) );
00181   }
00182 
00183   value = fieldValue( Bold, feature );
00184   if ( value.isEmpty() )
00185   {
00186     font.setBold( mLabelAttributes->bold() );
00187   }
00188   else
00189   {
00190     font.setBold(( bool ) value.toInt() );
00191   }
00192 
00193   value = fieldValue( Italic, feature );
00194   if ( value.isEmpty() )
00195   {
00196     font.setItalic( mLabelAttributes->italic() );
00197   }
00198   else
00199   {
00200     font.setItalic(( bool ) value.toInt() );
00201   }
00202 
00203   value = fieldValue( Underline, feature );
00204   if ( value.isEmpty() )
00205   {
00206     font.setUnderline( mLabelAttributes->underline() );
00207   }
00208   else
00209   {
00210     font.setUnderline(( bool ) value.toInt() );
00211   }
00212 
00213   value = fieldValue( StrikeOut, feature );
00214   if ( value.isEmpty() )
00215   {
00216     font.setStrikeOut( mLabelAttributes->strikeOut() );
00217   }
00218   else
00219   {
00220     font.setStrikeOut(( bool ) value.toInt() );
00221   }
00222 
00223   //
00224   QgsPoint overridePoint;
00225   bool useOverridePoint = false;
00226   value = fieldValue( XCoordinate, feature );
00227   if ( !value.isEmpty() )
00228   {
00229     overridePoint.setX( value.toDouble() );
00230     useOverridePoint = true;
00231   }
00232   value = fieldValue( YCoordinate, feature );
00233   if ( !value.isEmpty() )
00234   {
00235     overridePoint.setY( value.toDouble() );
00236     useOverridePoint = true;
00237   }
00238 
00239   /* Alignment */
00240   int alignment;
00241   QFontMetrics fm( font );
00242   int width, height;
00243 
00244   if ( mLabelAttributes->multilineEnabled() )
00245   {
00246     QStringList texts = text.split( "\n" );
00247 
00248     width = 0;
00249     for ( int i = 0; i < texts.size(); i++ )
00250     {
00251       int w = fm.width( texts[i] );
00252       if ( w > width )
00253         width = w;
00254     }
00255 
00256     height = fm.height() * texts.size();
00257   }
00258   else
00259   {
00260     width = fm.width( text );
00261     height = fm.height();
00262   }
00263 
00264   int dx = 0;
00265   int dy = 0;
00266 
00267   value = fieldValue( Alignment, feature );
00268   if ( value.isEmpty() )
00269   {
00270     alignment = mLabelAttributes->alignment();
00271   }
00272   else
00273   {
00274     value = value.toLower();
00275 
00276     alignment = 0;
00277 
00278     if ( value.contains( "left" ) )
00279       alignment |= Qt::AlignLeft;
00280     else if ( value.contains( "right" ) )
00281       alignment |= Qt::AlignRight;
00282     else
00283       alignment |= Qt::AlignHCenter;
00284 
00285     if ( value.contains( "bottom" ) )
00286       alignment |= Qt::AlignBottom;
00287     else if ( value.contains( "top" ) )
00288       alignment |= Qt::AlignTop;
00289     else
00290       alignment |= Qt::AlignVCenter;
00291   }
00292 
00293   if ( alignment & Qt::AlignLeft )
00294   {
00295     dx = 0;
00296   }
00297   else if ( alignment & Qt::AlignHCenter )
00298   {
00299     dx = -width / 2;
00300   }
00301   else if ( alignment & Qt::AlignRight )
00302   {
00303     dx = -width;
00304   }
00305 
00306   if ( alignment & Qt::AlignBottom )
00307   {
00308     dy = 0;
00309   }
00310   else if ( alignment & Qt::AlignVCenter )
00311   {
00312     dy = height / 2;
00313   }
00314   else if ( alignment & Qt::AlignTop )
00315   {
00316     dy = height;
00317   }
00318 
00319   // Offset
00320   double xoffset, yoffset;
00321   value = fieldValue( XOffset, feature );
00322   if ( value.isEmpty() )
00323   {
00324     xoffset = mLabelAttributes->xOffset();
00325   }
00326   else
00327   {
00328     xoffset = value.toDouble();
00329   }
00330   value = fieldValue( YOffset, feature );
00331   if ( value.isEmpty() )
00332   {
00333     yoffset = mLabelAttributes->yOffset();
00334   }
00335   else
00336   {
00337     yoffset = value.toDouble();
00338   }
00339 
00340   // recalc offset to pixels
00341   if ( mLabelAttributes->offsetType() == QgsLabelAttributes::MapUnits )
00342   {
00343     xoffset *= scale;
00344     yoffset *= scale;
00345   }
00346   else
00347   {
00348     xoffset = xoffset * 0.3527 * renderContext.scaleFactor();
00349     yoffset = yoffset * 0.3527 * renderContext.scaleFactor();
00350   }
00351 
00352   // Angle
00353   double ang;
00354   value = fieldValue( Angle, feature );
00355   if ( value.isEmpty() )
00356   {
00357     ang = mLabelAttributes->angle();
00358   }
00359   else
00360   {
00361     ang = value.toDouble();
00362   }
00363 
00364 
00365   // Work out a suitable position to put the label for the
00366   // feature. For multi-geometries, put the same label on each
00367   // part.
00368   if ( useOverridePoint )
00369   {
00370     renderLabel( renderContext, overridePoint, text, font, pen, dx, dy,
00371                  xoffset, yoffset, ang, width, height, alignment );
00372   }
00373   else
00374   {
00375     std::vector<labelpoint> points;
00376     labelPoint( points, feature );
00377     for ( uint i = 0; i < points.size(); ++i )
00378     {
00379       renderLabel( renderContext, points[i].p, text, font, pen, dx, dy,
00380                    xoffset, yoffset, mLabelAttributes->angleIsAuto() ? points[i].angle : ang, width, height, alignment );
00381     }
00382   }
00383 }
00384 
00385 void QgsLabel::renderLabel( QgsRenderContext &renderContext,
00386                             QgsPoint point,
00387                             QString text, QFont font, QPen pen,
00388                             int dx, int dy,
00389                             double xoffset, double yoffset,
00390                             double ang,
00391                             int width, int height, int alignment )
00392 {
00393   QPainter *painter = renderContext.painter();
00394 
00395   // Convert point to projected units
00396   if ( renderContext.coordinateTransform() )
00397   {
00398     try
00399     {
00400       point = renderContext.coordinateTransform()->transform( point );
00401     }
00402     catch ( QgsCsException &cse )
00403     {
00404       Q_UNUSED( cse ); // unused otherwise
00405       QgsDebugMsg( "Caught transform error. Skipping rendering this label" );
00406       return;
00407     }
00408   }
00409 
00410   // and then to canvas units
00411   renderContext.mapToPixel().transform( &point );
00412   double x = point.x();
00413   double y = point.y();
00414 
00415   double rad = ang * M_PI / 180;
00416 
00417   x = x + xoffset * cos( rad ) - yoffset * sin( rad );
00418   y = y - xoffset * sin( rad ) - yoffset * cos( rad );
00419 
00420   painter->save();
00421   painter->setFont( font );
00422   painter->translate( x, y );
00423   //correct oversampled font size back by scaling painter down
00424   painter->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() );
00425   painter->rotate( -ang );
00426 
00427   //
00428   // Draw a buffer behind the text if one is desired
00429   //
00430   if ( mLabelAttributes->bufferSizeIsSet() && mLabelAttributes->bufferEnabled() )
00431   {
00432     double myBufferSize = mLabelAttributes->bufferSize() * 0.3527 * renderContext.scaleFactor() * renderContext.rasterScaleFactor();
00433     QPen bufferPen;
00434     if ( mLabelAttributes->bufferColorIsSet() )
00435     {
00436       bufferPen.setColor( mLabelAttributes->bufferColor() );
00437     }
00438     else //default to a white buffer
00439     {
00440       bufferPen.setColor( Qt::white );
00441     }
00442     painter->setPen( bufferPen );
00443 
00444     double bufferStepSize; //hack to distinguish pixel devices from logical devices
00445     if (( renderContext.scaleFactor() - 1 ) > 1.5 )
00446     {
00447       bufferStepSize = 1;
00448     }
00449     else //draw more dense in case of logical devices
00450     {
00451       bufferStepSize = 1 / renderContext.rasterScaleFactor();
00452     }
00453 
00454     for ( double i = dx - myBufferSize; i <= dx + myBufferSize; i += bufferStepSize )
00455     {
00456       for ( double j = dy - myBufferSize; j <= dy + myBufferSize; j += bufferStepSize )
00457       {
00458         if ( mLabelAttributes->multilineEnabled() )
00459           painter->drawText( QRectF( i, j - height, width, height ), alignment, text );
00460         else
00461           painter->drawText( QPointF( i, j ), text );
00462       }
00463     }
00464   }
00465 
00466   painter->setPen( pen );
00467   if ( mLabelAttributes->multilineEnabled() )
00468     painter->drawText( dx, dy - height, width, height, alignment, text );
00469   else
00470     painter->drawText( dx, dy, text );
00471   painter->restore();
00472 }
00473 
00474 void QgsLabel::addRequiredFields( QgsAttributeList& fields ) const
00475 {
00476   for ( uint i = 0; i < LabelFieldCount; i++ )
00477   {
00478     if ( mLabelFieldIdx[i] == -1 )
00479       continue;
00480     bool found = false;
00481     for ( QgsAttributeList::iterator it = fields.begin(); it != fields.end(); ++it )
00482     {
00483       if ( *it == mLabelFieldIdx[i] )
00484       {
00485         found = true;
00486         break;
00487       }
00488     }
00489     if ( !found )
00490     {
00491       fields.append( mLabelFieldIdx[i] );
00492     }
00493   }
00494 }
00495 
00496 void QgsLabel::setFields( const QgsFieldMap & fields )
00497 {
00498   mField = fields;
00499 }
00500 
00501 QgsFieldMap & QgsLabel::fields( void )
00502 {
00503   return mField;
00504 }
00505 
00506 void QgsLabel::setLabelField( int attr, int fieldIndex )
00507 {
00508   if ( attr >= LabelFieldCount )
00509     return;
00510 
00511   mLabelFieldIdx[attr] = fieldIndex;
00512 }
00513 
00514 QString QgsLabel::labelField( int attr ) const
00515 {
00516   if ( attr > LabelFieldCount )
00517     return QString();
00518 
00519   int fieldIndex = mLabelFieldIdx[attr];
00520   return mField[fieldIndex].name();
00521 }
00522 
00523 QgsLabelAttributes *QgsLabel::labelAttributes( void )
00524 {
00525   return mLabelAttributes;
00526 }
00527 // @note this will be deprecated use attributes rather
00528 QgsLabelAttributes *QgsLabel::layerAttributes( void )
00529 {
00530   return mLabelAttributes;
00531 }
00532 
00533 void QgsLabel::labelPoint( std::vector<labelpoint>& points, QgsFeature & feature )
00534 {
00535   QgsGeometry *geometry = feature.geometry();
00536   unsigned char *geom = geometry->asWkb();
00537   size_t geomlen = geometry->wkbSize();
00538   QGis::WkbType wkbType = geometry->wkbType();
00539   labelpoint point;
00540 
00541   switch ( wkbType )
00542   {
00543     case QGis::WKBPoint25D:
00544     case QGis::WKBPoint:
00545     case QGis::WKBLineString25D:
00546     case QGis::WKBLineString:
00547     case QGis::WKBPolygon25D:
00548     case QGis::WKBPolygon:
00549     {
00550       labelPoint( point, geom, geomlen );
00551       points.push_back( point );
00552     }
00553     break;
00554 
00555     case QGis::WKBMultiPoint25D:
00556     case QGis::WKBMultiPoint:
00557     case QGis::WKBMultiLineString25D:
00558     case QGis::WKBMultiLineString:
00559     case QGis::WKBMultiPolygon25D:
00560     case QGis::WKBMultiPolygon:
00561       // Return a position for each individual in the multi-feature
00562     {
00563       Q_ASSERT( 1 + sizeof( wkbType ) + sizeof( int ) <= geomlen );
00564       geom += 1 + sizeof( wkbType );
00565       int nFeatures = *( unsigned int * )geom;
00566       geom += sizeof( int );
00567 
00568       unsigned char *feature = geom;
00569       for ( int i = 0; i < nFeatures && feature; ++i )
00570       {
00571         feature = labelPoint( point, feature, geom + geomlen - feature );
00572         points.push_back( point );
00573       }
00574     }
00575     break;
00576     default:
00577       QgsDebugMsg( "Unknown geometry type of " + QString::number( wkbType ) );
00578   }
00579 }
00580 
00581 unsigned char* QgsLabel::labelPoint( labelpoint& point, unsigned char *geom, size_t geomlen )
00582 {
00583   // verify that local types match sizes as WKB spec
00584   Q_ASSERT( sizeof( int ) == 4 );
00585   Q_ASSERT( sizeof( QGis::WkbType ) == 4 );
00586   Q_ASSERT( sizeof( double ) == 8 );
00587 
00588   if ( geom == NULL )
00589   {
00590     QgsDebugMsg( "empty wkb" );
00591     return NULL;
00592   }
00593 
00594   QGis::WkbType wkbType;
00595 #ifndef QT_NO_DEBUG
00596   unsigned char *geomend = geom + geomlen;
00597 #endif
00598   Q_ASSERT( geom + 1 + sizeof( wkbType ) <= geomend );
00599 
00600   geom++; // skip endianness
00601   memcpy( &wkbType, geom, sizeof( wkbType ) );
00602   geom += sizeof( wkbType );
00603 
00604   int dims = 2;
00605 
00606   switch ( wkbType )
00607   {
00608     case QGis::WKBPoint25D:
00609     case QGis::WKBPoint:
00610     {
00611       Q_ASSERT( geom + 2*sizeof( double ) <= geomend );
00612       double *pts = ( double * )geom;
00613       point.p.set( pts[0], pts[1] );
00614       point.angle = 0.0;
00615       geom += 2 * sizeof( double );
00616     }
00617     break;
00618 
00619     case QGis::WKBLineString25D:
00620       dims = 3;
00621     case QGis::WKBLineString: // Line center
00622     {
00623       Q_ASSERT( geom + sizeof( int ) <= geomend );
00624       int nPoints = *( unsigned int * )geom;
00625       geom += sizeof( int );
00626 
00627       Q_ASSERT( geom + nPoints*sizeof( double )*dims <= geomend );
00628 
00629       // get line center
00630       double *pts = ( double * )geom;
00631       double tl = 0.0;
00632       for ( int i = 1; i < nPoints; i++ )
00633       {
00634         double dx = pts[dims*i]   - pts[dims*( i-1 )];
00635         double dy = pts[dims*i+1] - pts[dims*( i-1 )+1];
00636         tl += sqrt( dx * dx + dy * dy );
00637       }
00638       tl /= 2.0;
00639 
00640       // find line center
00641       double l = 0.0;
00642       for ( int i = 1; i < nPoints; i++ )
00643       {
00644         double dx = pts[dims*i]   - pts[dims*( i-1 )];
00645         double dy = pts[dims*i+1] - pts[dims*( i-1 )+1];
00646         double dl = sqrt( dx * dx + dy * dy );
00647 
00648         if ( l + dl > tl )
00649         {
00650           double k = ( tl - l ) / dl;
00651 
00652           point.p.set( pts[dims*( i-1 )]   + k * dx,
00653                        pts[dims*( i-1 )+1] + k * dy );
00654           point.angle = atan2( dy, dx ) * 180.0 * M_1_PI;
00655           break;
00656         }
00657 
00658         l += dl;
00659       }
00660 
00661       geom += nPoints * sizeof( double ) * dims;
00662     }
00663     break;
00664 
00665     case QGis::WKBPolygon25D:
00666       dims = 3;
00667     case QGis::WKBPolygon: // centroid of outer ring
00668     {
00669       Q_ASSERT( geom + sizeof( int ) <= geomend );
00670       int nRings = *( unsigned int * )geom;
00671       geom += sizeof( int );
00672 
00673       for ( int i = 0; i < nRings; ++i )
00674       {
00675         Q_ASSERT( geom + sizeof( int ) <= geomend );
00676         int nPoints = *( unsigned int * )geom;
00677         geom += sizeof( int );
00678 
00679         Q_ASSERT( geom + nPoints*sizeof( double )*dims <= geomend );
00680 
00681         if ( i == 0 )
00682         {
00683           double sx = 0.0, sy = 0.0;
00684           double *pts = ( double* ) geom;
00685           for ( int j = 0; j < nPoints - 1; j++ )
00686           {
00687             sx += pts[dims*j];
00688             sy += pts[dims*j+1];
00689           }
00690           point.p.set( sx / ( nPoints - 1 ),
00691                        sy / ( nPoints - 1 ) );
00692           point.angle = 0.0;
00693         }
00694 
00695         geom += nPoints * sizeof( double ) * dims;
00696       }
00697     }
00698     break;
00699 
00700     default:
00701       // To get here is a bug because our caller should be filtering
00702       // on wkb type.
00703       QgsDebugMsg( "unsupported wkb type" );
00704       return NULL;
00705   }
00706 
00707   return geom;
00708 }
00709 
00710 bool QgsLabel::readLabelField( QDomElement &el, int attr, QString prefix = "field" )
00711 {
00712   QString name = prefix + "name";
00713 
00714   if ( el.hasAttribute( name ) )
00715   {
00716     name = el.attribute( name );
00717 
00718     QgsFieldMap::const_iterator field_it = mField.constBegin();
00719     for ( ; field_it != mField.constEnd(); ++field_it )
00720     {
00721       if ( field_it.value().name() == name )
00722       {
00723         break;
00724       }
00725     }
00726 
00727     if ( field_it != mField.constEnd() )
00728     {
00729       mLabelFieldIdx[attr] = field_it.key();
00730       return true;
00731     }
00732   }
00733   else if ( el.hasAttribute( prefix ) )
00734   {
00735     QString value = el.attribute( prefix );
00736     mLabelFieldIdx[attr] = value.isEmpty() ? -1 : value.toInt();
00737     return true;
00738   }
00739 
00740   mLabelFieldIdx[attr] = -1;
00741   return false;
00742 }
00743 
00744 
00745 void QgsLabel::readXML( const QDomNode& node )
00746 {
00747   QgsDebugMsg( " called for layer label properties, got node " + node.nodeName() );
00748 
00749   QDomNode scratchNode;       // Dom node re-used to get current QgsLabel attribute
00750   QDomElement el;
00751 
00752   int red, green, blue;
00753   int type;
00754 
00755   /* Text */
00756   scratchNode = node.namedItem( "label" );
00757 
00758   if ( scratchNode.isNull() )
00759   {
00760     QgsDebugMsg( "couldn't find QgsLabel ``label'' attribute" );
00761   }
00762   else
00763   {
00764     el = scratchNode.toElement();
00765     mLabelAttributes->setText( el.attribute( "text", "" ) );
00766     readLabelField( el, Text );
00767   }
00768 
00769   /* Family */
00770   scratchNode = node.namedItem( "family" );
00771 
00772   if ( scratchNode.isNull() )
00773   {
00774     QgsDebugMsg( "couldn't find QgsLabel ``family'' attribute" );
00775   }
00776   else
00777   {
00778     el = scratchNode.toElement();
00779     mLabelAttributes->setFamily( el.attribute( "name", "" ) );
00780     readLabelField( el, Family );
00781   }
00782 
00783   /* Size */
00784   scratchNode = node.namedItem( "size" );
00785 
00786   if ( scratchNode.isNull() )
00787   {
00788     QgsDebugMsg( "couldn't find QgsLabel ``size'' attribute" );
00789   }
00790   else
00791   {
00792     el = scratchNode.toElement();
00793     if ( !el.hasAttribute( "unitfield" ) && !el.hasAttribute( "unitfieldname" ) )
00794     {
00795       type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
00796       mLabelAttributes->setSize( el.attribute( "value", "0.0" ).toDouble(), type );
00797     }
00798     else
00799     {
00800       readLabelField( el, SizeType, "unitfield" );
00801     }
00802     readLabelField( el, Size );
00803   }
00804 
00805   /* Bold */
00806   scratchNode = node.namedItem( "bold" );
00807 
00808   if ( scratchNode.isNull() )
00809   {
00810     QgsDebugMsg( "couldn't find QgsLabel ``bold'' attribute" );
00811   }
00812   else
00813   {
00814     el = scratchNode.toElement();
00815     mLabelAttributes->setBold(( bool )el.attribute( "on", "0" ).toInt() );
00816     readLabelField( el, Bold );
00817   }
00818 
00819   /* Italic */
00820   scratchNode = node.namedItem( "italic" );
00821 
00822   if ( scratchNode.isNull() )
00823   {
00824     QgsDebugMsg( "couldn't find QgsLabel ``italic'' attribute" );
00825   }
00826   else
00827   {
00828     el = scratchNode.toElement();
00829     mLabelAttributes->setItalic(( bool )el.attribute( "on", "0" ).toInt() );
00830     readLabelField( el, Italic );
00831   }
00832 
00833   /* Underline */
00834   scratchNode = node.namedItem( "underline" );
00835 
00836   if ( scratchNode.isNull() )
00837   {
00838     QgsDebugMsg( "couldn't find QgsLabel ``underline'' attribute" );
00839   }
00840   else
00841   {
00842     el = scratchNode.toElement();
00843     mLabelAttributes->setUnderline(( bool )el.attribute( "on", "0" ).toInt() );
00844     readLabelField( el, Underline );
00845   }
00846 
00847   /* Strikeout */
00848   scratchNode = node.namedItem( "strikeout" );
00849 
00850   if ( scratchNode.isNull() )
00851   {
00852     QgsDebugMsg( "couldn't find QgsLabel ``strikeout'' attribute" );
00853   }
00854   else
00855   {
00856     el = scratchNode.toElement();
00857     mLabelAttributes->setStrikeOut(( bool )el.attribute( "on", "0" ).toInt() );
00858     readLabelField( el, StrikeOut );
00859   }
00860 
00861   /* Color */
00862   scratchNode = node.namedItem( "color" );
00863 
00864   if ( scratchNode.isNull() )
00865   {
00866     QgsDebugMsg( "couldn't find QgsLabel ``color'' attribute" );
00867   }
00868   else
00869   {
00870     el = scratchNode.toElement();
00871 
00872     red = el.attribute( "red", "0" ).toInt();
00873     green = el.attribute( "green", "0" ).toInt();
00874     blue = el.attribute( "blue", "0" ).toInt();
00875 
00876     mLabelAttributes->setColor( QColor( red, green, blue ) );
00877 
00878     readLabelField( el, Color );
00879   }
00880 
00881   /* X */
00882   scratchNode = node.namedItem( "x" );
00883 
00884   if ( scratchNode.isNull() )
00885   {
00886     QgsDebugMsg( "couldn't find QgsLabel ``x'' attribute" );
00887   }
00888   else
00889   {
00890     el = scratchNode.toElement();
00891     readLabelField( el, XCoordinate );
00892   }
00893 
00894   /* Y */
00895   scratchNode = node.namedItem( "y" );
00896 
00897   if ( scratchNode.isNull() )
00898   {
00899     QgsDebugMsg( "couldn't find QgsLabel ``y'' attribute" );
00900   }
00901   else
00902   {
00903     el = scratchNode.toElement();
00904     readLabelField( el, YCoordinate );
00905   }
00906 
00907 
00908   /* X,Y offset */
00909   scratchNode = node.namedItem( "offset" );
00910 
00911   if ( scratchNode.isNull() )
00912   {
00913     QgsDebugMsg( "couldn't find QgsLabel ``offset'' attribute" );
00914   }
00915   else
00916   {
00917     double xoffset, yoffset;
00918 
00919     el = scratchNode.toElement();
00920 
00921     type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
00922     xoffset = el.attribute( "x", "0.0" ).toDouble();
00923     yoffset = el.attribute( "y", "0.0" ).toDouble();
00924 
00925     mLabelAttributes->setOffset( xoffset, yoffset, type );
00926     readLabelField( el, XOffset, "xfield" );
00927     readLabelField( el, YOffset, "yfield" );
00928   }
00929 
00930   /* Angle */
00931   scratchNode = node.namedItem( "angle" );
00932 
00933   if ( scratchNode.isNull() )
00934   {
00935     QgsDebugMsg( "couldn't find QgsLabel ``angle'' attribute" );
00936   }
00937   else
00938   {
00939     el = scratchNode.toElement();
00940     mLabelAttributes->setAngle( el.attribute( "value", "0.0" ).toDouble() );
00941     readLabelField( el, Angle );
00942     mLabelAttributes->setAutoAngle( el.attribute( "auto", "0" ) == "1" );
00943   }
00944 
00945   /* Alignment */
00946   scratchNode = node.namedItem( "alignment" );
00947 
00948   if ( scratchNode.isNull() )
00949   {
00950     QgsDebugMsg( "couldn't find QgsLabel ``alignment'' attribute" );
00951   }
00952   else
00953   {
00954     el = scratchNode.toElement();
00955     mLabelAttributes->setAlignment( QgsLabelAttributes::alignmentCode( el.attribute( "value", "" ) ) );
00956     readLabelField( el, Alignment );
00957   }
00958 
00959 
00960   // Buffer
00961   scratchNode = node.namedItem( "buffercolor" );
00962 
00963   if ( scratchNode.isNull() )
00964   {
00965     QgsDebugMsg( "couldn't find QgsLabel ``buffercolor'' attribute" );
00966   }
00967   else
00968   {
00969     el = scratchNode.toElement();
00970 
00971     red = el.attribute( "red", "0" ).toInt();
00972     green = el.attribute( "green", "0" ).toInt();
00973     blue = el.attribute( "blue", "0" ).toInt();
00974 
00975     mLabelAttributes->setBufferColor( QColor( red, green, blue ) );
00976     readLabelField( el, BufferColor );
00977   }
00978 
00979   scratchNode = node.namedItem( "buffersize" );
00980 
00981   if ( scratchNode.isNull() )
00982   {
00983     QgsDebugMsg( "couldn't find QgsLabel ``bffersize'' attribute" );
00984   }
00985   else
00986   {
00987     el = scratchNode.toElement();
00988 
00989     type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
00990     mLabelAttributes->setBufferSize( el.attribute( "value", "0.0" ).toDouble(), type );
00991     readLabelField( el, BufferSize );
00992   }
00993 
00994   scratchNode = node.namedItem( "bufferenabled" );
00995 
00996   if ( scratchNode.isNull() )
00997   {
00998     QgsDebugMsg( "couldn't find QgsLabel ``bufferenabled'' attribute" );
00999   }
01000   else
01001   {
01002     el = scratchNode.toElement();
01003 
01004     mLabelAttributes->setBufferEnabled(( bool )el.attribute( "on", "0" ).toInt() );
01005     readLabelField( el, BufferEnabled );
01006   }
01007 
01008   scratchNode = node.namedItem( "multilineenabled" );
01009 
01010   if ( scratchNode.isNull() )
01011   {
01012     QgsDebugMsg( "couldn't find QgsLabel ``multilineenabled'' attribute" );
01013   }
01014   else
01015   {
01016     el = scratchNode.toElement();
01017 
01018     mLabelAttributes->setMultilineEnabled(( bool )el.attribute( "on", "0" ).toInt() );
01019     readLabelField( el, MultilineEnabled );
01020   }
01021 
01022   scratchNode = node.namedItem( "selectedonly" );
01023 
01024   if ( scratchNode.isNull() )
01025   {
01026     QgsDebugMsg( "couldn't find QgsLabel ``selectedonly'' attribute" );
01027   }
01028   else
01029   {
01030     el = scratchNode.toElement();
01031     mLabelAttributes->setSelectedOnly(( bool )el.attribute( "on", "0" ).toInt() );
01032   }
01033 
01034 } // QgsLabel::readXML()
01035 
01036 
01037 
01038 void QgsLabel::writeXML( QDomNode & layer_node, QDomDocument & document ) const
01039 {
01040   QDomElement labelattributes = document.createElement( "labelattributes" );
01041 
01042   // Text
01043   QDomElement label = document.createElement( "label" );
01044   label.setAttribute( "text", mLabelAttributes->text() );
01045   if ( mLabelAttributes->textIsSet() && mLabelFieldIdx[Text] != -1 )
01046   {
01047     label.setAttribute( "fieldname", labelField( Text ) );
01048   }
01049   else
01050   {
01051     label.setAttribute( "fieldname", "" );
01052   }
01053   labelattributes.appendChild( label );
01054 
01055   // Family
01056   QDomElement family = document.createElement( "family" );
01057   if ( mLabelAttributes->familyIsSet() && !mLabelAttributes->family().isNull() )
01058   {
01059     if ( mLabelFieldIdx[Family] != -1 )
01060     {
01061       family.setAttribute( "name", mLabelAttributes->family() );
01062       family.setAttribute( "fieldname", labelField( Family ) );
01063     }
01064     else
01065     {
01066       family.setAttribute( "name", mLabelAttributes->family() );
01067       family.setAttribute( "fieldname", "" );
01068     }
01069   }
01070   else
01071   {
01072     family.setAttribute( "name", "Arial" );
01073     family.setAttribute( "fieldname", "" );
01074   }
01075   labelattributes.appendChild( family );
01076 
01077   // size and units
01078   QDomElement size = document.createElement( "size" );
01079   size.setAttribute( "value", mLabelAttributes->size() );
01080   if ( mLabelAttributes->sizeIsSet() )
01081   {
01082     if ( mLabelFieldIdx[Size] != -1 )
01083     {
01084       if ( mLabelFieldIdx[SizeType] != -1 )
01085       {
01086         size.setAttribute( "unitfieldname", labelField( SizeType ) );
01087       }
01088       else
01089       {
01090         size.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->sizeType() ) );
01091       }
01092       size.setAttribute( "fieldname", labelField( Size ) );
01093     }
01094     else
01095     {
01096       size.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->sizeType() ) );
01097       size.setAttribute( "fieldname", "" );
01098     }
01099   }
01100   else
01101   {
01102     size.setAttribute( "value", "12" );
01103     size.setAttribute( "units", "Points" );
01104     size.setAttribute( "fieldname", "" );
01105   }
01106   labelattributes.appendChild( size );
01107 
01108   // bold
01109   QDomElement bold = document.createElement( "bold" );
01110   if ( mLabelAttributes->boldIsSet() )
01111   {
01112     bold.setAttribute( "on", mLabelAttributes->bold() );
01113     if ( mLabelFieldIdx[Bold] != -1 )
01114     {
01115       bold.setAttribute( "fieldname", labelField( Bold ) );
01116     }
01117     else
01118     {
01119       bold.setAttribute( "fieldname", "" );
01120     }
01121   }
01122   else
01123   {
01124     bold.setAttribute( "on", 0 );
01125     bold.setAttribute( "fieldname", 0 );
01126   }
01127   labelattributes.appendChild( bold );
01128 
01129   // italics
01130   QDomElement italic = document.createElement( "italic" );
01131   if ( mLabelAttributes->italicIsSet() )
01132   {
01133     italic.setAttribute( "on", mLabelAttributes->italic() );
01134     if ( mLabelFieldIdx[Italic] != -1 )
01135     {
01136       italic.setAttribute( "fieldname", labelField( Italic ) );
01137     }
01138     else
01139     {
01140       italic.setAttribute( "fieldname", "" );
01141     }
01142   }
01143   else
01144   {
01145     italic.setAttribute( "on", "0" );
01146     italic.setAttribute( "fieldname", "" );
01147   }
01148   labelattributes.appendChild( italic );
01149 
01150   // underline
01151   QDomElement underline = document.createElement( "underline" );
01152   if ( mLabelAttributes->underlineIsSet() )
01153   {
01154     underline.setAttribute( "on", mLabelAttributes->underline() );
01155     if ( mLabelFieldIdx[Underline] != -1 )
01156     {
01157       underline.setAttribute( "fieldname", labelField( Underline ) );
01158     }
01159     else
01160     {
01161       underline.setAttribute( "fieldname", "" );
01162     }
01163   }
01164   else
01165   {
01166     underline.setAttribute( "on", 0 );
01167     underline.setAttribute( "fieldname", "" );
01168   }
01169   labelattributes.appendChild( underline );
01170 
01171   // strikeout
01172   QDomElement strikeOut = document.createElement( "strikeout" );
01173   if ( mLabelAttributes->strikeOutIsSet() )
01174   {
01175     strikeOut.setAttribute( "on", mLabelAttributes->strikeOut() );
01176     if ( mLabelFieldIdx[StrikeOut] != -1 )
01177     {
01178       strikeOut.setAttribute( "fieldname", labelField( StrikeOut ) );
01179     }
01180     else
01181     {
01182       strikeOut.setAttribute( "fieldname", "" );
01183     }
01184   }
01185   else
01186   {
01187     strikeOut.setAttribute( "on", 0 );
01188     strikeOut.setAttribute( "fieldname", "" );
01189   }
01190   labelattributes.appendChild( strikeOut );
01191 
01192   // color
01193   QDomElement color = document.createElement( "color" );
01194   if ( mLabelAttributes->colorIsSet() )
01195   {
01196     color.setAttribute( "red", mLabelAttributes->color().red() );
01197     color.setAttribute( "green", mLabelAttributes->color().green() );
01198     color.setAttribute( "blue", mLabelAttributes->color().blue() );
01199     if ( mLabelFieldIdx[Color] != -1 )
01200     {
01201       color.setAttribute( "fieldname", labelField( Color ) );
01202     }
01203     else
01204     {
01205       color.setAttribute( "fieldname", "" );
01206     }
01207   }
01208   else
01209   {
01210     color.setAttribute( "red", 0 );
01211     color.setAttribute( "green", 0 );
01212     color.setAttribute( "blue", 0 );
01213     color.setAttribute( "fieldname", "" );
01214   }
01215   labelattributes.appendChild( color );
01216 
01217   /* X */
01218   QDomElement x = document.createElement( "x" );
01219   if ( mLabelFieldIdx[XCoordinate] != -1 )
01220   {
01221     x.setAttribute( "fieldname", labelField( XCoordinate ) );
01222   }
01223   else
01224   {
01225     x.setAttribute( "fieldname", "" );
01226   }
01227   labelattributes.appendChild( x );
01228 
01229   /* Y */
01230   QDomElement y = document.createElement( "y" );
01231   if ( mLabelFieldIdx[YCoordinate] != -1 )
01232   {
01233     y.setAttribute( "fieldname", labelField( YCoordinate ) );
01234   }
01235   else
01236   {
01237     y.setAttribute( "fieldname", "" );
01238   }
01239   labelattributes.appendChild( y );
01240 
01241   // offset
01242   if ( mLabelAttributes->offsetIsSet() )
01243   {
01244     QDomElement offset = document.createElement( "offset" );
01245     offset.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->offsetType() ) );
01246     offset.setAttribute( "x", mLabelAttributes->xOffset() );
01247     offset.setAttribute( "xfieldname", labelField( XOffset ) );
01248     offset.setAttribute( "y", mLabelAttributes->yOffset() );
01249     offset.setAttribute( "yfieldname", labelField( YOffset ) );
01250     labelattributes.appendChild( offset );
01251   }
01252 
01253   // Angle
01254   QDomElement angle = document.createElement( "angle" );
01255   if ( mLabelAttributes->angleIsSet() )
01256   {
01257     angle.setAttribute( "value", mLabelAttributes->angle() );
01258     if ( mLabelFieldIdx[Angle] != -1 )
01259     {
01260       angle.setAttribute( "fieldname", labelField( Angle ) );
01261     }
01262     else
01263     {
01264       angle.setAttribute( "fieldname", "" );
01265     }
01266   }
01267   else
01268   {
01269     angle.setAttribute( "value", "" );
01270     angle.setAttribute( "fieldname", "" );
01271   }
01272   angle.setAttribute( "auto", mLabelAttributes->angleIsAuto() ? "1" : "0" );
01273   labelattributes.appendChild( angle );
01274 
01275   // alignment
01276   if ( mLabelAttributes->alignmentIsSet() )
01277   {
01278     QDomElement alignment = document.createElement( "alignment" );
01279     alignment.setAttribute( "value", QgsLabelAttributes::alignmentName( mLabelAttributes->alignment() ) );
01280     alignment.setAttribute( "fieldname", labelField( Alignment ) );
01281     labelattributes.appendChild( alignment );
01282   }
01283 
01284   // buffer color
01285   QDomElement buffercolor = document.createElement( "buffercolor" );
01286   if ( mLabelAttributes->bufferColorIsSet() )
01287   {
01288     buffercolor.setAttribute( "red", mLabelAttributes->bufferColor().red() );
01289     buffercolor.setAttribute( "green", mLabelAttributes->bufferColor().green() );
01290     buffercolor.setAttribute( "blue", mLabelAttributes->bufferColor().blue() );
01291     if ( mLabelFieldIdx[BufferColor] != -1 )
01292     {
01293       buffercolor.setAttribute( "fieldname", labelField( BufferColor ) );
01294     }
01295     else
01296     {
01297       buffercolor.setAttribute( "fieldname", "" );
01298     }
01299   }
01300   else
01301   {
01302     buffercolor.setAttribute( "red", "" );
01303     buffercolor.setAttribute( "green", "" );
01304     buffercolor.setAttribute( "blue", "" );
01305     buffercolor.setAttribute( "fieldname", "" );
01306   }
01307   labelattributes.appendChild( buffercolor );
01308 
01309   // buffer size
01310   QDomElement buffersize = document.createElement( "buffersize" );
01311   if ( mLabelAttributes->bufferSizeIsSet() )
01312   {
01313     buffersize.setAttribute( "value", mLabelAttributes->bufferSize() );
01314     buffersize.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->bufferSizeType() ) );
01315     if ( mLabelFieldIdx[BufferSize] != -1 )
01316     {
01317       buffersize.setAttribute( "fieldname", labelField( BufferSize ) );
01318     }
01319     else
01320     {
01321       buffersize.setAttribute( "fieldname", "" );
01322     }
01323   }
01324   else
01325   {
01326     buffersize.setAttribute( "value", "" );
01327     buffersize.setAttribute( "units", "" );
01328     buffersize.setAttribute( "fieldname", "" );
01329   }
01330   labelattributes.appendChild( buffersize );
01331 
01332   // buffer enabled
01333   QDomElement bufferenabled = document.createElement( "bufferenabled" );
01334   if ( mLabelAttributes->bufferEnabled() )
01335   {
01336     bufferenabled.setAttribute( "on", mLabelAttributes->bufferEnabled() );
01337     if ( mLabelFieldIdx[BufferEnabled] != -1 )
01338     {
01339       bufferenabled.setAttribute( "fieldname", labelField( BufferEnabled ) );
01340     }
01341     else
01342     {
01343       bufferenabled.setAttribute( "fieldname", "" );
01344     }
01345   }
01346   else
01347   {
01348     bufferenabled.setAttribute( "on", "" );
01349     bufferenabled.setAttribute( "fieldname", "" );
01350   }
01351   labelattributes.appendChild( bufferenabled );
01352 
01353   // multiline enabled
01354   QDomElement multilineenabled = document.createElement( "multilineenabled" );
01355   if ( mLabelAttributes->multilineEnabled() )
01356   {
01357     multilineenabled.setAttribute( "on", mLabelAttributes->multilineEnabled() );
01358     if ( mLabelFieldIdx[MultilineEnabled] != -1 )
01359     {
01360       multilineenabled.setAttribute( "fieldname", labelField( MultilineEnabled ) );
01361     }
01362     else
01363     {
01364       multilineenabled.setAttribute( "fieldname", "" );
01365     }
01366   }
01367   else
01368   {
01369     multilineenabled.setAttribute( "on", "" );
01370     multilineenabled.setAttribute( "fieldname", "" );
01371   }
01372   labelattributes.appendChild( multilineenabled );
01373 
01374   QDomElement selectedonly = document.createElement( "selectedonly" );
01375   if ( mLabelAttributes->selectedOnly() )
01376   {
01377     selectedonly.setAttribute( "on", mLabelAttributes->selectedOnly() );
01378   }
01379   else
01380   {
01381     selectedonly.setAttribute( "on", "" );
01382   }
01383   labelattributes.appendChild( selectedonly );
01384 
01385   layer_node.appendChild( labelattributes );
01386 }
01387 
01388 void QgsLabel::setScaleBasedVisibility( bool theVisibilityFlag )
01389 {
01390   mScaleBasedVisibility = theVisibilityFlag;
01391 }
01392 
01393 bool QgsLabel::scaleBasedVisibility() const
01394 {
01395   return mScaleBasedVisibility;
01396 }
01397 
01398 void QgsLabel::setMinScale( float theMinScale )
01399 {
01400   mMinScale = theMinScale;
01401 }
01402 
01403 float QgsLabel::minScale() const
01404 {
01405   return mMinScale;
01406 }
01407 
01408 void QgsLabel::setMaxScale( float theMaxScale )
01409 {
01410   mMaxScale = theMaxScale;
01411 }
01412 
01413 float QgsLabel::maxScale() const
01414 {
01415   return mMaxScale;
01416 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines