Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgslayoutitemscalebar.cpp
3 : : -------------------------
4 : : begin : November 2017
5 : : copyright : (C) 2017 by Nyall Dawson
6 : : email : nyall dot dawson at gmail dot com
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 "qgslayoutitemscalebar.h"
18 : : #include "qgslayoutitemregistry.h"
19 : : #include "qgsscalebarrendererregistry.h"
20 : : #include "qgslayoutitemmap.h"
21 : : #include "qgslayout.h"
22 : : #include "qgslayoututils.h"
23 : : #include "qgsdistancearea.h"
24 : : #include "qgssingleboxscalebarrenderer.h"
25 : : #include "qgsscalebarrenderer.h"
26 : : #include "qgsmapsettings.h"
27 : : #include "qgsrectangle.h"
28 : : #include "qgsproject.h"
29 : : #include "qgssymbollayerutils.h"
30 : : #include "qgsfontutils.h"
31 : : #include "qgsunittypes.h"
32 : : #include "qgssettings.h"
33 : : #include "qgsstyleentityvisitor.h"
34 : : #include "qgsnumericformat.h"
35 : : #include "qgsnumericformatregistry.h"
36 : : #include "qgslinesymbollayer.h"
37 : : #include "qgsfillsymbollayer.h"
38 : :
39 : : #include <QDomDocument>
40 : : #include <QDomElement>
41 : : #include <QFontMetricsF>
42 : : #include <QPainter>
43 : :
44 : : #include <cmath>
45 : :
46 : 0 : QgsLayoutItemScaleBar::QgsLayoutItemScaleBar( QgsLayout *layout )
47 : 0 : : QgsLayoutItem( layout )
48 : 0 : {
49 : 0 : applyDefaultSettings();
50 : 0 : applyDefaultSize();
51 : 0 : }
52 : :
53 : 0 : int QgsLayoutItemScaleBar::type() const
54 : : {
55 : 0 : return QgsLayoutItemRegistry::LayoutScaleBar;
56 : : }
57 : :
58 : 0 : QIcon QgsLayoutItemScaleBar::icon() const
59 : : {
60 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemScaleBar.svg" ) );
61 : 0 : }
62 : :
63 : 0 : QgsLayoutItemScaleBar *QgsLayoutItemScaleBar::create( QgsLayout *layout )
64 : : {
65 : 0 : return new QgsLayoutItemScaleBar( layout );
66 : 0 : }
67 : :
68 : 0 : QgsLayoutSize QgsLayoutItemScaleBar::minimumSize() const
69 : : {
70 : 0 : QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, nullptr );
71 : 0 : return QgsLayoutSize( mStyle->calculateBoxSize( context, mSettings, createScaleContext() ), QgsUnitTypes::LayoutMillimeters );
72 : 0 : }
73 : :
74 : 0 : void QgsLayoutItemScaleBar::draw( QgsLayoutItemRenderContext &context )
75 : : {
76 : 0 : if ( !mStyle )
77 : 0 : return;
78 : :
79 : 0 : if ( dataDefinedProperties().isActive( QgsLayoutObject::ScalebarLineColor ) || dataDefinedProperties().isActive( QgsLayoutObject::ScalebarLineWidth ) )
80 : : {
81 : : // compatibility code - ScalebarLineColor and ScalebarLineWidth are deprecated
82 : 0 : QgsExpressionContext expContext = createExpressionContext();
83 : 0 : std::unique_ptr< QgsLineSymbol > sym( mSettings.lineSymbol()->clone() );
84 : : Q_NOWARN_DEPRECATED_PUSH
85 : 0 : if ( dataDefinedProperties().isActive( QgsLayoutObject::ScalebarLineWidth ) )
86 : 0 : sym->setWidth( mDataDefinedProperties.valueAsDouble( QgsLayoutObject::ScalebarLineWidth, expContext, mSettings.lineWidth() ) );
87 : 0 : if ( dataDefinedProperties().isActive( QgsLayoutObject::ScalebarLineColor ) )
88 : 0 : sym->setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarLineColor, expContext, mSettings.lineColor() ) );
89 : : Q_NOWARN_DEPRECATED_POP
90 : 0 : mSettings.setLineSymbol( sym.release() );
91 : 0 : }
92 : 0 : if ( dataDefinedProperties().isActive( QgsLayoutObject::ScalebarFillColor ) )
93 : : {
94 : : // compatibility code - ScalebarLineColor and ScalebarLineWidth are deprecated
95 : 0 : QgsExpressionContext expContext = createExpressionContext();
96 : 0 : std::unique_ptr< QgsFillSymbol > sym( mSettings.fillSymbol()->clone() );
97 : : Q_NOWARN_DEPRECATED_PUSH
98 : 0 : sym->setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarFillColor, expContext, mSettings.fillColor() ) );
99 : : Q_NOWARN_DEPRECATED_POP
100 : 0 : mSettings.setFillSymbol( sym.release() );
101 : 0 : }
102 : 0 : if ( dataDefinedProperties().isActive( QgsLayoutObject::ScalebarFillColor2 ) )
103 : : {
104 : : // compatibility code - ScalebarLineColor and ScalebarLineWidth are deprecated
105 : 0 : QgsExpressionContext expContext = createExpressionContext();
106 : 0 : std::unique_ptr< QgsFillSymbol > sym( mSettings.alternateFillSymbol()->clone() );
107 : : Q_NOWARN_DEPRECATED_PUSH
108 : 0 : sym->setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarFillColor2, expContext, mSettings.fillColor2() ) );
109 : : Q_NOWARN_DEPRECATED_POP
110 : 0 : mSettings.setAlternateFillSymbol( sym.release() );
111 : 0 : }
112 : :
113 : 0 : mStyle->draw( context.renderContext(), mSettings, createScaleContext() );
114 : 0 : }
115 : :
116 : 0 : void QgsLayoutItemScaleBar::setNumberOfSegments( int nSegments )
117 : : {
118 : 0 : if ( !mStyle )
119 : : {
120 : 0 : mSettings.setNumberOfSegments( nSegments );
121 : 0 : return;
122 : : }
123 : 0 : mSettings.setNumberOfSegments( nSegments );
124 : 0 : resizeToMinimumWidth();
125 : 0 : }
126 : :
127 : 0 : void QgsLayoutItemScaleBar::setUnitsPerSegment( double units )
128 : : {
129 : 0 : if ( !mStyle )
130 : : {
131 : 0 : mSettings.setUnitsPerSegment( units );
132 : 0 : return;
133 : : }
134 : 0 : mSettings.setUnitsPerSegment( units );
135 : 0 : refreshSegmentMillimeters();
136 : 0 : resizeToMinimumWidth();
137 : 0 : }
138 : :
139 : 0 : void QgsLayoutItemScaleBar::setSegmentSizeMode( QgsScaleBarSettings::SegmentSizeMode mode )
140 : : {
141 : 0 : if ( !mStyle )
142 : : {
143 : 0 : mSettings.setSegmentSizeMode( mode );
144 : 0 : return;
145 : : }
146 : 0 : mSettings.setSegmentSizeMode( mode );
147 : 0 : refreshSegmentMillimeters();
148 : 0 : resizeToMinimumWidth();
149 : 0 : }
150 : :
151 : 0 : void QgsLayoutItemScaleBar::setMinimumBarWidth( double minWidth )
152 : : {
153 : 0 : if ( !mStyle )
154 : : {
155 : 0 : mSettings.setMinimumBarWidth( minWidth );
156 : 0 : return;
157 : : }
158 : 0 : mSettings.setMinimumBarWidth( minWidth );
159 : 0 : refreshSegmentMillimeters();
160 : 0 : resizeToMinimumWidth();
161 : 0 : }
162 : :
163 : 0 : void QgsLayoutItemScaleBar::setMaximumBarWidth( double maxWidth )
164 : : {
165 : 0 : if ( !mStyle )
166 : : {
167 : 0 : mSettings.setMaximumBarWidth( maxWidth );
168 : 0 : return;
169 : : }
170 : 0 : mSettings.setMaximumBarWidth( maxWidth );
171 : 0 : refreshSegmentMillimeters();
172 : 0 : resizeToMinimumWidth();
173 : 0 : }
174 : :
175 : 0 : QgsTextFormat QgsLayoutItemScaleBar::textFormat() const
176 : : {
177 : 0 : return mSettings.textFormat();
178 : : }
179 : :
180 : 0 : void QgsLayoutItemScaleBar::setTextFormat( const QgsTextFormat &format )
181 : : {
182 : 0 : mSettings.setTextFormat( format );
183 : 0 : refreshItemSize();
184 : 0 : emit changed();
185 : 0 : }
186 : :
187 : 0 : QgsLineSymbol *QgsLayoutItemScaleBar::lineSymbol() const
188 : : {
189 : 0 : return mSettings.lineSymbol();
190 : : }
191 : :
192 : 0 : void QgsLayoutItemScaleBar::setLineSymbol( QgsLineSymbol *symbol )
193 : : {
194 : 0 : mSettings.setLineSymbol( symbol );
195 : 0 : }
196 : :
197 : 0 : QgsLineSymbol *QgsLayoutItemScaleBar::divisionLineSymbol() const
198 : : {
199 : 0 : return mSettings.divisionLineSymbol();
200 : : }
201 : :
202 : 0 : void QgsLayoutItemScaleBar::setDivisionLineSymbol( QgsLineSymbol *symbol )
203 : : {
204 : 0 : mSettings.setDivisionLineSymbol( symbol );
205 : 0 : }
206 : :
207 : 0 : QgsLineSymbol *QgsLayoutItemScaleBar::subdivisionLineSymbol() const
208 : : {
209 : 0 : return mSettings.subdivisionLineSymbol();
210 : : }
211 : :
212 : 0 : void QgsLayoutItemScaleBar::setSubdivisionLineSymbol( QgsLineSymbol *symbol )
213 : : {
214 : 0 : mSettings.setSubdivisionLineSymbol( symbol );
215 : 0 : }
216 : :
217 : 0 : QgsFillSymbol *QgsLayoutItemScaleBar::fillSymbol() const
218 : : {
219 : 0 : return mSettings.fillSymbol();
220 : : }
221 : :
222 : 0 : void QgsLayoutItemScaleBar::setFillSymbol( QgsFillSymbol *symbol )
223 : : {
224 : 0 : mSettings.setFillSymbol( symbol );
225 : 0 : }
226 : :
227 : 0 : QgsFillSymbol *QgsLayoutItemScaleBar::alternateFillSymbol() const
228 : : {
229 : 0 : return mSettings.alternateFillSymbol();
230 : : }
231 : :
232 : 0 : void QgsLayoutItemScaleBar::setAlternateFillSymbol( QgsFillSymbol *symbol )
233 : : {
234 : 0 : mSettings.setAlternateFillSymbol( symbol );
235 : 0 : }
236 : :
237 : 0 : void QgsLayoutItemScaleBar::setNumberOfSegmentsLeft( int nSegmentsLeft )
238 : : {
239 : 0 : if ( !mStyle )
240 : : {
241 : 0 : mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
242 : 0 : return;
243 : : }
244 : 0 : mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
245 : 0 : resizeToMinimumWidth();
246 : 0 : }
247 : :
248 : 0 : void QgsLayoutItemScaleBar::setBoxContentSpace( double space )
249 : : {
250 : 0 : if ( !mStyle )
251 : : {
252 : 0 : mSettings.setBoxContentSpace( space );
253 : 0 : return;
254 : : }
255 : 0 : mSettings.setBoxContentSpace( space );
256 : 0 : refreshItemSize();
257 : 0 : }
258 : :
259 : 0 : void QgsLayoutItemScaleBar::setLinkedMap( QgsLayoutItemMap *map )
260 : : {
261 : 0 : disconnectCurrentMap();
262 : :
263 : 0 : mMap = map;
264 : :
265 : 0 : if ( !map )
266 : : {
267 : 0 : return;
268 : : }
269 : :
270 : 0 : connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
271 : 0 : connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
272 : :
273 : 0 : refreshSegmentMillimeters();
274 : 0 : emit changed();
275 : 0 : }
276 : :
277 : 0 : void QgsLayoutItemScaleBar::disconnectCurrentMap()
278 : : {
279 : 0 : if ( !mMap )
280 : : {
281 : 0 : return;
282 : : }
283 : :
284 : 0 : disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
285 : 0 : disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
286 : 0 : mMap = nullptr;
287 : 0 : }
288 : :
289 : 0 : void QgsLayoutItemScaleBar::refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property )
290 : : {
291 : 0 : QgsExpressionContext context = createExpressionContext();
292 : :
293 : 0 : bool forceUpdate = false;
294 : : //updates data defined properties and redraws item to match
295 : 0 : if ( property == QgsLayoutObject::ScalebarFillColor || property == QgsLayoutObject::AllProperties )
296 : : {
297 : 0 : forceUpdate = true;
298 : 0 : }
299 : 0 : if ( property == QgsLayoutObject::ScalebarFillColor2 || property == QgsLayoutObject::AllProperties )
300 : : {
301 : 0 : forceUpdate = true;
302 : 0 : }
303 : 0 : if ( property == QgsLayoutObject::ScalebarLineColor || property == QgsLayoutObject::AllProperties )
304 : : {
305 : 0 : forceUpdate = true;
306 : 0 : }
307 : 0 : if ( property == QgsLayoutObject::ScalebarLineWidth || property == QgsLayoutObject::AllProperties )
308 : : {
309 : 0 : forceUpdate = true;
310 : 0 : }
311 : 0 : if ( forceUpdate )
312 : : {
313 : 0 : refreshItemSize();
314 : 0 : update();
315 : 0 : }
316 : :
317 : 0 : QgsLayoutItem::refreshDataDefinedProperty( property );
318 : 0 : }
319 : :
320 : 0 : void QgsLayoutItemScaleBar::refreshSegmentMillimeters()
321 : : {
322 : 0 : if ( mMap )
323 : : {
324 : : //get mm dimension of composer map
325 : 0 : QRectF composerItemRect = mMap->rect();
326 : :
327 : 0 : switch ( mSettings.segmentSizeMode() )
328 : : {
329 : : case QgsScaleBarSettings::SegmentSizeFixed:
330 : : {
331 : : //calculate size depending on mNumUnitsPerSegment
332 : 0 : mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
333 : 0 : break;
334 : : }
335 : :
336 : : case QgsScaleBarSettings::SegmentSizeFitWidth:
337 : : {
338 : 0 : if ( mSettings.maximumBarWidth() < mSettings.minimumBarWidth() )
339 : : {
340 : 0 : mSegmentMillimeters = 0;
341 : 0 : }
342 : : else
343 : : {
344 : 0 : double nSegments = ( mSettings.numberOfSegmentsLeft() != 0 ) + mSettings.numberOfSegments();
345 : : // unitsPerSegments which fit minBarWidth resp. maxBarWidth
346 : 0 : double minUnitsPerSeg = ( mSettings.minimumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
347 : 0 : double maxUnitsPerSeg = ( mSettings.maximumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
348 : 0 : mSettings.setUnitsPerSegment( QgsLayoutUtils::calculatePrettySize( minUnitsPerSeg, maxUnitsPerSeg ) );
349 : 0 : mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
350 : : }
351 : 0 : break;
352 : : }
353 : : }
354 : 0 : }
355 : 0 : }
356 : :
357 : 0 : double QgsLayoutItemScaleBar::mapWidth() const
358 : : {
359 : 0 : if ( !mMap )
360 : : {
361 : 0 : return 0.0;
362 : : }
363 : :
364 : 0 : QgsRectangle mapExtent = mMap->extent();
365 : 0 : if ( mSettings.units() == QgsUnitTypes::DistanceUnknownUnit )
366 : : {
367 : 0 : return mapExtent.width();
368 : : }
369 : : else
370 : : {
371 : 0 : QgsDistanceArea da;
372 : 0 : da.setSourceCrs( mMap->crs(), mLayout->project()->transformContext() );
373 : 0 : da.setEllipsoid( mLayout->project()->ellipsoid() );
374 : :
375 : 0 : QgsUnitTypes::DistanceUnit units = da.lengthUnits();
376 : 0 : double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), mapExtent.yMinimum() ),
377 : 0 : QgsPointXY( mapExtent.xMaximum(), mapExtent.yMinimum() ) );
378 : 0 : measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
379 : 0 : return measure;
380 : 0 : }
381 : 0 : }
382 : :
383 : 0 : QgsScaleBarRenderer::ScaleBarContext QgsLayoutItemScaleBar::createScaleContext() const
384 : : {
385 : 0 : QgsScaleBarRenderer::ScaleBarContext scaleContext;
386 : 0 : scaleContext.size = rect().size();
387 : 0 : scaleContext.segmentWidth = mSegmentMillimeters;
388 : 0 : scaleContext.scale = mMap ? mMap->scale() : 1.0;
389 : 0 : scaleContext.flags = mStyle->flags();
390 : 0 : return scaleContext;
391 : : }
392 : :
393 : 0 : void QgsLayoutItemScaleBar::setLabelVerticalPlacement( QgsScaleBarSettings::LabelVerticalPlacement placement )
394 : : {
395 : 0 : mSettings.setLabelVerticalPlacement( placement );
396 : 0 : refreshItemSize();
397 : 0 : emit changed();
398 : 0 : }
399 : :
400 : 0 : void QgsLayoutItemScaleBar::setLabelHorizontalPlacement( QgsScaleBarSettings::LabelHorizontalPlacement placement )
401 : : {
402 : 0 : mSettings.setLabelHorizontalPlacement( placement );
403 : 0 : refreshItemSize();
404 : 0 : emit changed();
405 : 0 : }
406 : :
407 : 0 : void QgsLayoutItemScaleBar::setAlignment( QgsScaleBarSettings::Alignment a )
408 : : {
409 : 0 : mSettings.setAlignment( a );
410 : 0 : refreshItemSize();
411 : 0 : emit changed();
412 : 0 : }
413 : :
414 : 0 : void QgsLayoutItemScaleBar::setUnits( QgsUnitTypes::DistanceUnit u )
415 : : {
416 : 0 : mSettings.setUnits( u );
417 : 0 : refreshSegmentMillimeters();
418 : 0 : refreshItemSize();
419 : 0 : emit changed();
420 : 0 : }
421 : :
422 : 0 : Qt::PenJoinStyle QgsLayoutItemScaleBar::lineJoinStyle() const
423 : : {
424 : : Q_NOWARN_DEPRECATED_PUSH
425 : 0 : return mSettings.lineJoinStyle();
426 : : Q_NOWARN_DEPRECATED_POP
427 : : }
428 : :
429 : 0 : void QgsLayoutItemScaleBar::setLineJoinStyle( Qt::PenJoinStyle style )
430 : : {
431 : : Q_NOWARN_DEPRECATED_PUSH
432 : 0 : if ( mSettings.lineJoinStyle() == style )
433 : : {
434 : : //no change
435 : 0 : return;
436 : : }
437 : 0 : mSettings.setLineJoinStyle( style );
438 : : Q_NOWARN_DEPRECATED_POP
439 : 0 : update();
440 : 0 : emit changed();
441 : 0 : }
442 : :
443 : 0 : Qt::PenCapStyle QgsLayoutItemScaleBar::lineCapStyle() const
444 : : {
445 : : Q_NOWARN_DEPRECATED_PUSH
446 : 0 : return mSettings.lineCapStyle();
447 : : Q_NOWARN_DEPRECATED_POP
448 : : }
449 : :
450 : 0 : void QgsLayoutItemScaleBar::setLineCapStyle( Qt::PenCapStyle style )
451 : : {
452 : : Q_NOWARN_DEPRECATED_PUSH
453 : 0 : if ( mSettings.lineCapStyle() == style )
454 : : {
455 : : //no change
456 : 0 : return;
457 : : }
458 : 0 : mSettings.setLineCapStyle( style );
459 : : Q_NOWARN_DEPRECATED_POP
460 : 0 : update();
461 : 0 : emit changed();
462 : 0 : }
463 : :
464 : 0 : void QgsLayoutItemScaleBar::applyDefaultSettings()
465 : : {
466 : : //style
467 : 0 : mStyle = std::make_unique< QgsSingleBoxScaleBarRenderer >();
468 : :
469 : : //default to no background
470 : 0 : setBackgroundEnabled( false );
471 : :
472 : : //get default composer font from settings
473 : 0 : QgsSettings settings;
474 : 0 : QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
475 : 0 : QgsTextFormat format;
476 : 0 : QFont f;
477 : 0 : if ( !defaultFontString.isEmpty() )
478 : : {
479 : 0 : f.setFamily( defaultFontString );
480 : 0 : }
481 : 0 : format.setFont( f );
482 : 0 : format.setSize( 12.0 );
483 : 0 : format.setSizeUnit( QgsUnitTypes::RenderPoints );
484 : :
485 : 0 : mSettings.setTextFormat( format );
486 : :
487 : 0 : mSettings.setUnits( QgsUnitTypes::DistanceUnknownUnit );
488 : 0 : refreshItemSize();
489 : :
490 : 0 : emit changed();
491 : 0 : }
492 : :
493 : 0 : bool QgsLayoutItemScaleBar::applyDefaultRendererSettings( QgsScaleBarRenderer *renderer )
494 : : {
495 : 0 : return renderer->applyDefaultSettings( mSettings );
496 : : }
497 : :
498 : 0 : QgsUnitTypes::DistanceUnit QgsLayoutItemScaleBar::guessUnits() const
499 : : {
500 : 0 : if ( !mMap )
501 : 0 : return QgsUnitTypes::DistanceMeters;
502 : :
503 : 0 : QgsCoordinateReferenceSystem crs = mMap->crs();
504 : : // start with crs units
505 : 0 : QgsUnitTypes::DistanceUnit unit = crs.mapUnits();
506 : 0 : if ( unit == QgsUnitTypes::DistanceDegrees || unit == QgsUnitTypes::DistanceUnknownUnit )
507 : : {
508 : : // geographic CRS, use metric units
509 : 0 : unit = QgsUnitTypes::DistanceMeters;
510 : 0 : }
511 : :
512 : : // try to pick reasonable choice between metric / imperial units
513 : 0 : double widthInSelectedUnits = mapWidth();
514 : 0 : double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
515 : 0 : switch ( unit )
516 : : {
517 : : case QgsUnitTypes::DistanceMeters:
518 : : {
519 : 0 : if ( initialUnitsPerSegment > 1000.0 )
520 : : {
521 : 0 : unit = QgsUnitTypes::DistanceKilometers;
522 : 0 : }
523 : 0 : break;
524 : : }
525 : : case QgsUnitTypes::DistanceFeet:
526 : : {
527 : 0 : if ( initialUnitsPerSegment > 5419.95 )
528 : : {
529 : 0 : unit = QgsUnitTypes::DistanceMiles;
530 : 0 : }
531 : 0 : break;
532 : : }
533 : : default:
534 : 0 : break;
535 : : }
536 : :
537 : 0 : return unit;
538 : 0 : }
539 : :
540 : 0 : void QgsLayoutItemScaleBar::applyDefaultSize( QgsUnitTypes::DistanceUnit units )
541 : : {
542 : 0 : mSettings.setUnits( units );
543 : 0 : if ( mMap )
544 : : {
545 : 0 : double upperMagnitudeMultiplier = 1.0;
546 : 0 : double widthInSelectedUnits = mapWidth();
547 : 0 : double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
548 : 0 : mSettings.setUnitsPerSegment( initialUnitsPerSegment );
549 : :
550 : 0 : setUnitLabel( QgsUnitTypes::toAbbreviatedString( units ) );
551 : 0 : upperMagnitudeMultiplier = 1;
552 : :
553 : 0 : double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
554 : 0 : int segmentMagnitude = std::floor( std::log10( segmentWidth ) );
555 : 0 : double unitsPerSegment = upperMagnitudeMultiplier * ( std::pow( 10.0, segmentMagnitude ) );
556 : 0 : double multiplier = std::floor( ( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
557 : :
558 : 0 : if ( multiplier > 0 )
559 : : {
560 : 0 : unitsPerSegment = unitsPerSegment * multiplier;
561 : 0 : }
562 : 0 : mSettings.setUnitsPerSegment( unitsPerSegment );
563 : 0 : mSettings.setMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
564 : :
565 : 0 : mSettings.setNumberOfSegments( 2 );
566 : 0 : mSettings.setNumberOfSegmentsLeft( 0 );
567 : 0 : }
568 : :
569 : 0 : refreshSegmentMillimeters();
570 : 0 : resizeToMinimumWidth();
571 : 0 : emit changed();
572 : 0 : }
573 : :
574 : 0 : void QgsLayoutItemScaleBar::resizeToMinimumWidth()
575 : : {
576 : 0 : if ( !mStyle )
577 : 0 : return;
578 : :
579 : 0 : QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, nullptr );
580 : 0 : double widthMM = mStyle->calculateBoxSize( context, mSettings, createScaleContext() ).width();
581 : 0 : QgsLayoutSize currentSize = sizeWithUnits();
582 : 0 : currentSize.setWidth( mLayout->renderContext().measurementConverter().convert( QgsLayoutMeasurement( widthMM, QgsUnitTypes::LayoutMillimeters ), currentSize.units() ).length() );
583 : 0 : attemptResize( currentSize );
584 : 0 : update();
585 : 0 : emit changed();
586 : 0 : }
587 : :
588 : 0 : void QgsLayoutItemScaleBar::update()
589 : : {
590 : : //Don't adjust box size for numeric scale bars:
591 : 0 : if ( mStyle && mStyle->id() != QLatin1String( "Numeric" ) )
592 : : {
593 : 0 : refreshItemSize();
594 : 0 : }
595 : 0 : QgsLayoutItem::update();
596 : 0 : }
597 : :
598 : 0 : void QgsLayoutItemScaleBar::updateScale()
599 : : {
600 : 0 : refreshSegmentMillimeters();
601 : : //Don't adjust box size for numeric scale bars:
602 : 0 : if ( mStyle && mStyle->id() != QLatin1String( "Numeric" ) )
603 : : {
604 : 0 : resizeToMinimumWidth();
605 : 0 : }
606 : 0 : update();
607 : 0 : }
608 : :
609 : 0 : void QgsLayoutItemScaleBar::setStyle( const QString &styleName )
610 : : {
611 : : //switch depending on style name
612 : 0 : std::unique_ptr< QgsScaleBarRenderer> renderer( QgsApplication::scaleBarRendererRegistry()->renderer( styleName ) );
613 : 0 : if ( renderer )
614 : : {
615 : 0 : mStyle = std::move( renderer );
616 : 0 : }
617 : 0 : refreshItemSize();
618 : 0 : emit changed();
619 : 0 : }
620 : :
621 : 0 : QString QgsLayoutItemScaleBar::style() const
622 : : {
623 : 0 : if ( mStyle )
624 : : {
625 : 0 : return mStyle->id();
626 : : }
627 : : else
628 : : {
629 : 0 : return QString();
630 : : }
631 : 0 : }
632 : :
633 : 0 : const QgsNumericFormat *QgsLayoutItemScaleBar::numericFormat() const
634 : : {
635 : 0 : return mSettings.numericFormat();
636 : : }
637 : :
638 : 0 : void QgsLayoutItemScaleBar::setNumericFormat( QgsNumericFormat *format )
639 : : {
640 : 0 : mSettings.setNumericFormat( format );
641 : 0 : }
642 : :
643 : 0 : QFont QgsLayoutItemScaleBar::font() const
644 : : {
645 : 0 : return mSettings.textFormat().font();
646 : 0 : }
647 : :
648 : 0 : void QgsLayoutItemScaleBar::setFont( const QFont &font )
649 : : {
650 : : Q_NOWARN_DEPRECATED_PUSH
651 : 0 : mSettings.setFont( font );
652 : : Q_NOWARN_DEPRECATED_POP
653 : 0 : refreshItemSize();
654 : 0 : emit changed();
655 : 0 : }
656 : :
657 : 0 : QColor QgsLayoutItemScaleBar::fontColor() const
658 : : {
659 : 0 : QColor color = mSettings.textFormat().color();
660 : 0 : color.setAlphaF( mSettings.textFormat().opacity() );
661 : 0 : return color;
662 : 0 : }
663 : :
664 : 0 : void QgsLayoutItemScaleBar::setFontColor( const QColor &color )
665 : : {
666 : 0 : mSettings.textFormat().setColor( color );
667 : 0 : mSettings.textFormat().setOpacity( color.alphaF() );
668 : 0 : }
669 : :
670 : 0 : QColor QgsLayoutItemScaleBar::fillColor() const
671 : : {
672 : : Q_NOWARN_DEPRECATED_PUSH
673 : 0 : return mSettings.fillColor();
674 : : Q_NOWARN_DEPRECATED_POP
675 : 0 : }
676 : :
677 : 0 : void QgsLayoutItemScaleBar::setFillColor( const QColor &color )
678 : : {
679 : : Q_NOWARN_DEPRECATED_PUSH
680 : 0 : mSettings.setFillColor( color );
681 : : Q_NOWARN_DEPRECATED_POP
682 : 0 : }
683 : :
684 : 0 : QColor QgsLayoutItemScaleBar::fillColor2() const
685 : : {
686 : : Q_NOWARN_DEPRECATED_PUSH
687 : 0 : return mSettings.fillColor2();
688 : : Q_NOWARN_DEPRECATED_POP
689 : : }
690 : :
691 : 0 : void QgsLayoutItemScaleBar::setFillColor2( const QColor &color )
692 : : {
693 : : Q_NOWARN_DEPRECATED_PUSH
694 : 0 : mSettings.setFillColor2( color );
695 : : Q_NOWARN_DEPRECATED_POP
696 : 0 : }
697 : :
698 : 0 : QColor QgsLayoutItemScaleBar::lineColor() const
699 : : {
700 : : Q_NOWARN_DEPRECATED_PUSH
701 : 0 : return mSettings.lineColor();
702 : : Q_NOWARN_DEPRECATED_POP
703 : : }
704 : :
705 : 0 : void QgsLayoutItemScaleBar::setLineColor( const QColor &color )
706 : : {
707 : : Q_NOWARN_DEPRECATED_PUSH
708 : 0 : mSettings.setLineColor( color );
709 : : Q_NOWARN_DEPRECATED_POP
710 : 0 : }
711 : :
712 : 0 : double QgsLayoutItemScaleBar::lineWidth() const
713 : : {
714 : : Q_NOWARN_DEPRECATED_PUSH
715 : 0 : return mSettings.lineWidth();
716 : : Q_NOWARN_DEPRECATED_POP
717 : : }
718 : :
719 : 0 : void QgsLayoutItemScaleBar::setLineWidth( double width )
720 : : {
721 : : Q_NOWARN_DEPRECATED_PUSH
722 : 0 : mSettings.setLineWidth( width );
723 : : Q_NOWARN_DEPRECATED_POP
724 : 0 : }
725 : :
726 : 0 : QPen QgsLayoutItemScaleBar::pen() const
727 : : {
728 : : Q_NOWARN_DEPRECATED_PUSH
729 : 0 : return mSettings.pen();
730 : : Q_NOWARN_DEPRECATED_POP
731 : : }
732 : :
733 : 0 : QBrush QgsLayoutItemScaleBar::brush() const
734 : : {
735 : : Q_NOWARN_DEPRECATED_PUSH
736 : 0 : return mSettings.brush();
737 : : Q_NOWARN_DEPRECATED_POP
738 : : }
739 : :
740 : 0 : QBrush QgsLayoutItemScaleBar::brush2() const
741 : : {
742 : : Q_NOWARN_DEPRECATED_PUSH
743 : 0 : return mSettings.brush2();
744 : : Q_NOWARN_DEPRECATED_POP
745 : : }
746 : :
747 : 0 : bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScaleBarElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
748 : : {
749 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "height" ), QString::number( mSettings.height() ) );
750 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "labelBarSpace" ), QString::number( mSettings.labelBarSpace() ) );
751 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "boxContentSpace" ), QString::number( mSettings.boxContentSpace() ) );
752 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "numSegments" ), mSettings.numberOfSegments() );
753 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "numSegmentsLeft" ), mSettings.numberOfSegmentsLeft() );
754 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "numSubdivisions" ), mSettings.numberOfSubdivisions() );
755 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "subdivisionsHeight" ), mSettings.subdivisionsHeight() );
756 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "numUnitsPerSegment" ), QString::number( mSettings.unitsPerSegment() ) );
757 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "segmentSizeMode" ), mSettings.segmentSizeMode() );
758 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "minBarWidth" ), mSettings.minimumBarWidth() );
759 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "maxBarWidth" ), mSettings.maximumBarWidth() );
760 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "segmentMillimeters" ), QString::number( mSegmentMillimeters ) );
761 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QString::number( mSettings.mapUnitsPerScaleBarUnit() ) );
762 : :
763 : 0 : QDomElement textElem = mSettings.textFormat().writeXml( doc, rwContext );
764 : 0 : composerScaleBarElem.appendChild( textElem );
765 : :
766 : : Q_NOWARN_DEPRECATED_PUSH
767 : : // kept just for allowing projects to open in QGIS < 3.14, remove for 4.0
768 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mSettings.lineWidth() ) );
769 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "lineJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mSettings.lineJoinStyle() ) );
770 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "lineCapStyle" ), QgsSymbolLayerUtils::encodePenCapStyle( mSettings.lineCapStyle() ) );
771 : : //pen color
772 : 0 : QDomElement strokeColorElem = doc.createElement( QStringLiteral( "strokeColor" ) );
773 : 0 : strokeColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.lineColor().red() ) );
774 : 0 : strokeColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.lineColor().green() ) );
775 : 0 : strokeColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.lineColor().blue() ) );
776 : 0 : strokeColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.lineColor().alpha() ) );
777 : 0 : composerScaleBarElem.appendChild( strokeColorElem );
778 : : Q_NOWARN_DEPRECATED_POP
779 : :
780 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "unitLabel" ), mSettings.unitLabel() );
781 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "unitType" ), QgsUnitTypes::encodeUnit( mSettings.units() ) );
782 : :
783 : 0 : QDomElement numericFormatElem = doc.createElement( QStringLiteral( "numericFormat" ) );
784 : 0 : mSettings.numericFormat()->writeXml( numericFormatElem, doc, rwContext );
785 : 0 : composerScaleBarElem.appendChild( numericFormatElem );
786 : :
787 : : //style
788 : 0 : if ( mStyle )
789 : : {
790 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "style" ), mStyle->id() );
791 : 0 : }
792 : :
793 : : //map id
794 : 0 : if ( mMap )
795 : : {
796 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
797 : 0 : }
798 : :
799 : : //colors
800 : :
801 : : Q_NOWARN_DEPRECATED_PUSH
802 : : // kept just for allowing projects to open in QGIS < 3.14, remove for 4.0
803 : :
804 : : //fill color
805 : 0 : QDomElement fillColorElem = doc.createElement( QStringLiteral( "fillColor" ) );
806 : 0 : fillColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor().red() ) );
807 : 0 : fillColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor().green() ) );
808 : 0 : fillColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor().blue() ) );
809 : 0 : fillColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor().alpha() ) );
810 : 0 : composerScaleBarElem.appendChild( fillColorElem );
811 : :
812 : : //fill color 2
813 : 0 : QDomElement fillColor2Elem = doc.createElement( QStringLiteral( "fillColor2" ) );
814 : 0 : fillColor2Elem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor2().red() ) );
815 : 0 : fillColor2Elem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor2().green() ) );
816 : 0 : fillColor2Elem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor2().blue() ) );
817 : 0 : fillColor2Elem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor2().alpha() ) );
818 : 0 : composerScaleBarElem.appendChild( fillColor2Elem );
819 : :
820 : : Q_NOWARN_DEPRECATED_POP
821 : :
822 : : //label vertical/horizontal placement
823 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "labelVerticalPlacement" ), QString::number( static_cast< int >( mSettings.labelVerticalPlacement() ) ) );
824 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "labelHorizontalPlacement" ), QString::number( static_cast< int >( mSettings.labelHorizontalPlacement() ) ) );
825 : :
826 : : //alignment
827 : 0 : composerScaleBarElem.setAttribute( QStringLiteral( "alignment" ), QString::number( static_cast< int >( mSettings.alignment() ) ) );
828 : :
829 : 0 : QDomElement lineSymbol = doc.createElement( QStringLiteral( "lineSymbol" ) );
830 : 0 : const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QString(),
831 : 0 : mSettings.lineSymbol(),
832 : 0 : doc,
833 : 0 : rwContext );
834 : 0 : lineSymbol.appendChild( symbolElem );
835 : 0 : composerScaleBarElem.appendChild( lineSymbol );
836 : :
837 : 0 : QDomElement divisionSymbol = doc.createElement( QStringLiteral( "divisionLineSymbol" ) );
838 : 0 : const QDomElement divisionSymbolElem = QgsSymbolLayerUtils::saveSymbol( QString(),
839 : 0 : mSettings.divisionLineSymbol(),
840 : 0 : doc,
841 : 0 : rwContext );
842 : 0 : divisionSymbol.appendChild( divisionSymbolElem );
843 : 0 : composerScaleBarElem.appendChild( divisionSymbol );
844 : :
845 : 0 : QDomElement subdivisionSymbol = doc.createElement( QStringLiteral( "subdivisionLineSymbol" ) );
846 : 0 : const QDomElement subdivisionSymbolElem = QgsSymbolLayerUtils::saveSymbol( QString(),
847 : 0 : mSettings.subdivisionLineSymbol(),
848 : 0 : doc,
849 : 0 : rwContext );
850 : 0 : subdivisionSymbol.appendChild( subdivisionSymbolElem );
851 : 0 : composerScaleBarElem.appendChild( subdivisionSymbol );
852 : :
853 : 0 : QDomElement fillSymbol1Elem = doc.createElement( QStringLiteral( "fillSymbol1" ) );
854 : 0 : const QDomElement symbol1Elem = QgsSymbolLayerUtils::saveSymbol( QString(),
855 : 0 : mSettings.fillSymbol(),
856 : 0 : doc,
857 : 0 : rwContext );
858 : 0 : fillSymbol1Elem.appendChild( symbol1Elem );
859 : 0 : composerScaleBarElem.appendChild( fillSymbol1Elem );
860 : :
861 : 0 : QDomElement fillSymbol2Elem = doc.createElement( QStringLiteral( "fillSymbol2" ) );
862 : 0 : const QDomElement symbol2Elem = QgsSymbolLayerUtils::saveSymbol( QString(),
863 : 0 : mSettings.alternateFillSymbol(),
864 : 0 : doc,
865 : 0 : rwContext );
866 : 0 : fillSymbol2Elem.appendChild( symbol2Elem );
867 : 0 : composerScaleBarElem.appendChild( fillSymbol2Elem );
868 : :
869 : : return true;
870 : 0 : }
871 : :
872 : 0 : bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
873 : : {
874 : 0 : mSettings.setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
875 : 0 : mSettings.setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
876 : 0 : mSettings.setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
877 : 0 : mSettings.setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
878 : 0 : mSettings.setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
879 : 0 : mSettings.setNumberOfSubdivisions( itemElem.attribute( QStringLiteral( "numSubdivisions" ), QStringLiteral( "1" ) ).toInt() );
880 : 0 : mSettings.setSubdivisionsHeight( itemElem.attribute( QStringLiteral( "subdivisionsHeight" ), QStringLiteral( "1.5" ) ).toDouble() );
881 : 0 : mSettings.setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
882 : 0 : mSettings.setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
883 : 0 : mSettings.setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
884 : 0 : mSettings.setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
885 : 0 : mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
886 : 0 : mSettings.setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
887 : :
888 : 0 : QDomElement lineSymbolElem = itemElem.firstChildElement( QStringLiteral( "lineSymbol" ) );
889 : 0 : bool foundLineSymbol = false;
890 : 0 : if ( !lineSymbolElem.isNull() )
891 : : {
892 : 0 : QDomElement symbolElem = lineSymbolElem.firstChildElement( QStringLiteral( "symbol" ) );
893 : 0 : std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
894 : 0 : if ( lineSymbol )
895 : : {
896 : 0 : mSettings.setLineSymbol( lineSymbol.release() );
897 : 0 : foundLineSymbol = true;
898 : 0 : }
899 : 0 : }
900 : 0 : QDomElement divisionSymbolElem = itemElem.firstChildElement( QStringLiteral( "divisionLineSymbol" ) );
901 : 0 : if ( !divisionSymbolElem.isNull() )
902 : : {
903 : 0 : QDomElement symbolElem = divisionSymbolElem.firstChildElement( QStringLiteral( "symbol" ) );
904 : 0 : std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
905 : 0 : if ( lineSymbol )
906 : : {
907 : 0 : mSettings.setDivisionLineSymbol( lineSymbol.release() );
908 : 0 : }
909 : 0 : }
910 : 0 : else if ( foundLineSymbol )
911 : : {
912 : 0 : mSettings.setDivisionLineSymbol( mSettings.lineSymbol()->clone() );
913 : 0 : }
914 : 0 : QDomElement subdivisionSymbolElem = itemElem.firstChildElement( QStringLiteral( "subdivisionLineSymbol" ) );
915 : 0 : if ( !subdivisionSymbolElem.isNull() )
916 : : {
917 : 0 : QDomElement symbolElem = subdivisionSymbolElem.firstChildElement( QStringLiteral( "symbol" ) );
918 : 0 : std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
919 : 0 : if ( lineSymbol )
920 : : {
921 : 0 : mSettings.setSubdivisionLineSymbol( lineSymbol.release() );
922 : 0 : }
923 : 0 : }
924 : 0 : else if ( foundLineSymbol )
925 : : {
926 : 0 : mSettings.setSubdivisionLineSymbol( mSettings.lineSymbol()->clone() );
927 : 0 : }
928 : :
929 : 0 : if ( !foundLineSymbol )
930 : : {
931 : : // old project compatibility
932 : 0 : std::unique_ptr< QgsLineSymbol > lineSymbol = std::make_unique< QgsLineSymbol >();
933 : 0 : std::unique_ptr< QgsSimpleLineSymbolLayer > lineSymbolLayer = std::make_unique< QgsSimpleLineSymbolLayer >();
934 : 0 : lineSymbolLayer->setWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
935 : 0 : lineSymbolLayer->setWidthUnit( QgsUnitTypes::RenderMillimeters );
936 : 0 : lineSymbolLayer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
937 : 0 : lineSymbolLayer->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
938 : :
939 : : //stroke color
940 : 0 : QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
941 : 0 : if ( !strokeColorList.isEmpty() )
942 : : {
943 : 0 : QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
944 : : bool redOk, greenOk, blueOk, alphaOk;
945 : : int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
946 : :
947 : 0 : strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
948 : 0 : strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
949 : 0 : strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
950 : 0 : strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
951 : :
952 : 0 : if ( redOk && greenOk && blueOk && alphaOk )
953 : : {
954 : 0 : lineSymbolLayer->setColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
955 : 0 : }
956 : 0 : }
957 : : else
958 : : {
959 : 0 : lineSymbolLayer->setColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
960 : : }
961 : :
962 : : // need to translate the deprecated ScalebarLineWidth and ScalebarLineColor properties to symbol properties,
963 : : // and then remove them from the scalebar so they don't interfere and apply to other compatibility workarounds
964 : 0 : lineSymbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeWidth, dataDefinedProperties().property( QgsLayoutObject::ScalebarLineWidth ) );
965 : 0 : dataDefinedProperties().setProperty( QgsLayoutObject::ScalebarLineWidth, QgsProperty() );
966 : 0 : lineSymbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyStrokeColor, dataDefinedProperties().property( QgsLayoutObject::ScalebarLineColor ) );
967 : 0 : dataDefinedProperties().setProperty( QgsLayoutObject::ScalebarLineColor, QgsProperty() );
968 : :
969 : 0 : lineSymbol->changeSymbolLayer( 0, lineSymbolLayer.release() );
970 : 0 : mSettings.setLineSymbol( lineSymbol->clone() );
971 : 0 : mSettings.setDivisionLineSymbol( lineSymbol->clone() );
972 : 0 : mSettings.setSubdivisionLineSymbol( lineSymbol.release() );
973 : 0 : }
974 : :
975 : 0 : mSettings.setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
976 : :
977 : 0 : QDomNodeList textFormatNodeList = itemElem.elementsByTagName( QStringLiteral( "text-style" ) );
978 : 0 : if ( !textFormatNodeList.isEmpty() )
979 : : {
980 : 0 : QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
981 : 0 : mSettings.textFormat().readXml( textFormatElem, context );
982 : 0 : }
983 : : else
984 : : {
985 : 0 : QFont f;
986 : 0 : if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
987 : : {
988 : 0 : f.fromString( itemElem.attribute( QStringLiteral( "font" ), QString() ) );
989 : 0 : }
990 : 0 : mSettings.textFormat().setFont( f );
991 : 0 : if ( f.pointSizeF() > 0 )
992 : : {
993 : 0 : mSettings.textFormat().setSize( f.pointSizeF() );
994 : 0 : mSettings.textFormat().setSizeUnit( QgsUnitTypes::RenderPoints );
995 : 0 : }
996 : 0 : else if ( f.pixelSize() > 0 )
997 : : {
998 : 0 : mSettings.textFormat().setSize( f.pixelSize() );
999 : 0 : mSettings.textFormat().setSizeUnit( QgsUnitTypes::RenderPixels );
1000 : 0 : }
1001 : 0 : }
1002 : :
1003 : 0 : QDomNodeList numericFormatNodeList = itemElem.elementsByTagName( QStringLiteral( "numericFormat" ) );
1004 : 0 : if ( !numericFormatNodeList.isEmpty() )
1005 : : {
1006 : 0 : QDomElement numericFormatElem = numericFormatNodeList.at( 0 ).toElement();
1007 : 0 : mSettings.setNumericFormat( QgsApplication::numericFormatRegistry()->createFromXml( numericFormatElem, context ) );
1008 : 0 : }
1009 : :
1010 : 0 : QDomElement fillSymbol1Elem = itemElem.firstChildElement( QStringLiteral( "fillSymbol1" ) );
1011 : 0 : bool foundFillSymbol1 = false;
1012 : 0 : if ( !fillSymbol1Elem.isNull() )
1013 : : {
1014 : 0 : QDomElement symbolElem = fillSymbol1Elem.firstChildElement( QStringLiteral( "symbol" ) );
1015 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) );
1016 : 0 : if ( fillSymbol )
1017 : : {
1018 : 0 : mSettings.setFillSymbol( fillSymbol.release() );
1019 : 0 : foundFillSymbol1 = true;
1020 : 0 : }
1021 : 0 : }
1022 : 0 : if ( !foundFillSymbol1 )
1023 : : {
1024 : : // old project compatibility
1025 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol = std::make_unique< QgsFillSymbol >();
1026 : 0 : std::unique_ptr< QgsSimpleFillSymbolLayer > fillSymbolLayer = std::make_unique< QgsSimpleFillSymbolLayer >();
1027 : 0 : fillSymbolLayer->setStrokeStyle( Qt::NoPen );
1028 : :
1029 : : //fill color
1030 : 0 : QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
1031 : 0 : if ( !fillColorList.isEmpty() )
1032 : : {
1033 : 0 : QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
1034 : : bool redOk, greenOk, blueOk, alphaOk;
1035 : : int fillRed, fillGreen, fillBlue, fillAlpha;
1036 : :
1037 : 0 : fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1038 : 0 : fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1039 : 0 : fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1040 : 0 : fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1041 : :
1042 : 0 : if ( redOk && greenOk && blueOk && alphaOk )
1043 : : {
1044 : 0 : fillSymbolLayer->setColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1045 : 0 : }
1046 : 0 : }
1047 : : else
1048 : : {
1049 : 0 : fillSymbolLayer->setColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
1050 : : }
1051 : :
1052 : : // need to translate the deprecated ScalebarFillColor property to symbol properties,
1053 : : // and then remove them from the scalebar so they don't interfere and apply to other compatibility workarounds
1054 : 0 : fillSymbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyFillColor, dataDefinedProperties().property( QgsLayoutObject::ScalebarFillColor ) );
1055 : 0 : dataDefinedProperties().setProperty( QgsLayoutObject::ScalebarFillColor, QgsProperty() );
1056 : :
1057 : 0 : fillSymbol->changeSymbolLayer( 0, fillSymbolLayer.release() );
1058 : 0 : mSettings.setFillSymbol( fillSymbol.release() );
1059 : 0 : }
1060 : :
1061 : 0 : QDomElement fillSymbol2Elem = itemElem.firstChildElement( QStringLiteral( "fillSymbol2" ) );
1062 : 0 : bool foundFillSymbol2 = false;
1063 : 0 : if ( !fillSymbol2Elem.isNull() )
1064 : : {
1065 : 0 : QDomElement symbolElem = fillSymbol2Elem.firstChildElement( QStringLiteral( "symbol" ) );
1066 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) );
1067 : 0 : if ( fillSymbol )
1068 : : {
1069 : 0 : mSettings.setAlternateFillSymbol( fillSymbol.release() );
1070 : 0 : foundFillSymbol2 = true;
1071 : 0 : }
1072 : 0 : }
1073 : 0 : if ( !foundFillSymbol2 )
1074 : : {
1075 : : // old project compatibility
1076 : 0 : std::unique_ptr< QgsFillSymbol > fillSymbol = std::make_unique< QgsFillSymbol >();
1077 : 0 : std::unique_ptr< QgsSimpleFillSymbolLayer > fillSymbolLayer = std::make_unique< QgsSimpleFillSymbolLayer >();
1078 : 0 : fillSymbolLayer->setStrokeStyle( Qt::NoPen );
1079 : :
1080 : : //fill color 2
1081 : :
1082 : 0 : QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
1083 : 0 : if ( !fillColor2List.isEmpty() )
1084 : : {
1085 : 0 : QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
1086 : : bool redOk, greenOk, blueOk, alphaOk;
1087 : : int fillRed, fillGreen, fillBlue, fillAlpha;
1088 : :
1089 : 0 : fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1090 : 0 : fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1091 : 0 : fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1092 : 0 : fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1093 : :
1094 : 0 : if ( redOk && greenOk && blueOk && alphaOk )
1095 : : {
1096 : 0 : fillSymbolLayer->setColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1097 : 0 : }
1098 : 0 : }
1099 : : else
1100 : : {
1101 : 0 : fillSymbolLayer->setColor( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
1102 : : }
1103 : :
1104 : : // need to translate the deprecated ScalebarFillColor2 property to symbol properties,
1105 : : // and then remove them from the scalebar so they don't interfere and apply to other compatibility workarounds
1106 : 0 : fillSymbolLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyFillColor, dataDefinedProperties().property( QgsLayoutObject::ScalebarFillColor2 ) );
1107 : 0 : dataDefinedProperties().setProperty( QgsLayoutObject::ScalebarFillColor2, QgsProperty() );
1108 : :
1109 : 0 : fillSymbol->changeSymbolLayer( 0, fillSymbolLayer.release() );
1110 : 0 : mSettings.setAlternateFillSymbol( fillSymbol.release() );
1111 : :
1112 : 0 : }
1113 : :
1114 : : //font color
1115 : 0 : QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
1116 : 0 : if ( !textColorList.isEmpty() )
1117 : : {
1118 : 0 : QDomElement textColorElem = textColorList.at( 0 ).toElement();
1119 : : bool redOk, greenOk, blueOk, alphaOk;
1120 : : int textRed, textGreen, textBlue, textAlpha;
1121 : :
1122 : 0 : textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1123 : 0 : textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1124 : 0 : textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1125 : 0 : textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1126 : :
1127 : 0 : if ( redOk && greenOk && blueOk && alphaOk )
1128 : : {
1129 : 0 : mSettings.textFormat().setColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
1130 : 0 : }
1131 : 0 : }
1132 : 0 : else if ( itemElem.hasAttribute( QStringLiteral( "fontColor" ) ) )
1133 : : {
1134 : 0 : QColor c;
1135 : 0 : c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1136 : 0 : mSettings.textFormat().setColor( c );
1137 : 0 : }
1138 : :
1139 : : //style
1140 : 0 : setStyle( itemElem.attribute( QStringLiteral( "style" ), QString() ) );
1141 : :
1142 : : //call attemptResize after setStyle to ensure the appropriate size limitations are applied
1143 : 0 : attemptResize( QgsLayoutSize::decodeSize( itemElem.attribute( QStringLiteral( "size" ) ) ) );
1144 : :
1145 : 0 : if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
1146 : : {
1147 : 0 : QgsUnitTypes::DistanceUnit u = QgsUnitTypes::DistanceUnknownUnit;
1148 : 0 : switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
1149 : : {
1150 : : case 0:
1151 : 0 : u = QgsUnitTypes::DistanceUnknownUnit;
1152 : 0 : break;
1153 : : case 1:
1154 : 0 : u = QgsUnitTypes::DistanceMeters;
1155 : 0 : break;
1156 : : case 2:
1157 : 0 : u = QgsUnitTypes::DistanceFeet;
1158 : 0 : break;
1159 : : case 3:
1160 : 0 : u = QgsUnitTypes::DistanceNauticalMiles;
1161 : 0 : break;
1162 : : }
1163 : 0 : mSettings.setUnits( u );
1164 : 0 : }
1165 : : else
1166 : : {
1167 : 0 : mSettings.setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
1168 : : }
1169 : :
1170 : 0 : mSettings.setLabelVerticalPlacement( static_cast< QgsScaleBarSettings::LabelVerticalPlacement >( itemElem.attribute( QStringLiteral( "labelVerticalPlacement" ), QStringLiteral( "0" ) ).toInt() ) );
1171 : 0 : mSettings.setLabelHorizontalPlacement( static_cast< QgsScaleBarSettings::LabelHorizontalPlacement >( itemElem.attribute( QStringLiteral( "labelHorizontalPlacement" ), QStringLiteral( "0" ) ).toInt() ) );
1172 : :
1173 : 0 : mSettings.setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
1174 : :
1175 : : //map
1176 : 0 : disconnectCurrentMap();
1177 : 0 : mMap = nullptr;
1178 : 0 : mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
1179 : : return true;
1180 : 0 : }
1181 : :
1182 : :
1183 : 0 : void QgsLayoutItemScaleBar::finalizeRestoreFromXml()
1184 : : {
1185 : 0 : if ( mLayout && !mMapUuid.isEmpty() )
1186 : : {
1187 : 0 : disconnectCurrentMap();
1188 : 0 : mMap = qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) );
1189 : 0 : if ( mMap )
1190 : : {
1191 : 0 : connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
1192 : 0 : connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
1193 : 0 : }
1194 : 0 : }
1195 : :
1196 : 0 : updateScale();
1197 : 0 : }
1198 : :
1199 : 0 : bool QgsLayoutItemScaleBar::accept( QgsStyleEntityVisitorInterface *visitor ) const
1200 : : {
1201 : 0 : QgsStyleTextFormatEntity entity( mSettings.textFormat() );
1202 : 0 : if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1203 : 0 : return false;
1204 : :
1205 : 0 : return true;
1206 : 0 : }
1207 : :
1208 : 0 : QgsLayoutItem::ExportLayerBehavior QgsLayoutItemScaleBar::exportLayerBehavior() const
1209 : : {
1210 : 0 : return CanGroupWithItemsOfSameType;
1211 : : }
|