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