|
QGIS API Documentation
master-3f58142
|
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 }