QGIS API Documentation  2.9.0-Master
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 "qgscomposition.h"
20 #include "qgscomposerutils.h"
21 #include "qgsdistancearea.h"
22 #include "qgsscalebarstyle.h"
24 #include "qgsmaprenderer.h"
27 #include "qgsticksscalebarstyle.h"
28 #include "qgsrectangle.h"
29 #include "qgsproject.h"
30 #include "qgssymbollayerv2utils.h"
31 #include <QDomDocument>
32 #include <QDomElement>
33 #include <QFontMetricsF>
34 #include <QPainter>
35 #include <QSettings>
36 #include <cmath>
37 
39  : QgsComposerItem( composition )
40  , mComposerMap( 0 )
41  , mNumUnitsPerSegment( 0 )
42  , mSegmentSizeMode( SegmentSizeFixed )
43  , mMinBarWidth( 50 )
44  , mMaxBarWidth( 150 )
45  , mFontColor( QColor( 0, 0, 0 ) )
46  , mStyle( 0 )
47  , mSegmentMillimeters( 0.0 )
48  , mAlignment( Left )
49  , mUnits( MapUnits )
50  , mLineJoinStyle( Qt::MiterJoin )
51  , mLineCapStyle( Qt::SquareCap )
52 {
55 }
56 
58 {
59  delete mStyle;
60 }
61 
62 void QgsComposerScaleBar::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
63 {
64  Q_UNUSED( itemStyle );
65  Q_UNUSED( pWidget );
66  if ( !mStyle || !painter )
67  {
68  return;
69  }
70  if ( !shouldDrawItem() )
71  {
72  return;
73  }
74 
75  drawBackground( painter );
76 
77  //x-offset is half of first label width because labels are drawn centered
78  QString firstLabel = firstLabelString();
79  double firstLabelWidth = QgsComposerUtils::textWidthMM( mFont, firstLabel );
80 
81  mStyle->draw( painter, firstLabelWidth / 2 );
82 
83  //draw frame and selection boxes if necessary
84  drawFrame( painter );
85  if ( isSelected() )
86  {
87  drawSelectionBoxes( painter );
88  }
89 }
90 
92 {
93  if ( !mStyle )
94  {
95  mNumSegments = nSegments;
96  return;
97  }
98  double width = mStyle->calculateBoxSize().width();
99  mNumSegments = nSegments;
100  double widthAfter = mStyle->calculateBoxSize().width();
101  correctXPositionAlignment( width, widthAfter );
102  emit itemChanged();
103 }
104 
106 {
107  if ( !mStyle )
108  {
110  return;
111  }
112  double width = mStyle->calculateBoxSize().width();
115  double widthAfter = mStyle->calculateBoxSize().width();
116  correctXPositionAlignment( width, widthAfter );
117  emit itemChanged();
118 }
119 
121 {
122  if ( !mStyle )
123  {
124  mSegmentSizeMode = mode;
125  return;
126  }
127  double width = mStyle->calculateBoxSize().width();
128  mSegmentSizeMode = mode;
130  double widthAfter = mStyle->calculateBoxSize().width();
131  correctXPositionAlignment( width, widthAfter );
132  emit itemChanged();
133 }
134 
135 void QgsComposerScaleBar::setMinBarWidth( double minWidth )
136 {
137  if ( !mStyle )
138  {
139  mMinBarWidth = minWidth;
140  return;
141  }
142  double width = mStyle->calculateBoxSize().width();
143  mMinBarWidth = minWidth;
145  double widthAfter = mStyle->calculateBoxSize().width();
146  correctXPositionAlignment( width, widthAfter );
147  emit itemChanged();
148 }
149 
150 void QgsComposerScaleBar::setMaxBarWidth( double maxWidth )
151 {
152  if ( !mStyle )
153  {
154  mMaxBarWidth = maxWidth;
155  return;
156  }
157  double width = mStyle->calculateBoxSize().width();
158  mMaxBarWidth = maxWidth;
160  double widthAfter = mStyle->calculateBoxSize().width();
161  correctXPositionAlignment( width, widthAfter );
162  emit itemChanged();
163 }
164 
166 {
167  if ( !mStyle )
168  {
169  mNumSegmentsLeft = nSegmentsLeft;
170  return;
171  }
172  double width = mStyle->calculateBoxSize().width();
173  mNumSegmentsLeft = nSegmentsLeft;
174  double widthAfter = mStyle->calculateBoxSize().width();
175  correctXPositionAlignment( width, widthAfter );
176  emit itemChanged();
177 }
178 
180 {
181  if ( !mStyle )
182  {
183  mBoxContentSpace = space;
184  return;
185  }
186  double width = mStyle->calculateBoxSize().width();
187  mBoxContentSpace = space;
188  double widthAfter = mStyle->calculateBoxSize().width();
189  correctXPositionAlignment( width, widthAfter );
190  emit itemChanged();
191 }
192 
194 {
195  if ( mComposerMap )
196  {
197  disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
198  disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
199  }
200  mComposerMap = map;
201 
202  if ( !map )
203  {
204  return;
205  }
206 
207  connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
208  connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
209 
211  emit itemChanged();
212 }
213 
215 {
216  if ( !mComposerMap )
217  {
218  return;
219  }
220 
221  disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
222  disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
223  mComposerMap = 0;
224 }
225 
226 // nextNiceNumber(4573.23, d) = 5000 (d=1) -> 4600 (d=10) -> 4580 (d=100) -> 4574 (d=1000) -> etc
227 inline double nextNiceNumber( double a, double d = 1 )
228 {
229  double s = qPow( 10.0, floor( log10( a ) ) ) / d;
230  return ceil( a / s ) * s;
231 }
232 
233 // prevNiceNumber(4573.23, d) = 4000 (d=1) -> 4500 (d=10) -> 4570 (d=100) -> 4573 (d=1000) -> etc
234 inline double prevNiceNumber( double a, double d = 1 )
235 {
236  double s = qPow( 10.0, floor( log10( a ) ) ) / d;
237  return floor( a / s ) * s;
238 }
239 
241 {
242  if ( mComposerMap )
243  {
244  //get mm dimension of composer map
245  QRectF composerItemRect = mComposerMap->rect();
246 
248  {
249  //calculate size depending on mNumUnitsPerSegment
250  mSegmentMillimeters = composerItemRect.width() / mapWidth() * mNumUnitsPerSegment;
251  }
252  else /*if(mSegmentSizeMode == SegmentSizeFitWidth)*/
253  {
254  if ( mMaxBarWidth < mMinBarWidth )
255  {
257  }
258  else
259  {
260  double nSegments = ( mNumSegmentsLeft != 0 ) + mNumSegments;
261  // unitsPerSegments which fit minBarWidth resp. maxBarWidth
262  double minUnitsPerSeg = ( mMinBarWidth * mapWidth() ) / ( nSegments * composerItemRect.width() );
263  double maxUnitsPerSeg = ( mMaxBarWidth * mapWidth() ) / ( nSegments * composerItemRect.width() );
264 
265  // Start with coarsest "nice" number closest to minUnitsPerSeg resp
266  // maxUnitsPerSeg, then proceed to finer numbers as long as neither
267  // lowerNiceUnitsPerSeg nor upperNiceUnitsPerSeg are are in
268  // [minUnitsPerSeg, maxUnitsPerSeg]
269  double lowerNiceUnitsPerSeg = nextNiceNumber( minUnitsPerSeg );
270  double upperNiceUnitsPerSeg = prevNiceNumber( maxUnitsPerSeg );
271 
272  double d = 1;
273  while ( lowerNiceUnitsPerSeg > maxUnitsPerSeg && upperNiceUnitsPerSeg < minUnitsPerSeg )
274  {
275  d *= 10;
276  lowerNiceUnitsPerSeg = nextNiceNumber( minUnitsPerSeg, d );
277  upperNiceUnitsPerSeg = prevNiceNumber( maxUnitsPerSeg, d );
278  }
279 
280  // Pick mNumUnitsPerSegment from {lowerNiceUnitsPerSeg, upperNiceUnitsPerSeg}, use the larger if possible
281  mNumUnitsPerSegment = upperNiceUnitsPerSeg < minUnitsPerSeg ? lowerNiceUnitsPerSeg : upperNiceUnitsPerSeg;
282  mSegmentMillimeters = composerItemRect.width() / mapWidth() * mNumUnitsPerSegment;
283  }
284  }
285  }
286 }
287 
289 {
290  if ( !mComposerMap )
291  {
292  return 0.0;
293  }
294 
295  QgsRectangle composerMapRect = *( mComposerMap->currentMapExtent() );
296  if ( mUnits == MapUnits )
297  {
298  return composerMapRect.width();
299  }
300  else
301  {
302  QgsDistanceArea da;
305  da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", "WGS84" ) );
306 
307  double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMinimum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) );
309  {
311  }
313  {
315  }
316  return measure;
317  }
318 }
319 
321 {
322  mAlignment = a;
323  update();
324  emit itemChanged();
325 }
326 
328 {
329  mUnits = u;
331  emit itemChanged();
332 }
333 
334 void QgsComposerScaleBar::setLineJoinStyle( Qt::PenJoinStyle style )
335 {
336  if ( mLineJoinStyle == style )
337  {
338  //no change
339  return;
340  }
342  mPen.setJoinStyle( mLineJoinStyle );
343  update();
344  emit itemChanged();
345 }
346 
347 void QgsComposerScaleBar::setLineCapStyle( Qt::PenCapStyle style )
348 {
349  if ( mLineCapStyle == style )
350  {
351  //no change
352  return;
353  }
355  mPen.setCapStyle( mLineCapStyle );
356  update();
357  emit itemChanged();
358 }
359 
361 {
362  mNumSegments = 2;
363  mNumSegmentsLeft = 0;
364 
366 
367  //style
368  delete mStyle;
369  mStyle = new QgsSingleBoxScaleBarStyle( this );
370 
371  mHeight = 3;
372 
373  //default to no background
374  setBackgroundEnabled( false );
375 
376  mPen = QPen( Qt::black );
377  mPen.setJoinStyle( mLineJoinStyle );
378  mPen.setCapStyle( mLineCapStyle );
379  mPen.setWidthF( 1.0 );
380 
381  mBrush.setColor( Qt::black );
382  mBrush.setStyle( Qt::SolidPattern );
383 
384  mBrush2.setColor( Qt::white );
385  mBrush2.setStyle( Qt::SolidPattern );
386 
387  //get default composer font from settings
388  QSettings settings;
389  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
390  if ( !defaultFontString.isEmpty() )
391  {
392  mFont.setFamily( defaultFontString );
393  }
394  mFont.setPointSizeF( 12.0 );
395  mFontColor = QColor( 0, 0, 0 );
396 
397  mLabelBarSpace = 3.0;
398  mBoxContentSpace = 1.0;
399  emit itemChanged();
400 }
401 
403 {
404  if ( mComposerMap )
405  {
406  setUnits( u );
407  double upperMagnitudeMultiplier = 1.0;
408  double widthInSelectedUnits = mapWidth();
409  double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
410  setNumUnitsPerSegment( initialUnitsPerSegment );
411 
412  switch ( mUnits )
413  {
414  case MapUnits:
415  {
416  upperMagnitudeMultiplier = 1.0;
417  setUnitLabeling( tr( "units" ) );
418  break;
419  }
420  case Meters:
421  {
422  if ( initialUnitsPerSegment > 1000.0 )
423  {
424  upperMagnitudeMultiplier = 1000.0;
425  setUnitLabeling( tr( "km" ) );
426  }
427  else
428  {
429  upperMagnitudeMultiplier = 1.0;
430  setUnitLabeling( tr( "m" ) );
431  }
432  break;
433  }
434  case Feet:
435  {
436  if ( initialUnitsPerSegment > 5419.95 )
437  {
438  upperMagnitudeMultiplier = 5419.95;
439  setUnitLabeling( tr( "miles" ) );
440  }
441  else
442  {
443  upperMagnitudeMultiplier = 1.0;
444  setUnitLabeling( tr( "ft" ) );
445  }
446  break;
447  }
448  case NauticalMiles:
449  {
450  upperMagnitudeMultiplier = 1;
451  setUnitLabeling( tr( "Nm" ) );
452  break;
453  }
454  }
455 
456  double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
457  int segmentMagnitude = floor( log10( segmentWidth ) );
458  double unitsPerSegment = upperMagnitudeMultiplier * ( qPow( 10.0, segmentMagnitude ) );
459  double multiplier = floor(( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
460 
461  if ( multiplier > 0 )
462  {
463  unitsPerSegment = unitsPerSegment * multiplier;
464  }
465  setNumUnitsPerSegment( unitsPerSegment );
466  setNumMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
467 
468  setNumSegments( 4 );
469  setNumSegmentsLeft( 2 );
470  }
471 
473  adjustBoxSize();
474  emit itemChanged();
475 }
476 
478 {
479  if ( !mStyle )
480  {
481  return;
482  }
483 
484  QRectF box = mStyle->calculateBoxSize();
485  if ( rect().height() > box.height() )
486  {
487  //keep user specified item height if higher than minimum scale bar height
488  box.setHeight( rect().height() );
489  }
490 
491  //update rect for data defined size and position
492  QRectF newRect = evalItemRect( box, true );
493 
494  //scale bars have a minimum size, respect that regardless of data defined settings
495  if ( newRect.width() < box.width() )
496  {
497  newRect.setWidth( box.width() );
498  }
499  if ( newRect.height() < box.height() )
500  {
501  newRect.setHeight( box.height() );
502  }
503 
505 }
506 
507 void QgsComposerScaleBar::setSceneRect( const QRectF& rectangle )
508 {
509  QRectF box = mStyle->calculateBoxSize();
510  if ( rectangle.height() > box.height() )
511  {
512  //keep user specified item height if higher than minimum scale bar height
513  box.setHeight( rectangle.height() );
514  }
515  box.moveTopLeft( rectangle.topLeft() );
516 
517  //update rect for data defined size and position
518  QRectF newRect = evalItemRect( rectangle );
519 
520  //scale bars have a minimum size, respect that regardless of data defined settings
521  if ( newRect.width() < box.width() )
522  {
523  newRect.setWidth( box.width() );
524  }
525  if ( newRect.height() < box.height() )
526  {
527  newRect.setHeight( box.height() );
528  }
529 
531 }
532 
534 {
535  //Don't adjust box size for numeric scale bars:
536  if ( mStyle && mStyle->name() != "Numeric" )
537  {
538  adjustBoxSize();
539  }
540  QgsComposerItem::update();
541 }
542 
544 {
545  if ( !mStyle )
546  {
547  return;
548  }
549  double width = mStyle->calculateBoxSize().width();
551  double widthAfter = mStyle->calculateBoxSize().width();
552  correctXPositionAlignment( width, widthAfter );
553  update();
554  emit itemChanged();
555 }
556 
557 void QgsComposerScaleBar::segmentPositions( QList<QPair<double, double> >& posWidthList ) const
558 {
559  posWidthList.clear();
560  double mCurrentXCoord = mPen.widthF() + mBoxContentSpace;
561 
562  //left segments
563  double leftSegmentSize = mSegmentMillimeters / mNumSegmentsLeft;
564  for ( int i = 0; i < mNumSegmentsLeft; ++i )
565  {
566  posWidthList.push_back( qMakePair( mCurrentXCoord, leftSegmentSize ) );
567  mCurrentXCoord += leftSegmentSize;
568  }
569 
570  //right segments
571  for ( int i = 0; i < mNumSegments; ++i )
572  {
573  posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters ) );
574  mCurrentXCoord += mSegmentMillimeters;
575  }
576 }
577 
578 void QgsComposerScaleBar::setStyle( const QString& styleName )
579 {
580  delete mStyle;
581  mStyle = 0;
582 
583  //switch depending on style name
584  if ( styleName == "Single Box" )
585  {
586  mStyle = new QgsSingleBoxScaleBarStyle( this );
587  }
588  else if ( styleName == "Double Box" )
589  {
590  mStyle = new QgsDoubleBoxScaleBarStyle( this );
591  }
592  else if ( styleName == "Line Ticks Middle" || styleName == "Line Ticks Down" || styleName == "Line Ticks Up" )
593  {
594  QgsTicksScaleBarStyle* tickStyle = new QgsTicksScaleBarStyle( this );
595  if ( styleName == "Line Ticks Middle" )
596  {
598  }
599  else if ( styleName == "Line Ticks Down" )
600  {
602  }
603  else if ( styleName == "Line Ticks Up" )
604  {
606  }
607  mStyle = tickStyle;
608  }
609  else if ( styleName == "Numeric" )
610  {
611  mStyle = new QgsNumericScaleBarStyle( this );
612  }
613  emit itemChanged();
614 }
615 
617 {
618  if ( mStyle )
619  {
620  return mStyle->name();
621  }
622  else
623  {
624  return "";
625  }
626 }
627 
629 {
630  if ( mNumSegmentsLeft > 0 )
631  {
632  return QString::number( mNumUnitsPerSegment / mNumMapUnitsPerScaleBarUnit );
633  }
634  else
635  {
636  return "0";
637  }
638 }
639 
641 {
642  return mFont;
643 }
644 
645 void QgsComposerScaleBar::setFont( const QFont& font )
646 {
647  mFont = font;
648  update();
649  emit itemChanged();
650 }
651 
652 bool QgsComposerScaleBar::writeXML( QDomElement& elem, QDomDocument & doc ) const
653 {
654  if ( elem.isNull() )
655  {
656  return false;
657  }
658 
659  QDomElement composerScaleBarElem = doc.createElement( "ComposerScaleBar" );
660  composerScaleBarElem.setAttribute( "height", QString::number( mHeight ) );
661  composerScaleBarElem.setAttribute( "labelBarSpace", QString::number( mLabelBarSpace ) );
662  composerScaleBarElem.setAttribute( "boxContentSpace", QString::number( mBoxContentSpace ) );
663  composerScaleBarElem.setAttribute( "numSegments", mNumSegments );
664  composerScaleBarElem.setAttribute( "numSegmentsLeft", mNumSegmentsLeft );
665  composerScaleBarElem.setAttribute( "numUnitsPerSegment", QString::number( mNumUnitsPerSegment ) );
666  composerScaleBarElem.setAttribute( "segmentSizeMode", mSegmentSizeMode );
667  composerScaleBarElem.setAttribute( "minBarWidth", mMinBarWidth );
668  composerScaleBarElem.setAttribute( "maxBarWidth", mMaxBarWidth );
669  composerScaleBarElem.setAttribute( "segmentMillimeters", QString::number( mSegmentMillimeters ) );
670  composerScaleBarElem.setAttribute( "numMapUnitsPerScaleBarUnit", QString::number( mNumMapUnitsPerScaleBarUnit ) );
671  composerScaleBarElem.setAttribute( "font", mFont.toString() );
672  composerScaleBarElem.setAttribute( "outlineWidth", QString::number( mPen.widthF() ) );
673  composerScaleBarElem.setAttribute( "unitLabel", mUnitLabeling );
674  composerScaleBarElem.setAttribute( "units", mUnits );
675  composerScaleBarElem.setAttribute( "lineJoinStyle", QgsSymbolLayerV2Utils::encodePenJoinStyle( mLineJoinStyle ) );
676  composerScaleBarElem.setAttribute( "lineCapStyle", QgsSymbolLayerV2Utils::encodePenCapStyle( mLineCapStyle ) );
677 
678  //style
679  if ( mStyle )
680  {
681  composerScaleBarElem.setAttribute( "style", mStyle->name() );
682  }
683 
684  //map id
685  if ( mComposerMap )
686  {
687  composerScaleBarElem.setAttribute( "mapId", mComposerMap->id() );
688  }
689 
690  //colors
691 
692  //fill color
693  QDomElement fillColorElem = doc.createElement( "fillColor" );
694  QColor fillColor = mBrush.color();
695  fillColorElem.setAttribute( "red", QString::number( fillColor.red() ) );
696  fillColorElem.setAttribute( "green", QString::number( fillColor.green() ) );
697  fillColorElem.setAttribute( "blue", QString::number( fillColor.blue() ) );
698  fillColorElem.setAttribute( "alpha", QString::number( fillColor.alpha() ) );
699  composerScaleBarElem.appendChild( fillColorElem );
700 
701  //fill color 2
702  QDomElement fillColor2Elem = doc.createElement( "fillColor2" );
703  QColor fillColor2 = mBrush2.color();
704  fillColor2Elem.setAttribute( "red", QString::number( fillColor2.red() ) );
705  fillColor2Elem.setAttribute( "green", QString::number( fillColor2.green() ) );
706  fillColor2Elem.setAttribute( "blue", QString::number( fillColor2.blue() ) );
707  fillColor2Elem.setAttribute( "alpha", QString::number( fillColor2.alpha() ) );
708  composerScaleBarElem.appendChild( fillColor2Elem );
709 
710  //pen color
711  QDomElement strokeColorElem = doc.createElement( "strokeColor" );
712  QColor strokeColor = mPen.color();
713  strokeColorElem.setAttribute( "red", QString::number( strokeColor.red() ) );
714  strokeColorElem.setAttribute( "green", QString::number( strokeColor.green() ) );
715  strokeColorElem.setAttribute( "blue", QString::number( strokeColor.blue() ) );
716  strokeColorElem.setAttribute( "alpha", QString::number( strokeColor.alpha() ) );
717  composerScaleBarElem.appendChild( strokeColorElem );
718 
719  //font color
720  QDomElement fontColorElem = doc.createElement( "textColor" );
721  fontColorElem.setAttribute( "red", QString::number( mFontColor.red() ) );
722  fontColorElem.setAttribute( "green", QString::number( mFontColor.green() ) );
723  fontColorElem.setAttribute( "blue", QString::number( mFontColor.blue() ) );
724  fontColorElem.setAttribute( "alpha", QString::number( mFontColor.alpha() ) );
725  composerScaleBarElem.appendChild( fontColorElem );
726 
727  //alignment
728  composerScaleBarElem.setAttribute( "alignment", QString::number(( int ) mAlignment ) );
729 
730  elem.appendChild( composerScaleBarElem );
731  return _writeXML( composerScaleBarElem, doc );
732 }
733 
734 bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocument& doc )
735 {
736  if ( itemElem.isNull() )
737  {
738  return false;
739  }
740 
741  mHeight = itemElem.attribute( "height", "5.0" ).toDouble();
742  mLabelBarSpace = itemElem.attribute( "labelBarSpace", "3.0" ).toDouble();
743  mBoxContentSpace = itemElem.attribute( "boxContentSpace", "1.0" ).toDouble();
744  mNumSegments = itemElem.attribute( "numSegments", "2" ).toInt();
745  mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt();
746  mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble();
747  mSegmentSizeMode = static_cast<SegmentSizeMode>( itemElem.attribute( "segmentSizeMode", "0" ).toInt() );
748  mMinBarWidth = itemElem.attribute( "minBarWidth", "50" ).toInt();
749  mMaxBarWidth = itemElem.attribute( "maxBarWidth", "150" ).toInt();
750  mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble();
751  mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble();
752  mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
753  mUnitLabeling = itemElem.attribute( "unitLabel" );
754  mLineJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( itemElem.attribute( "lineJoinStyle", "miter" ) );
755  mPen.setJoinStyle( mLineJoinStyle );
756  mLineCapStyle = QgsSymbolLayerV2Utils::decodePenCapStyle( itemElem.attribute( "lineCapStyle", "square" ) );
757  mPen.setCapStyle( mLineCapStyle );
758  QString fontString = itemElem.attribute( "font", "" );
759  if ( !fontString.isEmpty() )
760  {
761  mFont.fromString( fontString );
762  }
763 
764  //colors
765  //fill color
766  QDomNodeList fillColorList = itemElem.elementsByTagName( "fillColor" );
767  if ( fillColorList.size() > 0 )
768  {
769  QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
770  bool redOk, greenOk, blueOk, alphaOk;
771  int fillRed, fillGreen, fillBlue, fillAlpha;
772 
773  fillRed = fillColorElem.attribute( "red" ).toDouble( &redOk );
774  fillGreen = fillColorElem.attribute( "green" ).toDouble( &greenOk );
775  fillBlue = fillColorElem.attribute( "blue" ).toDouble( &blueOk );
776  fillAlpha = fillColorElem.attribute( "alpha" ).toDouble( &alphaOk );
777 
778  if ( redOk && greenOk && blueOk && alphaOk )
779  {
780  mBrush.setColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
781  }
782  }
783  else
784  {
785  mBrush.setColor( QColor( itemElem.attribute( "brushColor", "#000000" ) ) );
786  }
787 
788  //fill color 2
789  QDomNodeList fillColor2List = itemElem.elementsByTagName( "fillColor2" );
790  if ( fillColor2List.size() > 0 )
791  {
792  QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
793  bool redOk, greenOk, blueOk, alphaOk;
794  int fillRed, fillGreen, fillBlue, fillAlpha;
795 
796  fillRed = fillColor2Elem.attribute( "red" ).toDouble( &redOk );
797  fillGreen = fillColor2Elem.attribute( "green" ).toDouble( &greenOk );
798  fillBlue = fillColor2Elem.attribute( "blue" ).toDouble( &blueOk );
799  fillAlpha = fillColor2Elem.attribute( "alpha" ).toDouble( &alphaOk );
800 
801  if ( redOk && greenOk && blueOk && alphaOk )
802  {
803  mBrush2.setColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
804  }
805  }
806  else
807  {
808  mBrush2.setColor( QColor( itemElem.attribute( "brush2Color", "#ffffff" ) ) );
809  }
810 
811  //stroke color
812  QDomNodeList strokeColorList = itemElem.elementsByTagName( "strokeColor" );
813  if ( strokeColorList.size() > 0 )
814  {
815  QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
816  bool redOk, greenOk, blueOk, alphaOk;
817  int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
818 
819  strokeRed = strokeColorElem.attribute( "red" ).toDouble( &redOk );
820  strokeGreen = strokeColorElem.attribute( "green" ).toDouble( &greenOk );
821  strokeBlue = strokeColorElem.attribute( "blue" ).toDouble( &blueOk );
822  strokeAlpha = strokeColorElem.attribute( "alpha" ).toDouble( &alphaOk );
823 
824  if ( redOk && greenOk && blueOk && alphaOk )
825  {
826  mPen.setColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
827  }
828  }
829  else
830  {
831  mPen.setColor( QColor( itemElem.attribute( "penColor", "#000000" ) ) );
832  }
833 
834  //font color
835  QDomNodeList textColorList = itemElem.elementsByTagName( "textColor" );
836  if ( textColorList.size() > 0 )
837  {
838  QDomElement textColorElem = textColorList.at( 0 ).toElement();
839  bool redOk, greenOk, blueOk, alphaOk;
840  int textRed, textGreen, textBlue, textAlpha;
841 
842  textRed = textColorElem.attribute( "red" ).toDouble( &redOk );
843  textGreen = textColorElem.attribute( "green" ).toDouble( &greenOk );
844  textBlue = textColorElem.attribute( "blue" ).toDouble( &blueOk );
845  textAlpha = textColorElem.attribute( "alpha" ).toDouble( &alphaOk );
846 
847  if ( redOk && greenOk && blueOk && alphaOk )
848  {
849  mFontColor = QColor( textRed, textGreen, textBlue, textAlpha );
850  }
851  }
852  else
853  {
854  mFontColor.setNamedColor( itemElem.attribute( "fontColor", "#000000" ) );
855  }
856 
857  //style
858  delete mStyle;
859  mStyle = 0;
860  QString styleString = itemElem.attribute( "style", "" );
861  setStyle( tr( styleString.toLocal8Bit().data() ) );
862 
863  mUnits = ( ScaleBarUnits )itemElem.attribute( "units" ).toInt();
864  mAlignment = ( Alignment )( itemElem.attribute( "alignment", "0" ).toInt() );
865 
866  //map
867  int mapId = itemElem.attribute( "mapId", "-1" ).toInt();
868  if ( mapId >= 0 )
869  {
872  if ( mComposerMap )
873  {
874  connect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateSegmentSize() ) );
875  connect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
876  }
877  }
878 
880 
881  //restore general composer item properties
882  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
883  if ( composerItemList.size() > 0 )
884  {
885  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
886  _readXML( composerItemElem, doc );
887  }
888 
889  return true;
890 }
891 
892 void QgsComposerScaleBar::correctXPositionAlignment( double width, double widthAfter )
893 {
894  //Don't adjust position for numeric scale bars:
895  if ( mStyle->name() == "Numeric" )
896  {
897  return;
898  }
899 
900  if ( mAlignment == Middle )
901  {
902  move( -( widthAfter - width ) / 2.0, 0 );
903  }
904  else if ( mAlignment == Right )
905  {
906  move( -( widthAfter - width ), 0 );
907  }
908 }
909 
Double box with alternating colors.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double mLabelBarSpace
Space between bar and Text labels.
double mHeight
Height of bars/lines.
double mNumUnitsPerSegment
Size of a segment (in map units)
void setUnits(ScaleBarUnits u)
void setLineCapStyle(Qt::PenCapStyle style)
Sets cap style used when drawing the lines in the scalebar.
double mNumMapUnitsPerScaleBarUnit
Number of map units per scale bar units (e.g.
void setFont(const QFont &font)
A scale bar style that draws text in the form of '1:XXXXX'.
void itemChanged()
Emitted when the item changes.
Qt::PenJoinStyle mLineJoinStyle
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
void setUnitLabeling(const QString &label)
void applyDefaultSize(ScaleBarUnits u=Meters)
Apply default size (scale bar 1/5 of map item width)
void setAlignment(Alignment a)
void applyDefaultSettings()
Apply default settings.
A item that forms part of a map composition.
void setNumSegments(int nSegments)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
void segmentPositions(QList< QPair< double, double > > &posWidthList) const
Returns the x - positions of the segment borders (in item coordinates) and the width of the segment...
virtual QRectF calculateBoxSize() const
void setNumSegmentsLeft(int nSegmentsLeft)
double mMinBarWidth
Minimum allowed bar width, when mSegmentSizeMode is FitWidth.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
ScaleBarUnits units() const
virtual void drawFrame(QPainter *p)
Draw black frame around item.
QgsScaleBarStyle * mStyle
Scalebar style.
QBrush mBrush2
Secondary fill.
virtual QString name() const =0
bool setEllipsoid(const QString &ellipsoid)
sets ellipsoid by its acronym
void update()
Adjusts box size and calls QgsComposerItem::update()
void setMinBarWidth(double minWidth)
Sets the minimum size (in millimeters) for scale bar segments.
A scale bar that draws segments using short ticks.
void setNumMapUnitsPerScaleBarUnit(double d)
void adjustBoxSize()
Sets box size suitable to content.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
void setMaxBarWidth(double maxWidth)
Sets the maximum size (in millimeters) for scale bar segments.
double mSegmentMillimeters
Width of a segment (in mm)
void setLineJoinStyle(Qt::PenJoinStyle style)
Sets join style used when drawing the lines in the scalebar.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:197
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:182
static Qt::PenCapStyle decodePenCapStyle(QString str)
virtual void drawSelectionBoxes(QPainter *p)
Draws additional graphics on selected items.
Qt::PenCapStyle mLineCapStyle
void setStyle(const QString &styleName)
Sets style by name.
virtual void draw(QPainter *p, double xOffset=0) const =0
Draws the style.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
double measureLine(const QList< QgsPoint > &points) const
measures line
double prevNiceNumber(double a, double d=1)
QgsComposerScaleBar(QgsComposition *composition)
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
stores state in Dom element
int mNumSegmentsLeft
Number of segments on left side.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
sets state from Dom document
SegmentSizeMode
Modes for setting size for scale bar segments.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
void setBackgroundEnabled(const bool drawBackground)
Set whether this item has a Background drawn around it or not.
A class to represent a point.
Definition: qgspoint.h:63
const QgsComposerMap * composerMap() const
Graphics scene for map printing.
Object representing map window.
QString style() const
Returns style name.
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
void setComposerMap(const QgsComposerMap *map)
void refreshSegmentMillimeters()
Calculates with of a segment in mm and stores it in mSegmentMillimeters.
void invalidateCurrentMap()
Sets mCompositionMap to 0 if the map is deleted.
void setBoxContentSpace(double space)
int id() const
Get identification number.
General purpose distance and area calculator.
static double textWidthMM(const QFont &font, const QString &text)
Calculate font width in millimeters for a string, including workarounds for QT font rendering issues...
QgsComposition * mComposition
int mNumSegments
Number of segments on right side.
QRectF evalItemRect(const QRectF &newRect, const bool resizeOnly=false)
Evaluates an item's bounding rect to consider data defined position and size of item and reference po...
double mMaxBarWidth
Maximum allowed bar width, when mSegmentSizeMode is FitWidth.
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
void setSegmentSizeMode(SegmentSizeMode mode)
Sets the size mode for scale bar segments.
SegmentSizeMode mSegmentSizeMode
Either fixed (i.e.
virtual void drawBackground(QPainter *p)
Draw background.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:351
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
double mBoxContentSpace
Space between content and item box.
static double fromUnitToUnitFactor(QGis::UnitType fromUnit, QGis::UnitType toUnit)
Returns the conversion factor between the specified units.
Definition: qgis.cpp:136
QString mUnitLabeling
Labeling of map units.
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
void setSceneRect(const QRectF &rectangle) override
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
double nextNiceNumber(double a, double d=1)
double mapWidth() const
Returns diagonal of composer map in selected units (map units / meters / feet / nautical miles) ...
const QgsComposerMap * mComposerMap
Reference to composer map object.
void setNumUnitsPerSegment(double units)
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:202
void move(double dx, double dy)
Moves item in canvas coordinates.
Scalebar style that draws a single box with alternating color for the segments.
void correctXPositionAlignment(double width, double widthAfter)
Moves scalebar position to the left / right depending on alignment and change in item width...
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:187
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
void setTickPosition(TickPosition p)
QString firstLabelString() const
Returns string of first label (important for drawing, labeling, size calculation. ...
static QString encodePenCapStyle(Qt::PenCapStyle style)
#define tr(sourceText)