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