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