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