Quantum GIS API Documentation  1.8
src/core/composer/qgscomposerscalebar.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines