QGIS/src/core/composer/qgscomposerscalebar.cpp
2011-06-16 20:30:07 +02:00

372 lines
11 KiB
C++

/***************************************************************************
qgscomposerscalebar.cpp
-------------------
begin : March 2005
copyright : (C) 2005 by Radim Blazek
email : blazek@itc.it
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgscomposerscalebar.h"
#include "qgscomposermap.h"
#include "qgsscalebarstyle.h"
#include "qgsdoubleboxscalebarstyle.h"
#include "qgsnumericscalebarstyle.h"
#include "qgssingleboxscalebarstyle.h"
#include "qgsticksscalebarstyle.h"
#include "qgsrectangle.h"
#include <QDomDocument>
#include <QDomElement>
#include <QFontMetricsF>
#include <QPainter>
#include <cmath>
QgsComposerScaleBar::QgsComposerScaleBar( QgsComposition* composition ): QgsComposerItem( composition ), mComposerMap( 0 ), mStyle( 0 ), mSegmentMillimeters( 0.0 )
{
applyDefaultSettings();
applyDefaultSize();
}
QgsComposerScaleBar::~QgsComposerScaleBar()
{
delete mStyle;
}
void QgsComposerScaleBar::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
{
Q_UNUSED( itemStyle );
Q_UNUSED( pWidget );
if ( !mStyle || !painter )
{
return;
}
drawBackground( painter );
painter->setPen( QPen( QColor( 0, 0, 0 ) ) ); //draw all text black
//x-offset is half of first label width because labels are drawn centered
QString firstLabel = firstLabelString();
double firstLabelWidth = textWidthMillimeters( mFont, firstLabel );
mStyle->draw( painter, firstLabelWidth / 2 );
//draw frame and selection boxes if necessary
drawFrame( painter );
if ( isSelected() )
{
drawSelectionBoxes( painter );
}
}
void QgsComposerScaleBar::setNumUnitsPerSegment( double units )
{
mNumUnitsPerSegment = units;
refreshSegmentMillimeters();
}
void QgsComposerScaleBar::setComposerMap( const QgsComposerMap* map )
{
disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
mComposerMap = map;
if ( !map )
{
return;
}
connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
refreshSegmentMillimeters();
}
void QgsComposerScaleBar::invalidateCurrentMap()
{
disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
mComposerMap = 0;
}
void QgsComposerScaleBar::refreshSegmentMillimeters()
{
if ( mComposerMap )
{
//get extent of composer map
QgsRectangle composerMapRect = mComposerMap->extent();
//get mm dimension of composer map
QRectF composerItemRect = mComposerMap->rect();
//calculate size depending on mNumUnitsPerSegment
mSegmentMillimeters = composerItemRect.width() / composerMapRect.width() * mNumUnitsPerSegment;
}
}
void QgsComposerScaleBar::applyDefaultSettings()
{
mNumSegments = 2;
mNumSegmentsLeft = 0;
mNumMapUnitsPerScaleBarUnit = 1.0;
//style
delete mStyle;
mStyle = new QgsSingleBoxScaleBarStyle( this );
mHeight = 5;
mPen = QPen( QColor( 0, 0, 0 ) );
mPen.setWidthF( 1.0 );
mBrush.setColor( QColor( 0, 0, 0 ) );
mBrush.setStyle( Qt::SolidPattern );
mFont.setPointSizeF( 12.0 );
mLabelBarSpace = 3.0;
mBoxContentSpace = 1.0;
}
void QgsComposerScaleBar::applyDefaultSize()
{
if ( mComposerMap )
{
//calculate mNumUnitsPerSegment
QgsRectangle composerMapRect = mComposerMap->extent();
double proposedScaleBarLength = composerMapRect.width() / 4;
int powerOf10 = int ( pow( 10.0, int ( log( proposedScaleBarLength ) / log( 10.0 ) ) ) ); // from scalebar plugin
int nPow10 = proposedScaleBarLength / powerOf10;
mNumSegments = 2;
mNumUnitsPerSegment = ( nPow10 / 2 ) * powerOf10;
}
refreshSegmentMillimeters();
adjustBoxSize();
}
void QgsComposerScaleBar::adjustBoxSize()
{
if ( !mStyle )
{
return;
}
QRectF box = mStyle->calculateBoxSize();
setSceneRect( box );
}
void QgsComposerScaleBar::update()
{
adjustBoxSize();
QgsComposerItem::update();
}
void QgsComposerScaleBar::updateSegmentSize()
{
refreshSegmentMillimeters();
update();
}
void QgsComposerScaleBar::segmentPositions( QList<QPair<double, double> >& posWidthList ) const
{
posWidthList.clear();
double mCurrentXCoord = mPen.widthF() + mBoxContentSpace;
//left segments
for ( int i = 0; i < mNumSegmentsLeft; ++i )
{
posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters / mNumSegmentsLeft ) );
mCurrentXCoord += mSegmentMillimeters / mNumSegmentsLeft;
}
//right segments
for ( int i = 0; i < mNumSegments; ++i )
{
posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters ) );
mCurrentXCoord += mSegmentMillimeters;
}
}
void QgsComposerScaleBar::setStyle( const QString& styleName )
{
delete mStyle;
mStyle = 0;
//switch depending on style name
if ( styleName == "Single Box" )
{
mStyle = new QgsSingleBoxScaleBarStyle( this );
}
else if ( styleName == "Double Box" )
{
mStyle = new QgsDoubleBoxScaleBarStyle( this );
}
else if ( styleName == "Line Ticks Middle" || styleName == "Line Ticks Down" || styleName == "Line Ticks Up" )
{
QgsTicksScaleBarStyle* tickStyle = new QgsTicksScaleBarStyle( this );
if ( styleName == "Line Ticks Middle" )
{
tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksMiddle );
}
else if ( styleName == "Line Ticks Down" )
{
tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksDown );
}
else if ( styleName == "Line Ticks Up" )
{
tickStyle->setTickPosition( QgsTicksScaleBarStyle::TicksUp );
}
mStyle = tickStyle;
}
else if ( styleName == "Numeric" )
{
mStyle = new QgsNumericScaleBarStyle( this );
}
}
QString QgsComposerScaleBar::style() const
{
if ( mStyle )
{
return mStyle->name();
}
else
{
return "";
}
}
QString QgsComposerScaleBar::firstLabelString() const
{
if ( mNumSegmentsLeft > 0 )
{
return QString::number( mNumUnitsPerSegment / mNumMapUnitsPerScaleBarUnit );
}
else
{
return "0";
}
}
QFont QgsComposerScaleBar::font() const
{
return mFont;
}
void QgsComposerScaleBar::setFont( const QFont& font )
{
mFont = font;
adjustBoxSize();
update();
}
bool QgsComposerScaleBar::writeXML( QDomElement& elem, QDomDocument & doc ) const
{
if ( elem.isNull() )
{
return false;
}
QDomElement composerScaleBarElem = doc.createElement( "ComposerScaleBar" );
composerScaleBarElem.setAttribute( "height", mHeight );
composerScaleBarElem.setAttribute( "labelBarSpace", mLabelBarSpace );
composerScaleBarElem.setAttribute( "boxContentSpace", mBoxContentSpace );
composerScaleBarElem.setAttribute( "numSegments", mNumSegments );
composerScaleBarElem.setAttribute( "numSegmentsLeft", mNumSegmentsLeft );
composerScaleBarElem.setAttribute( "numUnitsPerSegment", mNumUnitsPerSegment );
composerScaleBarElem.setAttribute( "segmentMillimeters", mSegmentMillimeters );
composerScaleBarElem.setAttribute( "numMapUnitsPerScaleBarUnit", mNumMapUnitsPerScaleBarUnit );
composerScaleBarElem.setAttribute( "font", mFont.toString() );
composerScaleBarElem.setAttribute( "outlineWidth", mPen.widthF() );
composerScaleBarElem.setAttribute( "unitLabel", mUnitLabeling );
//style
if ( mStyle )
{
composerScaleBarElem.setAttribute( "style", mStyle->name() );
}
//map id
if ( mComposerMap )
{
composerScaleBarElem.setAttribute( "mapId", mComposerMap->id() );
}
//fill color
QColor brushColor = mBrush.color();
QDomElement colorElem = doc.createElement( "BrushColor" );
colorElem.setAttribute( "red", brushColor.red() );
colorElem.setAttribute( "green", brushColor.green() );
colorElem.setAttribute( "blue", brushColor.blue() );
composerScaleBarElem.appendChild( colorElem );
elem.appendChild( composerScaleBarElem );
return _writeXML( composerScaleBarElem, doc );
}
bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocument& doc )
{
if ( itemElem.isNull() )
{
return false;
}
mHeight = itemElem.attribute( "height", "5.0" ).toDouble();
mLabelBarSpace = itemElem.attribute( "labelBarSpace", "3.0" ).toDouble();
mBoxContentSpace = itemElem.attribute( "boxContentSpace", "1.0" ).toDouble();
mNumSegments = itemElem.attribute( "numSegments", "2" ).toInt();
mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt();
mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble();
mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble();
mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble();
mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
mUnitLabeling = itemElem.attribute( "unitLabel" );
QString fontString = itemElem.attribute( "font", "" );
if ( !fontString.isEmpty() )
{
mFont.fromString( fontString );
}
//style
delete mStyle;
mStyle = 0;
QString styleString = itemElem.attribute( "style", "" );
setStyle( tr( styleString.toLocal8Bit().data() ) );
//map
int mapId = itemElem.attribute( "mapId", "-1" ).toInt();
if ( mapId >= 0 )
{
const QgsComposerMap* composerMap = mComposition->getComposerMapById( mapId );
mComposerMap = composerMap;
if ( mComposerMap )
{
connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
}
}
refreshSegmentMillimeters();
//restore general composer item properties
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( composerItemList.size() > 0 )
{
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
_readXML( composerItemElem, doc );
}
return true;
}