Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
qgscomposerscalebar.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerscalebar.cpp
3  -------------------
4  begin : March 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : blazek@itc.it
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgscomposerscalebar.h"
18 #include "qgscomposermap.h"
19 #include "qgsscalebarstyle.h"
23 #include "qgsticksscalebarstyle.h"
24 #include "qgsrectangle.h"
25 #include <QDomDocument>
26 #include <QDomElement>
27 #include <QFontMetricsF>
28 #include <QPainter>
29 #include <cmath>
30 
31 QgsComposerScaleBar::QgsComposerScaleBar( QgsComposition* composition ): QgsComposerItem( composition ), mComposerMap( 0 ), mStyle( 0 ), mSegmentMillimeters( 0.0 )
32 {
35 }
36 
38 {
39  delete mStyle;
40 }
41 
42 void QgsComposerScaleBar::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
43 {
44  if ( !mStyle || !painter )
45  {
46  return;
47  }
48 
49  drawBackground( painter );
50  painter->setPen( QPen( QColor( 0, 0, 0 ) ) ); //draw all text black
51 
52  //x-offset is half of first label width because labels are drawn centered
53  QString firstLabel = firstLabelString();
54  double firstLabelWidth = textWidthMillimeters( mFont, firstLabel );
55 
56  mStyle->draw( painter, firstLabelWidth / 2 );
57 
58  //draw frame and selection boxes if necessary
59  drawFrame( painter );
60  if ( isSelected() )
61  {
62  drawSelectionBoxes( painter );
63  }
64 }
65 
67 {
68  mNumUnitsPerSegment = units;
70 }
71 
73 {
74  disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
75  disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
76  mComposerMap = map;
77 
78  if ( !map )
79  {
80  return;
81  }
82 
83  connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
84  connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
85 
87 }
88 
90 {
91  disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
92  disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
93  mComposerMap = 0;
94 }
95 
97 {
98  if ( mComposerMap )
99  {
100  //get extent of composer map
101  QgsRectangle composerMapRect = mComposerMap->extent();
102 
103  //get mm dimension of composer map
104  QRectF composerItemRect = mComposerMap->rect();
105 
106  //calculate size depending on mNumUnitsPerSegment
107  mSegmentMillimeters = composerItemRect.width() / composerMapRect.width() * mNumUnitsPerSegment;
108  }
109 }
110 
112 {
113  mNumSegments = 2;
114  mNumSegmentsLeft = 0;
115 
117 
118  //style
119  delete mStyle;
120  mStyle = new QgsSingleBoxScaleBarStyle( this );
121 
122  mHeight = 5;
123 
124  mPen = QPen( QColor( 0, 0, 0 ) );
125  mPen.setWidthF( 1.0 );
126 
127  mBrush.setColor( QColor( 0, 0, 0 ) );
128  mBrush.setStyle( Qt::SolidPattern );
129 
130  mFont.setPointSizeF( 12.0 );
131 
132  mLabelBarSpace = 3.0;
133  mBoxContentSpace = 1.0;
134 }
135 
137 {
138  if ( mComposerMap )
139  {
140  //calculate mNumUnitsPerSegment
141  QgsRectangle composerMapRect = mComposerMap->extent();
142 
143  double proposedScaleBarLength = composerMapRect.width() / 4;
144  int powerOf10 = int ( pow( 10.0, int ( log( proposedScaleBarLength ) / log( 10.0 ) ) ) ); // from scalebar plugin
145  int nPow10 = proposedScaleBarLength / powerOf10;
146  mNumSegments = 2;
147  mNumUnitsPerSegment = ( nPow10 / 2 ) * powerOf10;
148  }
149 
151  adjustBoxSize();
152 }
153 
155 {
156  if ( !mStyle )
157  {
158  return;
159  }
160 
161  QRectF box = mStyle->calculateBoxSize();
162  setSceneRect( box );
163 }
164 
166 {
167  adjustBoxSize();
169 }
170 
172 {
174  update();
175 }
176 
177 void QgsComposerScaleBar::segmentPositions( QList<QPair<double, double> >& posWidthList ) const
178 {
179  posWidthList.clear();
180  double mCurrentXCoord = mPen.widthF() + mBoxContentSpace;
181 
182  //left segments
183  for ( int i = 0; i < mNumSegmentsLeft; ++i )
184  {
185  posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters / mNumSegmentsLeft ) );
186  mCurrentXCoord += mSegmentMillimeters / mNumSegmentsLeft;
187  }
188 
189  //right segments
190  for ( int i = 0; i < mNumSegments; ++i )
191  {
192  posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters ) );
193  mCurrentXCoord += mSegmentMillimeters;
194  }
195 }
196 
197 void QgsComposerScaleBar::setStyle( const QString& styleName )
198 {
199  delete mStyle;
200  mStyle = 0;
201 
202  //switch depending on style name
203  if ( styleName == "Single Box" )
204  {
205  mStyle = new QgsSingleBoxScaleBarStyle( this );
206  }
207  else if ( styleName == "Double Box" )
208  {
209  mStyle = new QgsDoubleBoxScaleBarStyle( this );
210  }
211  else if ( styleName == "Line Ticks Middle" || styleName == "Line Ticks Down" || styleName == "Line Ticks Up" )
212  {
213  QgsTicksScaleBarStyle* tickStyle = new QgsTicksScaleBarStyle( this );
214  if ( styleName == "Line Ticks Middle" )
215  {
217  }
218  else if ( styleName == "Line Ticks Down" )
219  {
221  }
222  else if ( styleName == "Line Ticks Up" )
223  {
225  }
226  mStyle = tickStyle;
227  }
228  else if ( styleName == "Numeric" )
229  {
230  mStyle = new QgsNumericScaleBarStyle( this );
231  }
232 }
233 
235 {
236  if ( mStyle )
237  {
238  return mStyle->name();
239  }
240  else
241  {
242  return "";
243  }
244 }
245 
247 {
248  if ( mNumSegmentsLeft > 0 )
249  {
250  return QString::number( mNumUnitsPerSegment / mNumMapUnitsPerScaleBarUnit );
251  }
252  else
253  {
254  return "0";
255  }
256 }
257 
259 {
260  return mFont;
261 }
262 
263 void QgsComposerScaleBar::setFont( const QFont& font )
264 {
265  mFont = font;
266  adjustBoxSize();
267  update();
268 }
269 
270 bool QgsComposerScaleBar::writeXML( QDomElement& elem, QDomDocument & doc ) const
271 {
272  if ( elem.isNull() )
273  {
274  return false;
275  }
276 
277  QDomElement composerScaleBarElem = doc.createElement( "ComposerScaleBar" );
278  composerScaleBarElem.setAttribute( "height", mHeight );
279  composerScaleBarElem.setAttribute( "labelBarSpace", mLabelBarSpace );
280  composerScaleBarElem.setAttribute( "boxContentSpace", mBoxContentSpace );
281  composerScaleBarElem.setAttribute( "numSegments", mNumSegments );
282  composerScaleBarElem.setAttribute( "numSegmentsLeft", mNumSegmentsLeft );
283  composerScaleBarElem.setAttribute( "numUnitsPerSegment", mNumUnitsPerSegment );
284  composerScaleBarElem.setAttribute( "segmentMillimeters", mSegmentMillimeters );
285  composerScaleBarElem.setAttribute( "numMapUnitsPerScaleBarUnit", mNumMapUnitsPerScaleBarUnit );
286  composerScaleBarElem.setAttribute( "font", mFont.toString() );
287  composerScaleBarElem.setAttribute( "outlineWidth", mPen.widthF() );
288  composerScaleBarElem.setAttribute( "unitLabel", mUnitLabeling );
289 
290  //style
291  if ( mStyle )
292  {
293  composerScaleBarElem.setAttribute( "style", mStyle->name() );
294  }
295 
296  //map id
297  if ( mComposerMap )
298  {
299  composerScaleBarElem.setAttribute( "mapId", mComposerMap->id() );
300  }
301 
302  //fill color
303  QColor brushColor = mBrush.color();
304  QDomElement colorElem = doc.createElement( "BrushColor" );
305  colorElem.setAttribute( "red", brushColor.red() );
306  colorElem.setAttribute( "green", brushColor.green() );
307  colorElem.setAttribute( "blue", brushColor.blue() );
308  composerScaleBarElem.appendChild( colorElem );
309 
310  elem.appendChild( composerScaleBarElem );
311  return _writeXML( composerScaleBarElem, doc );
312 }
313 
314 bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocument& doc )
315 {
316  if ( itemElem.isNull() )
317  {
318  return false;
319  }
320 
321  mHeight = itemElem.attribute( "height", "5.0" ).toDouble();
322  mLabelBarSpace = itemElem.attribute( "labelBarSpace", "3.0" ).toDouble();
323  mBoxContentSpace = itemElem.attribute( "boxContentSpace", "1.0" ).toDouble();
324  mNumSegments = itemElem.attribute( "numSegments", "2" ).toInt();
325  mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt();
326  mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble();
327  mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble();
328  mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble();
329  mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
330  mUnitLabeling = itemElem.attribute( "unitLabel" );
331  QString fontString = itemElem.attribute( "font", "" );
332  if ( !fontString.isEmpty() )
333  {
334  mFont.fromString( fontString );
335  }
336 
337  //style
338  delete mStyle;
339  mStyle = 0;
340  QString styleString = itemElem.attribute( "style", "" );
341  setStyle( tr( styleString.toLocal8Bit().data() ) );
342 
343  //map
344  int mapId = itemElem.attribute( "mapId", "-1" ).toInt();
345  if ( mapId >= 0 )
346  {
349  if ( mComposerMap )
350  {
351  connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
352  connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
353  }
354  }
355 
357 
358  //restore general composer item properties
359  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
360  if ( composerItemList.size() > 0 )
361  {
362  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
363  _readXML( composerItemElem, doc );
364  }
365 
366  return true;
367 }
368 
369