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