|
QGIS API Documentation
master-3f58142
|
00001 /*************************************************************************** 00002 qgscomposerscalebar.cpp 00003 ------------------- 00004 begin : March 2005 00005 copyright : (C) 2005 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 "qgscomposerscalebar.h" 00018 #include "qgscomposermap.h" 00019 #include "qgscomposition.h" 00020 #include "qgsdistancearea.h" 00021 #include "qgsscalebarstyle.h" 00022 #include "qgsdoubleboxscalebarstyle.h" 00023 #include "qgsmaprenderer.h" 00024 #include "qgsnumericscalebarstyle.h" 00025 #include "qgssingleboxscalebarstyle.h" 00026 #include "qgsticksscalebarstyle.h" 00027 #include "qgsrectangle.h" 00028 #include "qgsproject.h" 00029 #include <QDomDocument> 00030 #include <QDomElement> 00031 #include <QFontMetricsF> 00032 #include <QPainter> 00033 #include <QSettings> 00034 #include <cmath> 00035 00036 QgsComposerScaleBar::QgsComposerScaleBar( QgsComposition* composition ) 00037 : QgsComposerItem( composition ) 00038 , mComposerMap( 0 ) 00039 , mNumUnitsPerSegment( 0 ) 00040 , mFontColor( QColor( 0, 0, 0 ) ) 00041 , mStyle( 0 ) 00042 , mSegmentMillimeters( 0.0 ) 00043 , mAlignment( Left ) 00044 , mUnits( MapUnits ) 00045 { 00046 applyDefaultSettings(); 00047 applyDefaultSize(); 00048 } 00049 00050 QgsComposerScaleBar::~QgsComposerScaleBar() 00051 { 00052 delete mStyle; 00053 } 00054 00055 void QgsComposerScaleBar::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget ) 00056 { 00057 Q_UNUSED( itemStyle ); 00058 Q_UNUSED( pWidget ); 00059 if ( !mStyle || !painter ) 00060 { 00061 return; 00062 } 00063 00064 drawBackground( painter ); 00065 00066 //x-offset is half of first label width because labels are drawn centered 00067 QString firstLabel = firstLabelString(); 00068 double firstLabelWidth = textWidthMillimeters( mFont, firstLabel ); 00069 00070 mStyle->draw( painter, firstLabelWidth / 2 ); 00071 00072 //draw frame and selection boxes if necessary 00073 drawFrame( painter ); 00074 if ( isSelected() ) 00075 { 00076 drawSelectionBoxes( painter ); 00077 } 00078 } 00079 00080 void QgsComposerScaleBar::setNumSegments( int nSegments ) 00081 { 00082 if ( !mStyle ) 00083 { 00084 mNumSegments = nSegments; 00085 return; 00086 } 00087 double width = mStyle->calculateBoxSize().width(); 00088 mNumSegments = nSegments; 00089 double widthAfter = mStyle->calculateBoxSize().width(); 00090 correctXPositionAlignment( width, widthAfter ); 00091 emit itemChanged(); 00092 } 00093 00094 void QgsComposerScaleBar::setNumUnitsPerSegment( double units ) 00095 { 00096 if ( !mStyle ) 00097 { 00098 mNumUnitsPerSegment = units; 00099 return; 00100 } 00101 double width = mStyle->calculateBoxSize().width(); 00102 mNumUnitsPerSegment = units; 00103 refreshSegmentMillimeters(); 00104 double widthAfter = mStyle->calculateBoxSize().width(); 00105 correctXPositionAlignment( width, widthAfter ); 00106 emit itemChanged(); 00107 } 00108 00109 void QgsComposerScaleBar::setNumSegmentsLeft( int nSegmentsLeft ) 00110 { 00111 if ( !mStyle ) 00112 { 00113 mNumSegmentsLeft = nSegmentsLeft; 00114 return; 00115 } 00116 double width = mStyle->calculateBoxSize().width(); 00117 mNumSegmentsLeft = nSegmentsLeft; 00118 double widthAfter = mStyle->calculateBoxSize().width(); 00119 correctXPositionAlignment( width, widthAfter ); 00120 emit itemChanged(); 00121 } 00122 00123 void QgsComposerScaleBar::setBoxContentSpace( double space ) 00124 { 00125 if ( !mStyle ) 00126 { 00127 mBoxContentSpace = space; 00128 return; 00129 } 00130 double width = mStyle->calculateBoxSize().width(); 00131 mBoxContentSpace = space; 00132 double widthAfter = mStyle->calculateBoxSize().width(); 00133 correctXPositionAlignment( width, widthAfter ); 00134 emit itemChanged(); 00135 } 00136 00137 void QgsComposerScaleBar::setComposerMap( const QgsComposerMap* map ) 00138 { 00139 disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) ); 00140 disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) ); 00141 mComposerMap = map; 00142 00143 if ( !map ) 00144 { 00145 return; 00146 } 00147 00148 connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) ); 00149 connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) ); 00150 00151 refreshSegmentMillimeters(); 00152 emit itemChanged(); 00153 } 00154 00155 void QgsComposerScaleBar::invalidateCurrentMap() 00156 { 00157 disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) ); 00158 disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) ); 00159 mComposerMap = 0; 00160 } 00161 00162 void QgsComposerScaleBar::refreshSegmentMillimeters() 00163 { 00164 if ( mComposerMap ) 00165 { 00166 //get extent of composer map 00167 QgsRectangle composerMapRect = mComposerMap->extent(); 00168 00169 //get mm dimension of composer map 00170 QRectF composerItemRect = mComposerMap->rect(); 00171 00172 //calculate size depending on mNumUnitsPerSegment 00173 mSegmentMillimeters = composerItemRect.width() / mapWidth() * mNumUnitsPerSegment; 00174 } 00175 } 00176 00177 double QgsComposerScaleBar::mapWidth() const 00178 { 00179 if ( !mComposerMap ) 00180 { 00181 return 0.0; 00182 } 00183 00184 QgsRectangle composerMapRect = mComposerMap->extent(); 00185 if ( mUnits == MapUnits ) 00186 { 00187 return composerMapRect.width(); 00188 } 00189 else 00190 { 00191 QgsDistanceArea da; 00192 da.setEllipsoidalMode( mComposerMap->mapRenderer()->hasCrsTransformEnabled() ); 00193 da.setSourceCrs( mComposerMap->mapRenderer()->destinationCrs().srsid() ); 00194 da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", "WGS84" ) ); 00195 00196 double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMinimum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) ); 00197 if ( mUnits == Feet ) 00198 { 00199 measure /= 0.3048; 00200 } 00201 return measure; 00202 } 00203 } 00204 00205 void QgsComposerScaleBar::setUnits( ScaleBarUnits u ) 00206 { 00207 mUnits = u; 00208 refreshSegmentMillimeters(); 00209 emit itemChanged(); 00210 } 00211 00212 void QgsComposerScaleBar::applyDefaultSettings() 00213 { 00214 mNumSegments = 2; 00215 mNumSegmentsLeft = 0; 00216 00217 mNumMapUnitsPerScaleBarUnit = 1.0; 00218 00219 //style 00220 delete mStyle; 00221 mStyle = new QgsSingleBoxScaleBarStyle( this ); 00222 00223 mHeight = 3; 00224 00225 mPen = QPen( QColor( 0, 0, 0 ) ); 00226 mPen.setWidthF( 1.0 ); 00227 00228 mBrush.setColor( QColor( 0, 0, 0 ) ); 00229 mBrush.setStyle( Qt::SolidPattern ); 00230 00231 mFont.setPointSizeF( 12.0 ); 00232 mFontColor = QColor( 0, 0, 0 ); 00233 00234 mLabelBarSpace = 3.0; 00235 mBoxContentSpace = 1.0; 00236 emit itemChanged(); 00237 } 00238 00239 void QgsComposerScaleBar::applyDefaultSize() 00240 { 00241 if ( mComposerMap ) 00242 { 00243 setUnits( Meters ); 00244 double widthMeter = mapWidth(); 00245 int nUnitsPerSegment = widthMeter / 10.0; //default scalebar width equals half the map width 00246 setNumUnitsPerSegment( nUnitsPerSegment ); 00247 00248 if ( nUnitsPerSegment > 1000 ) 00249 { 00250 setNumUnitsPerSegment(( int )( numUnitsPerSegment() / 1000.0 + 0.5 ) * 1000 ); 00251 setUnitLabeling( tr( "km" ) ); 00252 setNumMapUnitsPerScaleBarUnit( 1000 ); 00253 } 00254 else 00255 { 00256 setUnitLabeling( tr( "m" ) ); 00257 } 00258 00259 setNumSegments( 4 ); 00260 setNumSegmentsLeft( 2 ); 00261 } 00262 00263 refreshSegmentMillimeters(); 00264 adjustBoxSize(); 00265 emit itemChanged(); 00266 } 00267 00268 void QgsComposerScaleBar::adjustBoxSize() 00269 { 00270 if ( !mStyle ) 00271 { 00272 return; 00273 } 00274 00275 QRectF box = mStyle->calculateBoxSize(); 00276 setSceneRect( box ); 00277 } 00278 00279 void QgsComposerScaleBar::update() 00280 { 00281 adjustBoxSize(); 00282 QgsComposerItem::update(); 00283 } 00284 00285 void QgsComposerScaleBar::updateSegmentSize() 00286 { 00287 if ( !mStyle ) 00288 { 00289 return; 00290 } 00291 double width = mStyle->calculateBoxSize().width(); 00292 refreshSegmentMillimeters(); 00293 double widthAfter = mStyle->calculateBoxSize().width(); 00294 correctXPositionAlignment( width, widthAfter ); 00295 update(); 00296 emit itemChanged(); 00297 } 00298 00299 void QgsComposerScaleBar::segmentPositions( QList<QPair<double, double> >& posWidthList ) const 00300 { 00301 posWidthList.clear(); 00302 double mCurrentXCoord = mPen.widthF() + mBoxContentSpace; 00303 00304 //left segments 00305 for ( int i = 0; i < mNumSegmentsLeft; ++i ) 00306 { 00307 posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters / mNumSegmentsLeft ) ); 00308 mCurrentXCoord += mSegmentMillimeters / mNumSegmentsLeft; 00309 } 00310 00311 //right segments 00312 for ( int i = 0; i < mNumSegments; ++i ) 00313 { 00314 posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters ) ); 00315 mCurrentXCoord += mSegmentMillimeters; 00316 } 00317 } 00318 00319 void QgsComposerScaleBar::setStyle( const QString& styleName ) 00320 { 00321 delete mStyle; 00322 mStyle = 0; 00323 00324 //switch depending on style name 00325 if ( styleName == "Single Box" ) 00326 { 00327 mStyle = new QgsSingleBoxScaleBarStyle( this ); 00328 } 00329 else if ( styleName == "Double Box" ) 00330 { 00331 mStyle = new QgsDoubleBoxScaleBarStyle( this ); 00332 } 00333 else if ( styleName == "Line Ticks Middle" || styleName == "Line Ticks Down" || styleName == "Line Ticks Up" ) 00334 { 00335 QgsTicksScaleBarStyle* tickStyle = new QgsTicksScaleBarStyle( this ); 00336 if ( styleName == "Line Ticks Middle" ) 00337 { 00338 tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksMiddle ); 00339 } 00340 else if ( styleName == "Line Ticks Down" ) 00341 { 00342 tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksDown ); 00343 } 00344 else if ( styleName == "Line Ticks Up" ) 00345 { 00346 tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksUp ); 00347 } 00348 mStyle = tickStyle; 00349 } 00350 else if ( styleName == "Numeric" ) 00351 { 00352 mStyle = new QgsNumericScaleBarStyle( this ); 00353 } 00354 emit itemChanged(); 00355 } 00356 00357 QString QgsComposerScaleBar::style() const 00358 { 00359 if ( mStyle ) 00360 { 00361 return mStyle->name(); 00362 } 00363 else 00364 { 00365 return ""; 00366 } 00367 } 00368 00369 QString QgsComposerScaleBar::firstLabelString() const 00370 { 00371 if ( mNumSegmentsLeft > 0 ) 00372 { 00373 return QString::number( mNumUnitsPerSegment / mNumMapUnitsPerScaleBarUnit ); 00374 } 00375 else 00376 { 00377 return "0"; 00378 } 00379 } 00380 00381 QFont QgsComposerScaleBar::font() const 00382 { 00383 return mFont; 00384 } 00385 00386 void QgsComposerScaleBar::setFont( const QFont& font ) 00387 { 00388 mFont = font; 00389 adjustBoxSize(); 00390 update(); 00391 emit itemChanged(); 00392 } 00393 00394 bool QgsComposerScaleBar::writeXML( QDomElement& elem, QDomDocument & doc ) const 00395 { 00396 if ( elem.isNull() ) 00397 { 00398 return false; 00399 } 00400 00401 QDomElement composerScaleBarElem = doc.createElement( "ComposerScaleBar" ); 00402 composerScaleBarElem.setAttribute( "height", QString::number( mHeight ) ); 00403 composerScaleBarElem.setAttribute( "labelBarSpace", QString::number( mLabelBarSpace ) ); 00404 composerScaleBarElem.setAttribute( "boxContentSpace", QString::number( mBoxContentSpace ) ); 00405 composerScaleBarElem.setAttribute( "numSegments", mNumSegments ); 00406 composerScaleBarElem.setAttribute( "numSegmentsLeft", mNumSegmentsLeft ); 00407 composerScaleBarElem.setAttribute( "numUnitsPerSegment", QString::number( mNumUnitsPerSegment ) ); 00408 composerScaleBarElem.setAttribute( "segmentMillimeters", QString::number( mSegmentMillimeters ) ); 00409 composerScaleBarElem.setAttribute( "numMapUnitsPerScaleBarUnit", QString::number( mNumMapUnitsPerScaleBarUnit ) ); 00410 composerScaleBarElem.setAttribute( "font", mFont.toString() ); 00411 composerScaleBarElem.setAttribute( "outlineWidth", QString::number( mPen.widthF() ) ); 00412 composerScaleBarElem.setAttribute( "unitLabel", mUnitLabeling ); 00413 composerScaleBarElem.setAttribute( "units", mUnits ); 00414 00415 //style 00416 if ( mStyle ) 00417 { 00418 composerScaleBarElem.setAttribute( "style", mStyle->name() ); 00419 } 00420 00421 //map id 00422 if ( mComposerMap ) 00423 { 00424 composerScaleBarElem.setAttribute( "mapId", mComposerMap->id() ); 00425 } 00426 00427 //colors 00428 composerScaleBarElem.setAttribute( "brushColor", mBrush.color().name() ); 00429 composerScaleBarElem.setAttribute( "penColor", mPen.color().name() ); 00430 composerScaleBarElem.setAttribute( "fontColor", mFontColor.name() ); 00431 00432 //alignment 00433 composerScaleBarElem.setAttribute( "alignment", QString::number(( int ) mAlignment ) ); 00434 00435 elem.appendChild( composerScaleBarElem ); 00436 return _writeXML( composerScaleBarElem, doc ); 00437 } 00438 00439 bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocument& doc ) 00440 { 00441 if ( itemElem.isNull() ) 00442 { 00443 return false; 00444 } 00445 00446 mHeight = itemElem.attribute( "height", "5.0" ).toDouble(); 00447 mLabelBarSpace = itemElem.attribute( "labelBarSpace", "3.0" ).toDouble(); 00448 mBoxContentSpace = itemElem.attribute( "boxContentSpace", "1.0" ).toDouble(); 00449 mNumSegments = itemElem.attribute( "numSegments", "2" ).toInt(); 00450 mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt(); 00451 mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble(); 00452 mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble(); 00453 mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble(); 00454 mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() ); 00455 mUnitLabeling = itemElem.attribute( "unitLabel" ); 00456 QString fontString = itemElem.attribute( "font", "" ); 00457 if ( !fontString.isEmpty() ) 00458 { 00459 mFont.fromString( fontString ); 00460 } 00461 00462 //colors 00463 //fill color 00464 mBrush.setColor( QColor( itemElem.attribute( "brushColor", "#000000" ) ) ); 00465 mPen.setColor( QColor( itemElem.attribute( "penColor", "#000000" ) ) ); 00466 mFontColor.setNamedColor( itemElem.attribute( "fontColor", "#000000" ) ); 00467 00468 //style 00469 delete mStyle; 00470 mStyle = 0; 00471 QString styleString = itemElem.attribute( "style", "" ); 00472 setStyle( tr( styleString.toLocal8Bit().data() ) ); 00473 00474 mUnits = ( ScaleBarUnits )itemElem.attribute( "units" ).toInt(); 00475 mAlignment = ( Alignment )( itemElem.attribute( "alignment", "0" ).toInt() ); 00476 00477 //map 00478 int mapId = itemElem.attribute( "mapId", "-1" ).toInt(); 00479 if ( mapId >= 0 ) 00480 { 00481 const QgsComposerMap* composerMap = mComposition->getComposerMapById( mapId ); 00482 mComposerMap = composerMap; 00483 if ( mComposerMap ) 00484 { 00485 connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) ); 00486 connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) ); 00487 } 00488 } 00489 00490 updateSegmentSize(); 00491 00492 //restore general composer item properties 00493 QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" ); 00494 if ( composerItemList.size() > 0 ) 00495 { 00496 QDomElement composerItemElem = composerItemList.at( 0 ).toElement(); 00497 _readXML( composerItemElem, doc ); 00498 } 00499 00500 return true; 00501 } 00502 00503 void QgsComposerScaleBar::correctXPositionAlignment( double width, double widthAfter ) 00504 { 00505 if ( mAlignment == Middle ) 00506 { 00507 move( -( widthAfter - width ) / 2.0, 0 ); 00508 } 00509 else if ( mAlignment == Right ) 00510 { 00511 move( -( widthAfter - width ), 0 ); 00512 } 00513 } 00514 00515