Quantum GIS API Documentation
1.7.4
|
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 }