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