QGIS API Documentation  2.11.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 "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 
308  double measure = da.measureLine( QgsPoint( composerMapRect.xMinimum(), composerMapRect.yMinimum() ), QgsPoint( composerMapRect.xMaximum(), composerMapRect.yMinimum() ) );
310  {
312  }
314  {
316  }
317  return measure;
318  }
319 }
320 
322 {
323  mAlignment = a;
324  update();
325  emit itemChanged();
326 }
327 
329 {
330  mUnits = u;
332  emit itemChanged();
333 }
334 
335 void QgsComposerScaleBar::setLineJoinStyle( Qt::PenJoinStyle style )
336 {
337  if ( mLineJoinStyle == style )
338  {
339  //no change
340  return;
341  }
344  update();
345  emit itemChanged();
346 }
347 
348 void QgsComposerScaleBar::setLineCapStyle( Qt::PenCapStyle style )
349 {
350  if ( mLineCapStyle == style )
351  {
352  //no change
353  return;
354  }
357  update();
358  emit itemChanged();
359 }
360 
362 {
363  mNumSegments = 2;
364  mNumSegmentsLeft = 0;
365 
367 
368  //style
369  delete mStyle;
370  mStyle = new QgsSingleBoxScaleBarStyle( this );
371 
372  mHeight = 3;
373 
374  //default to no background
375  setBackgroundEnabled( false );
376 
377  mPen = QPen( Qt::black );
380  mPen.setWidthF( 1.0 );
381 
382  mBrush.setColor( Qt::black );
383  mBrush.setStyle( Qt::SolidPattern );
384 
385  mBrush2.setColor( Qt::white );
386  mBrush2.setStyle( Qt::SolidPattern );
387 
388  //get default composer font from settings
389  QSettings settings;
390  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
391  if ( !defaultFontString.isEmpty() )
392  {
393  mFont.setFamily( defaultFontString );
394  }
395  mFont.setPointSizeF( 12.0 );
396  mFontColor = QColor( 0, 0, 0 );
397 
398  mLabelBarSpace = 3.0;
399  mBoxContentSpace = 1.0;
400  emit itemChanged();
401 }
402 
404 {
405  if ( mComposerMap )
406  {
407  setUnits( u );
408  double upperMagnitudeMultiplier = 1.0;
409  double widthInSelectedUnits = mapWidth();
410  double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
411  setNumUnitsPerSegment( initialUnitsPerSegment );
412 
413  switch ( mUnits )
414  {
415  case MapUnits:
416  {
417  upperMagnitudeMultiplier = 1.0;
418  setUnitLabeling( tr( "units" ) );
419  break;
420  }
421  case Meters:
422  {
423  if ( initialUnitsPerSegment > 1000.0 )
424  {
425  upperMagnitudeMultiplier = 1000.0;
426  setUnitLabeling( tr( "km" ) );
427  }
428  else
429  {
430  upperMagnitudeMultiplier = 1.0;
431  setUnitLabeling( tr( "m" ) );
432  }
433  break;
434  }
435  case Feet:
436  {
437  if ( initialUnitsPerSegment > 5419.95 )
438  {
439  upperMagnitudeMultiplier = 5419.95;
440  setUnitLabeling( tr( "miles" ) );
441  }
442  else
443  {
444  upperMagnitudeMultiplier = 1.0;
445  setUnitLabeling( tr( "ft" ) );
446  }
447  break;
448  }
449  case NauticalMiles:
450  {
451  upperMagnitudeMultiplier = 1;
452  setUnitLabeling( tr( "Nm" ) );
453  break;
454  }
455  }
456 
457  double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
458  int segmentMagnitude = floor( log10( segmentWidth ) );
459  double unitsPerSegment = upperMagnitudeMultiplier * ( qPow( 10.0, segmentMagnitude ) );
460  double multiplier = floor(( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
461 
462  if ( multiplier > 0 )
463  {
464  unitsPerSegment = unitsPerSegment * multiplier;
465  }
466  setNumUnitsPerSegment( unitsPerSegment );
467  setNumMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
468 
469  setNumSegments( 4 );
470  setNumSegmentsLeft( 2 );
471  }
472 
474  adjustBoxSize();
475  emit itemChanged();
476 }
477 
479 {
480  if ( !mStyle )
481  {
482  return;
483  }
484 
485  QRectF box = mStyle->calculateBoxSize();
486  if ( rect().height() > box.height() )
487  {
488  //keep user specified item height if higher than minimum scale bar height
489  box.setHeight( rect().height() );
490  }
491 
492  //update rect for data defined size and position
493  QRectF newRect = evalItemRect( box, true );
494 
495  //scale bars have a minimum size, respect that regardless of data defined settings
496  if ( newRect.width() < box.width() )
497  {
498  newRect.setWidth( box.width() );
499  }
500  if ( newRect.height() < box.height() )
501  {
502  newRect.setHeight( box.height() );
503  }
504 
506 }
507 
509 {
510  QRectF box = mStyle->calculateBoxSize();
511  if ( rectangle.height() > box.height() )
512  {
513  //keep user specified item height if higher than minimum scale bar height
514  box.setHeight( rectangle.height() );
515  }
516  box.moveTopLeft( rectangle.topLeft() );
517 
518  //update rect for data defined size and position
519  QRectF newRect = evalItemRect( rectangle );
520 
521  //scale bars have a minimum size, respect that regardless of data defined settings
522  if ( newRect.width() < box.width() )
523  {
524  newRect.setWidth( box.width() );
525  }
526  if ( newRect.height() < box.height() )
527  {
528  newRect.setHeight( box.height() );
529  }
530 
532 }
533 
535 {
536  //Don't adjust box size for numeric scale bars:
537  if ( mStyle && mStyle->name() != "Numeric" )
538  {
539  adjustBoxSize();
540  }
542 }
543 
545 {
546  if ( !mStyle )
547  {
548  return;
549  }
550  double width = mStyle->calculateBoxSize().width();
552  double widthAfter = mStyle->calculateBoxSize().width();
553  correctXPositionAlignment( width, widthAfter );
554  update();
555  emit itemChanged();
556 }
557 
559 {
560  posWidthList.clear();
561  double mCurrentXCoord = mPen.widthF() + mBoxContentSpace;
562 
563  //left segments
564  double leftSegmentSize = mSegmentMillimeters / mNumSegmentsLeft;
565  for ( int i = 0; i < mNumSegmentsLeft; ++i )
566  {
567  posWidthList.push_back( qMakePair( mCurrentXCoord, leftSegmentSize ) );
568  mCurrentXCoord += leftSegmentSize;
569  }
570 
571  //right segments
572  for ( int i = 0; i < mNumSegments; ++i )
573  {
574  posWidthList.push_back( qMakePair( mCurrentXCoord, mSegmentMillimeters ) );
575  mCurrentXCoord += mSegmentMillimeters;
576  }
577 }
578 
579 void QgsComposerScaleBar::setStyle( const QString& styleName )
580 {
581  delete mStyle;
582  mStyle = 0;
583 
584  //switch depending on style name
585  if ( styleName == "Single Box" )
586  {
587  mStyle = new QgsSingleBoxScaleBarStyle( this );
588  }
589  else if ( styleName == "Double Box" )
590  {
591  mStyle = new QgsDoubleBoxScaleBarStyle( this );
592  }
593  else if ( styleName == "Line Ticks Middle" || styleName == "Line Ticks Down" || styleName == "Line Ticks Up" )
594  {
595  QgsTicksScaleBarStyle* tickStyle = new QgsTicksScaleBarStyle( this );
596  if ( styleName == "Line Ticks Middle" )
597  {
599  }
600  else if ( styleName == "Line Ticks Down" )
601  {
603  }
604  else if ( styleName == "Line Ticks Up" )
605  {
607  }
608  mStyle = tickStyle;
609  }
610  else if ( styleName == "Numeric" )
611  {
612  mStyle = new QgsNumericScaleBarStyle( this );
613  }
614  emit itemChanged();
615 }
616 
618 {
619  if ( mStyle )
620  {
621  return mStyle->name();
622  }
623  else
624  {
625  return "";
626  }
627 }
628 
630 {
631  if ( mNumSegmentsLeft > 0 )
632  {
634  }
635  else
636  {
637  return "0";
638  }
639 }
640 
642 {
643  return mFont;
644 }
645 
647 {
648  mFont = font;
649  update();
650  emit itemChanged();
651 }
652 
654 {
655  if ( elem.isNull() )
656  {
657  return false;
658  }
659 
660  QDomElement composerScaleBarElem = doc.createElement( "ComposerScaleBar" );
661  composerScaleBarElem.setAttribute( "height", QString::number( mHeight ) );
662  composerScaleBarElem.setAttribute( "labelBarSpace", QString::number( mLabelBarSpace ) );
663  composerScaleBarElem.setAttribute( "boxContentSpace", QString::number( mBoxContentSpace ) );
664  composerScaleBarElem.setAttribute( "numSegments", mNumSegments );
665  composerScaleBarElem.setAttribute( "numSegmentsLeft", mNumSegmentsLeft );
666  composerScaleBarElem.setAttribute( "numUnitsPerSegment", QString::number( mNumUnitsPerSegment ) );
667  composerScaleBarElem.setAttribute( "segmentSizeMode", mSegmentSizeMode );
668  composerScaleBarElem.setAttribute( "minBarWidth", mMinBarWidth );
669  composerScaleBarElem.setAttribute( "maxBarWidth", mMaxBarWidth );
670  composerScaleBarElem.setAttribute( "segmentMillimeters", QString::number( mSegmentMillimeters ) );
671  composerScaleBarElem.setAttribute( "numMapUnitsPerScaleBarUnit", QString::number( mNumMapUnitsPerScaleBarUnit ) );
672  composerScaleBarElem.appendChild( QgsFontUtils::toXmlElement( mFont, doc, "scaleBarFont" ) );
673  composerScaleBarElem.setAttribute( "outlineWidth", QString::number( mPen.widthF() ) );
674  composerScaleBarElem.setAttribute( "unitLabel", mUnitLabeling );
675  composerScaleBarElem.setAttribute( "units", mUnits );
676  composerScaleBarElem.setAttribute( "lineJoinStyle", QgsSymbolLayerV2Utils::encodePenJoinStyle( mLineJoinStyle ) );
677  composerScaleBarElem.setAttribute( "lineCapStyle", QgsSymbolLayerV2Utils::encodePenCapStyle( mLineCapStyle ) );
678 
679  //style
680  if ( mStyle )
681  {
682  composerScaleBarElem.setAttribute( "style", mStyle->name() );
683  }
684 
685  //map id
686  if ( mComposerMap )
687  {
688  composerScaleBarElem.setAttribute( "mapId", mComposerMap->id() );
689  }
690 
691  //colors
692 
693  //fill color
694  QDomElement fillColorElem = doc.createElement( "fillColor" );
695  QColor fillColor = mBrush.color();
696  fillColorElem.setAttribute( "red", QString::number( fillColor.red() ) );
697  fillColorElem.setAttribute( "green", QString::number( fillColor.green() ) );
698  fillColorElem.setAttribute( "blue", QString::number( fillColor.blue() ) );
699  fillColorElem.setAttribute( "alpha", QString::number( fillColor.alpha() ) );
700  composerScaleBarElem.appendChild( fillColorElem );
701 
702  //fill color 2
703  QDomElement fillColor2Elem = doc.createElement( "fillColor2" );
704  QColor fillColor2 = mBrush2.color();
705  fillColor2Elem.setAttribute( "red", QString::number( fillColor2.red() ) );
706  fillColor2Elem.setAttribute( "green", QString::number( fillColor2.green() ) );
707  fillColor2Elem.setAttribute( "blue", QString::number( fillColor2.blue() ) );
708  fillColor2Elem.setAttribute( "alpha", QString::number( fillColor2.alpha() ) );
709  composerScaleBarElem.appendChild( fillColor2Elem );
710 
711  //pen color
712  QDomElement strokeColorElem = doc.createElement( "strokeColor" );
713  QColor strokeColor = mPen.color();
714  strokeColorElem.setAttribute( "red", QString::number( strokeColor.red() ) );
715  strokeColorElem.setAttribute( "green", QString::number( strokeColor.green() ) );
716  strokeColorElem.setAttribute( "blue", QString::number( strokeColor.blue() ) );
717  strokeColorElem.setAttribute( "alpha", QString::number( strokeColor.alpha() ) );
718  composerScaleBarElem.appendChild( strokeColorElem );
719 
720  //font color
721  QDomElement fontColorElem = doc.createElement( "textColor" );
722  fontColorElem.setAttribute( "red", QString::number( mFontColor.red() ) );
723  fontColorElem.setAttribute( "green", QString::number( mFontColor.green() ) );
724  fontColorElem.setAttribute( "blue", QString::number( mFontColor.blue() ) );
725  fontColorElem.setAttribute( "alpha", QString::number( mFontColor.alpha() ) );
726  composerScaleBarElem.appendChild( fontColorElem );
727 
728  //alignment
729  composerScaleBarElem.setAttribute( "alignment", QString::number(( int ) mAlignment ) );
730 
731  elem.appendChild( composerScaleBarElem );
732  return _writeXML( composerScaleBarElem, doc );
733 }
734 
735 bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocument& doc )
736 {
737  if ( itemElem.isNull() )
738  {
739  return false;
740  }
741 
742  mHeight = itemElem.attribute( "height", "5.0" ).toDouble();
743  mLabelBarSpace = itemElem.attribute( "labelBarSpace", "3.0" ).toDouble();
744  mBoxContentSpace = itemElem.attribute( "boxContentSpace", "1.0" ).toDouble();
745  mNumSegments = itemElem.attribute( "numSegments", "2" ).toInt();
746  mNumSegmentsLeft = itemElem.attribute( "numSegmentsLeft", "0" ).toInt();
747  mNumUnitsPerSegment = itemElem.attribute( "numUnitsPerSegment", "1.0" ).toDouble();
748  mSegmentSizeMode = static_cast<SegmentSizeMode>( itemElem.attribute( "segmentSizeMode", "0" ).toInt() );
749  mMinBarWidth = itemElem.attribute( "minBarWidth", "50" ).toInt();
750  mMaxBarWidth = itemElem.attribute( "maxBarWidth", "150" ).toInt();
751  mSegmentMillimeters = itemElem.attribute( "segmentMillimeters", "0.0" ).toDouble();
752  mNumMapUnitsPerScaleBarUnit = itemElem.attribute( "numMapUnitsPerScaleBarUnit", "1.0" ).toDouble();
753  mPen.setWidthF( itemElem.attribute( "outlineWidth", "1.0" ).toDouble() );
754  mUnitLabeling = itemElem.attribute( "unitLabel" );
755  mLineJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( itemElem.attribute( "lineJoinStyle", "miter" ) );
757  mLineCapStyle = QgsSymbolLayerV2Utils::decodePenCapStyle( itemElem.attribute( "lineCapStyle", "square" ) );
759  if ( !QgsFontUtils::setFromXmlChildNode( mFont, itemElem, "scaleBarFont" ) )
760  {
761  mFont.fromString( itemElem.attribute( "font", "" ) );
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.
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
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)
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: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.
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)
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:352
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:136
qreal widthF() const
char * data()
QString mUnitLabeling
Labeling of map units.
static Qt::PenJoinStyle decodePenJoinStyle(QString str)
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:202
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:187
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)