Quantum GIS API Documentation  1.7.4
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                : 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 "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 ): QgsComposerItem( composition ), mComposerMap( 0 ), mStyle( 0 ), mSegmentMillimeters( 0.0 )
00032 {
00033   applyDefaultSettings();
00034   applyDefaultSize();
00035 }
00036 
00037 QgsComposerScaleBar::~QgsComposerScaleBar()
00038 {
00039   delete mStyle;
00040 }
00041 
00042 void QgsComposerScaleBar::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
00043 {
00044   if ( !mStyle || !painter )
00045   {
00046     return;
00047   }
00048 
00049   drawBackground( painter );
00050   painter->setPen( QPen( QColor( 0, 0, 0 ) ) ); //draw all text black
00051 
00052   //x-offset is half of first label width because labels are drawn centered
00053   QString firstLabel = firstLabelString();
00054   double firstLabelWidth = textWidthMillimeters( mFont, firstLabel );
00055 
00056   mStyle->draw( painter, firstLabelWidth / 2 );
00057 
00058   //draw frame and selection boxes if necessary
00059   drawFrame( painter );
00060   if ( isSelected() )
00061   {
00062     drawSelectionBoxes( painter );
00063   }
00064 }
00065 
00066 void QgsComposerScaleBar::setNumUnitsPerSegment( double units )
00067 {
00068   mNumUnitsPerSegment = units;
00069   refreshSegmentMillimeters();
00070 }
00071 
00072 void QgsComposerScaleBar::setComposerMap( const QgsComposerMap* map )
00073 {
00074   disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
00075   disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
00076   mComposerMap = map;
00077 
00078   if ( !map )
00079   {
00080     return;
00081   }
00082 
00083   connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
00084   connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
00085 
00086   refreshSegmentMillimeters();
00087 }
00088 
00089 void QgsComposerScaleBar::invalidateCurrentMap()
00090 {
00091   disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
00092   disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
00093   mComposerMap = 0;
00094 }
00095 
00096 void QgsComposerScaleBar::refreshSegmentMillimeters()
00097 {
00098   if ( mComposerMap )
00099   {
00100     //get extent of composer map
00101     QgsRectangle composerMapRect = mComposerMap->extent();
00102 
00103     //get mm dimension of composer map
00104     QRectF composerItemRect = mComposerMap->rect();
00105 
00106     //calculate size depending on mNumUnitsPerSegment
00107     mSegmentMillimeters = composerItemRect.width() / composerMapRect.width() * mNumUnitsPerSegment;
00108   }
00109 }
00110 
00111 void QgsComposerScaleBar::applyDefaultSettings()
00112 {
00113   mNumSegments = 2;
00114   mNumSegmentsLeft = 0;
00115 
00116   mNumMapUnitsPerScaleBarUnit = 1.0;
00117 
00118   //style
00119   delete mStyle;
00120   mStyle = new QgsSingleBoxScaleBarStyle( this );
00121 
00122   mHeight = 5;
00123 
00124   mPen = QPen( QColor( 0, 0, 0 ) );
00125   mPen.setWidthF( 1.0 );
00126 
00127   mBrush.setColor( QColor( 0, 0, 0 ) );
00128   mBrush.setStyle( Qt::SolidPattern );
00129 
00130   mFont.setPointSizeF( 12.0 );
00131 
00132   mLabelBarSpace = 3.0;
00133   mBoxContentSpace = 1.0;
00134 }
00135 
00136 void QgsComposerScaleBar::applyDefaultSize()
00137 {
00138   if ( mComposerMap )
00139   {
00140     //calculate mNumUnitsPerSegment
00141     QgsRectangle composerMapRect = mComposerMap->extent();
00142 
00143     double proposedScaleBarLength = composerMapRect.width() / 4;
00144     int powerOf10 = int ( pow( 10.0, int ( log( proposedScaleBarLength ) / log( 10.0 ) ) ) ); // from scalebar plugin
00145     int nPow10 = proposedScaleBarLength / powerOf10;
00146     mNumSegments = 2;
00147     mNumUnitsPerSegment = ( nPow10 / 2 ) * powerOf10;
00148   }
00149 
00150   refreshSegmentMillimeters();
00151   adjustBoxSize();
00152 }
00153 
00154 void QgsComposerScaleBar::adjustBoxSize()
00155 {
00156   if ( !mStyle )
00157   {
00158     return;
00159   }
00160 
00161   QRectF box = mStyle->calculateBoxSize();
00162   setSceneRect( box );
00163 }
00164 
00165 void QgsComposerScaleBar::update()
00166 {
00167   adjustBoxSize();
00168   QgsComposerItem::update();
00169 }
00170 
00171 void QgsComposerScaleBar::updateSegmentSize()
00172 {
00173   refreshSegmentMillimeters();
00174   update();
00175 }
00176 
00177 void QgsComposerScaleBar::segmentPositions( QList<QPair<double, double> >& posWidthList ) const
00178 {
00179   posWidthList.clear();
00180   double mCurrentXCoord = mPen.widthF() + mBoxContentSpace;
00181 
00182   //left segments
00183   for ( int i = 0; i < mNumSegmentsLeft; ++i )
00184   {
00185     posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters / mNumSegmentsLeft ) );
00186     mCurrentXCoord += mSegmentMillimeters / mNumSegmentsLeft;
00187   }
00188 
00189   //right segments
00190   for ( int i = 0; i < mNumSegments; ++i )
00191   {
00192     posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters ) );
00193     mCurrentXCoord += mSegmentMillimeters;
00194   }
00195 }
00196 
00197 void QgsComposerScaleBar::setStyle( const QString& styleName )
00198 {
00199   delete mStyle;
00200   mStyle = 0;
00201 
00202   //switch depending on style name
00203   if ( styleName == "Single Box" )
00204   {
00205     mStyle = new QgsSingleBoxScaleBarStyle( this );
00206   }
00207   else if ( styleName == "Double Box" )
00208   {
00209     mStyle = new QgsDoubleBoxScaleBarStyle( this );
00210   }
00211   else if ( styleName == "Line Ticks Middle"  || styleName == "Line Ticks Down" || styleName == "Line Ticks Up" )
00212   {
00213     QgsTicksScaleBarStyle* tickStyle = new QgsTicksScaleBarStyle( this );
00214     if ( styleName == "Line Ticks Middle" )
00215     {
00216       tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksMiddle );
00217     }
00218     else if ( styleName == "Line Ticks Down" )
00219     {
00220       tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksDown );
00221     }
00222     else if ( styleName == "Line Ticks Up" )
00223     {
00224       tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksUp );
00225     }
00226     mStyle = tickStyle;
00227   }
00228   else if ( styleName == "Numeric" )
00229   {
00230     mStyle = new QgsNumericScaleBarStyle( this );
00231   }
00232 }
00233 
00234 QString QgsComposerScaleBar::style() const
00235 {
00236   if ( mStyle )
00237   {
00238     return mStyle->name();
00239   }
00240   else
00241   {
00242     return "";
00243   }
00244 }
00245 
00246 QString QgsComposerScaleBar::firstLabelString() const
00247 {
00248   if ( mNumSegmentsLeft > 0 )
00249   {
00250     return QString::number( mNumUnitsPerSegment / mNumMapUnitsPerScaleBarUnit );
00251   }
00252   else
00253   {
00254     return "0";
00255   }
00256 }
00257 
00258 QFont QgsComposerScaleBar::font() const
00259 {
00260   return mFont;
00261 }
00262 
00263 void QgsComposerScaleBar::setFont( const QFont& font )
00264 {
00265   mFont = font;
00266   adjustBoxSize();
00267   update();
00268 }
00269 
00270 bool QgsComposerScaleBar::writeXML( QDomElement& elem, QDomDocument & doc ) const
00271 {
00272   if ( elem.isNull() )
00273   {
00274     return false;
00275   }
00276 
00277   QDomElement composerScaleBarElem = doc.createElement( "ComposerScaleBar" );
00278   composerScaleBarElem.setAttribute( "height", mHeight );
00279   composerScaleBarElem.setAttribute( "labelBarSpace", mLabelBarSpace );
00280   composerScaleBarElem.setAttribute( "boxContentSpace", mBoxContentSpace );
00281   composerScaleBarElem.setAttribute( "numSegments", mNumSegments );
00282   composerScaleBarElem.setAttribute( "numSegmentsLeft", mNumSegmentsLeft );
00283   composerScaleBarElem.setAttribute( "numUnitsPerSegment", mNumUnitsPerSegment );
00284   composerScaleBarElem.setAttribute( "segmentMillimeters", mSegmentMillimeters );
00285   composerScaleBarElem.setAttribute( "numMapUnitsPerScaleBarUnit", mNumMapUnitsPerScaleBarUnit );
00286   composerScaleBarElem.setAttribute( "font", mFont.toString() );
00287   composerScaleBarElem.setAttribute( "outlineWidth", mPen.widthF() );
00288   composerScaleBarElem.setAttribute( "unitLabel", mUnitLabeling );
00289 
00290   //style
00291   if ( mStyle )
00292   {
00293     composerScaleBarElem.setAttribute( "style", mStyle->name() );
00294   }
00295 
00296   //map id
00297   if ( mComposerMap )
00298   {
00299     composerScaleBarElem.setAttribute( "mapId", mComposerMap->id() );
00300   }
00301 
00302   //fill color
00303   QColor brushColor = mBrush.color();
00304   QDomElement colorElem = doc.createElement( "BrushColor" );
00305   colorElem.setAttribute( "red", brushColor.red() );
00306   colorElem.setAttribute( "green", brushColor.green() );
00307   colorElem.setAttribute( "blue", brushColor.blue() );
00308   composerScaleBarElem.appendChild( colorElem );
00309 
00310   elem.appendChild( composerScaleBarElem );
00311   return _writeXML( composerScaleBarElem, doc );
00312 }
00313 
00314 bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocument& doc )
00315 {
00316   if ( itemElem.isNull() )
00317   {
00318     return false;
00319   }
00320 
00321   mHeight = itemElem.attribute( "height", "5.0" ).toDouble();
00322   mLabelBarSpace = itemElem.attribute( "labelBarSpace", "3.0" ).toDouble();
00323   mBoxContentSpace = itemElem.attribute( "boxContentSpace", "1.0" ).toDouble();
00324   mNumSegments = itemElem.attribute( "numSegments", "2" ).toInt();
00325   mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt();
00326   mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble();
00327   mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble();
00328   mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble();
00329   mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
00330   mUnitLabeling = itemElem.attribute( "unitLabel" );
00331   QString fontString = itemElem.attribute( "font", "" );
00332   if ( !fontString.isEmpty() )
00333   {
00334     mFont.fromString( fontString );
00335   }
00336 
00337   //style
00338   delete mStyle;
00339   mStyle = 0;
00340   QString styleString = itemElem.attribute( "style", "" );
00341   setStyle( tr( styleString.toLocal8Bit().data() ) );
00342 
00343   //map
00344   int mapId = itemElem.attribute( "mapId", "-1" ).toInt();
00345   if ( mapId >= 0 )
00346   {
00347     const QgsComposerMap* composerMap = mComposition->getComposerMapById( mapId );
00348     mComposerMap = composerMap;
00349     if ( mComposerMap )
00350     {
00351       connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
00352       connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
00353     }
00354   }
00355 
00356   refreshSegmentMillimeters();
00357 
00358   //restore general composer item properties
00359   QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
00360   if ( composerItemList.size() > 0 )
00361   {
00362     QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
00363     _readXML( composerItemElem, doc );
00364   }
00365 
00366   return true;
00367 }
00368 
00369 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines