QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgslayoutitemscalebar.cpp
Go to the documentation of this file.
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
18
19#include <cmath>
20
21#include "qgsdistancearea.h"
22#include "qgsfillsymbol.h"
23#include "qgsfillsymbollayer.h"
24#include "qgsfontutils.h"
25#include "qgslayout.h"
26#include "qgslayoutitemmap.h"
29#include "qgslayoututils.h"
30#include "qgslinesymbol.h"
31#include "qgslinesymbollayer.h"
32#include "qgsmessagelog.h"
33#include "qgsnumericformat.h"
35#include "qgsproject.h"
36#include "qgsrectangle.h"
37#include "qgsscalebarrenderer.h"
39#include "qgssettings.h"
42#include "qgssymbollayerutils.h"
43#include "qgsunittypes.h"
44
45#include <QAbstractTextDocumentLayout>
46#include <QDomDocument>
47#include <QDomElement>
48#include <QFontMetricsF>
49#include <QPainter>
50#include <QTextDocument>
51
52#include "moc_qgslayoutitemscalebar.cpp"
53
60
65
67{
68 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemScaleBar.svg" ) );
69}
70
75
77{
79
80 const QgsScaleBarRenderer::ScaleBarContext scaleContext = createScaleContext();
81 if ( !scaleContext.isValid() )
82 return QgsLayoutSize();
83
84 return QgsLayoutSize( mStyle->calculateBoxSize( context, mSettings, scaleContext ), Qgis::LayoutUnit::Millimeters );
85}
86
88{
89 if ( !mStyle )
90 return;
91
92 const QgsScaleBarRenderer::ScaleBarContext scaleContext = createScaleContext();
93 if ( !scaleContext.isValid() )
94 {
95 if ( mLayout->renderContext().isPreviewRender() )
96 {
97 // No initial render available - so draw some preview text alerting user
98 QPainter *painter = context.renderContext().painter();
99
100 const double scale = context.renderContext().convertToPainterUnits( 1, Qgis::RenderUnit::Millimeters );
101 const QRectF thisPaintRect = QRectF( 0, 0, rect().width() * scale, rect().height() * scale );
102
103 painter->setBrush( QBrush( QColor( 255, 125, 125, 125 ) ) );
104 painter->setPen( Qt::NoPen );
105 painter->drawRect( thisPaintRect );
106 painter->setBrush( Qt::NoBrush );
107
108 painter->setPen( QColor( 200, 0, 0, 255 ) );
109 QTextDocument td;
110 td.setTextWidth( thisPaintRect.width() );
111 td.setHtml( QStringLiteral( "<span style=\"color: rgb(200,0,0);\"><b>%1</b><br>%2</span>" ).arg(
112 tr( "Invalid scale!" ),
113 tr( "The scale bar cannot be rendered due to invalid settings or an incompatible linked map extent." ) ) );
114 painter->setClipRect( thisPaintRect );
115 QAbstractTextDocumentLayout::PaintContext ctx;
116 td.documentLayout()->draw( painter, ctx );
117 }
118 return;
119 }
120
122 {
123 // compatibility code - ScalebarLineColor and ScalebarLineWidth are deprecated
125 std::unique_ptr< QgsLineSymbol > sym( mSettings.lineSymbol()->clone() );
128 sym->setWidth( mDataDefinedProperties.valueAsDouble( QgsLayoutObject::DataDefinedProperty::ScalebarLineWidth, expContext, mSettings.lineWidth() ) );
130 sym->setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::DataDefinedProperty::ScalebarLineColor, expContext, mSettings.lineColor() ) );
132 mSettings.setLineSymbol( sym.release() );
133 }
135 {
136 // compatibility code - ScalebarLineColor and ScalebarLineWidth are deprecated
138 std::unique_ptr< QgsFillSymbol > sym( mSettings.fillSymbol()->clone() );
140 sym->setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::DataDefinedProperty::ScalebarFillColor, expContext, mSettings.fillColor() ) );
142 mSettings.setFillSymbol( sym.release() );
143 }
145 {
146 // compatibility code - ScalebarLineColor and ScalebarLineWidth are deprecated
148 std::unique_ptr< QgsFillSymbol > sym( mSettings.alternateFillSymbol()->clone() );
150 sym->setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::DataDefinedProperty::ScalebarFillColor2, expContext, mSettings.fillColor2() ) );
152 mSettings.setAlternateFillSymbol( sym.release() );
153 }
154
155 mStyle->draw( context.renderContext(), mSettings, scaleContext );
156}
157
159{
160 if ( !mStyle )
161 {
162 mSettings.setNumberOfSegments( nSegments );
163 return;
164 }
165 mSettings.setNumberOfSegments( nSegments );
167}
168
170{
171 if ( !mStyle )
172 {
173 mSettings.setUnitsPerSegment( units );
174 return;
175 }
176 mSettings.setUnitsPerSegment( units );
177 refreshSegmentMillimeters();
179}
180
181
183{
184 if ( !mStyle )
185 {
186 mSettings.setSegmentSizeMode( mode );
187 return;
188 }
189 mSettings.setSegmentSizeMode( mode );
190 refreshSegmentMillimeters();
192}
193
195{
196 if ( !mStyle )
197 {
198 mSettings.setMinimumBarWidth( minWidth );
199 return;
200 }
201 mSettings.setMinimumBarWidth( minWidth );
202 refreshSegmentMillimeters();
204}
205
207{
208 if ( !mStyle )
209 {
210 mSettings.setMaximumBarWidth( maxWidth );
211 return;
212 }
213 mSettings.setMaximumBarWidth( maxWidth );
214 refreshSegmentMillimeters();
216}
217
219{
220 return mSettings.textFormat();
221}
222
224{
225 mSettings.setTextFormat( format );
227 emit changed();
228}
229
231{
232 return mSettings.lineSymbol();
233}
234
236{
237 mSettings.setLineSymbol( symbol );
238}
239
241{
242 return mSettings.divisionLineSymbol();
243}
244
246{
247 mSettings.setDivisionLineSymbol( symbol );
248}
249
251{
252 return mSettings.subdivisionLineSymbol();
253}
254
256{
257 mSettings.setSubdivisionLineSymbol( symbol );
258}
259
261{
262 return mSettings.fillSymbol();
263}
264
266{
267 mSettings.setFillSymbol( symbol );
268}
269
271{
272 return mSettings.alternateFillSymbol();
273}
274
276{
277 mSettings.setAlternateFillSymbol( symbol );
278}
279
281{
282 if ( !mStyle )
283 {
284 mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
285 return;
286 }
287 mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
289}
290
292{
293 if ( !mStyle )
294 {
295 mSettings.setBoxContentSpace( space );
296 return;
297 }
298 mSettings.setBoxContentSpace( space );
300}
301
303{
304 disconnectCurrentMap();
305
306 mMap = map;
307
308 if ( !map )
309 {
310 return;
311 }
312
313 connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
314 connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
315
316 refreshSegmentMillimeters();
317 emit changed();
318}
319
320void QgsLayoutItemScaleBar::disconnectCurrentMap()
321{
322 if ( !mMap )
323 {
324 return;
325 }
326
327 disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
328 disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
329 mMap = nullptr;
330}
331
336
338{
339 if ( mMethod == method )
340 return;
341
342 mMethod = method;
343 refreshSegmentMillimeters();
345}
346
347void QgsLayoutItemScaleBar::refreshUnitsPerSegment( const QgsExpressionContext *context )
348{
350 {
351 double unitsPerSegment = mSettings.unitsPerSegment();
352 bool ok = false;
354
355 if ( !ok )
356 {
357 QgsMessageLog::logMessage( tr( "Scalebar units per segment expression eval error" ) );
358 }
359 else
360 {
362 }
363 }
364}
365
366void QgsLayoutItemScaleBar::refreshMinimumBarWidth( const QgsExpressionContext *context )
367{
369 {
370 double minimumBarWidth = mSettings.minimumBarWidth();
371
372 bool ok = false;
374
375 if ( !ok )
376 {
377 QgsMessageLog::logMessage( tr( "Scalebar minimum segment width expression eval error" ) );
378 }
379 else
380 {
382 }
383 }
384}
385
386void QgsLayoutItemScaleBar::refreshMaximumBarWidth( const QgsExpressionContext *context )
387{
389 {
390 double maximumBarWidth = mSettings.maximumBarWidth();
391
392 bool ok = false;
394
395 if ( !ok )
396 {
397 QgsMessageLog::logMessage( tr( "Scalebar maximum segment width expression eval error" ) );
398 }
399 else
400 {
402 }
403 }
404}
405
406void QgsLayoutItemScaleBar::refreshNumberOfSegmentsLeft( const QgsExpressionContext *context )
407{
409 {
410 int leftSegments = mSettings.numberOfSegmentsLeft();
411
412 bool ok = false;
413 leftSegments = mDataDefinedProperties.valueAsInt( QgsLayoutObject::DataDefinedProperty::ScalebarLeftSegments, *context, leftSegments, &ok );
414
415 if ( !ok )
416 {
417 QgsMessageLog::logMessage( tr( "Scalebar left segment count expression eval error" ) );
418 }
419 else
420 {
421 setNumberOfSegmentsLeft( leftSegments );
422 }
423 }
424}
425
426void QgsLayoutItemScaleBar::refreshNumberOfSegmentsRight( const QgsExpressionContext *context )
427{
429 {
430 int rightSegments = mSettings.numberOfSegments();
431
432 bool ok = false;
433 rightSegments = mDataDefinedProperties.valueAsInt( QgsLayoutObject::DataDefinedProperty::ScalebarRightSegments, *context, rightSegments, &ok );
434
435 if ( !ok )
436 {
437 QgsMessageLog::logMessage( tr( "Scalebar left segment count expression eval error" ) );
438 }
439 else
440 {
441 setNumberOfSegments( rightSegments );
442 }
443 }
444}
445
447{
449
450 bool forceUpdate = false;
451
454 {
455 double height = mSettings.height();
456
457 bool ok = false;
459
460 if ( !ok )
461 {
462 QgsMessageLog::logMessage( tr( "Scalebar height expression eval error" ) );
463 }
464 else
465 {
466 setHeight( height );
467 }
468
469 forceUpdate = true;
470 }
471
474 {
475 double height = mSettings.subdivisionsHeight();
476
477 bool ok = false;
479
480 if ( !ok )
481 {
482 QgsMessageLog::logMessage( tr( "Scalebar subdivision height expression eval error" ) );
483 }
484 else
485 {
487 }
488
489 forceUpdate = true;
490 }
491
493 {
494 refreshNumberOfSegmentsLeft( &context );
495 forceUpdate = true;
496 }
497
499 {
500 refreshNumberOfSegmentsRight( &context );
501 forceUpdate = true;
502 }
503
506 {
507 int segments = mSettings.numberOfSubdivisions();
508
509 bool ok = false;
511
512 if ( !ok )
513 {
514 QgsMessageLog::logMessage( tr( "Scalebar number of subdivisions expression eval error" ) );
515 }
516 else
517 {
518 setNumberOfSubdivisions( segments );
519 }
520
521 forceUpdate = true;
522 }
523
524
526 {
527 refreshUnitsPerSegment( &context );
528 forceUpdate = true;
529 }
530
532 {
533 refreshMinimumBarWidth( &context );
534 forceUpdate = true;
535 }
536
538 {
539 refreshMaximumBarWidth( &context );
540 forceUpdate = true;
541 }
542
543 // updates data defined properties and redraws item to match
544 // -- Deprecated --
546 {
547 forceUpdate = true;
548 }
550 {
551 forceUpdate = true;
552 }
554 {
555 forceUpdate = true;
556 }
558 {
559 forceUpdate = true;
560 }
561
562 if ( forceUpdate )
563 {
565 update();
566 }
567
569}
570
571void QgsLayoutItemScaleBar::refreshSegmentMillimeters()
572{
573 if ( mMap )
574 {
575 //get mm dimension of composer map
576 const QRectF composerItemRect = mMap->rect();
577
578 const double currentMapWidth = mapWidth();
579 if ( qgsDoubleNear( currentMapWidth, 0 ) || std::isnan( currentMapWidth ) )
580 {
581 mSegmentMillimeters = std::numeric_limits< double >::quiet_NaN();
582 return;
583 }
584
585 switch ( mSettings.segmentSizeMode() )
586 {
588 {
589 //calculate size depending on mNumUnitsPerSegment
590 mSegmentMillimeters = composerItemRect.width() / currentMapWidth * mSettings.unitsPerSegment();
591 break;
592 }
593
595 {
596 if ( mSettings.maximumBarWidth() < mSettings.minimumBarWidth() )
597 {
598 mSegmentMillimeters = 0;
599 }
600 else
601 {
602 const double nSegments = ( mSettings.numberOfSegmentsLeft() != 0 ) + mSettings.numberOfSegments();
603 // unitsPerSegments which fit minBarWidth resp. maxBarWidth
604 const double minUnitsPerSeg = ( mSettings.minimumBarWidth() * currentMapWidth ) / ( nSegments * composerItemRect.width() );
605 const double maxUnitsPerSeg = ( mSettings.maximumBarWidth() * currentMapWidth ) / ( nSegments * composerItemRect.width() );
606 mSettings.setUnitsPerSegment( QgsLayoutUtils::calculatePrettySize( minUnitsPerSeg, maxUnitsPerSeg ) );
607 mSegmentMillimeters = composerItemRect.width() / currentMapWidth * mSettings.unitsPerSegment();
608 }
609 break;
610 }
611 }
612 }
613}
614
615double QgsLayoutItemScaleBar::mapWidth() const
616{
617 if ( !mMap )
618 {
619 return 0.0;
620 }
621
622 const QgsRectangle mapExtent = mMap->extent();
623 if ( mSettings.units() == Qgis::DistanceUnit::Unknown )
624 {
625 return mapExtent.width();
626 }
627 else
628 {
629 QgsDistanceArea da;
630 da.setSourceCrs( mMap->crs(), mLayout->project()->transformContext() );
631 da.setEllipsoid( mLayout->project()->ellipsoid() );
632
634
635 QList< double > yValues;
636 switch ( mMethod )
637 {
639 yValues << mapExtent.yMaximum();
640 break;
641
643 yValues << 0.5 * ( mapExtent.yMaximum() + mapExtent.yMinimum() );
644 break;
645
646
648 yValues << mapExtent.yMinimum();
649 break;
650
652 yValues << mapExtent.yMaximum();
653 yValues << 0.5 * ( mapExtent.yMaximum() + mapExtent.yMinimum() );
654 yValues << mapExtent.yMinimum();
655 break;
656
658 if ( mMap->crs().mapUnits() == Qgis::DistanceUnit::Degrees )
659 {
660 yValues << 0;
661 }
662 else
663 {
664 // this method is only for degree based systems, so just fallback to default if not degree based
665 yValues << 0.5 * ( mapExtent.yMaximum() + mapExtent.yMinimum() );
666 }
667 break;
668 }
669
670 double sumValidMeasures = 0;
671 int validMeasureCount = 0;
672
673 for ( const double y : std::as_const( yValues ) )
674 {
675 try
676 {
677 double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), y ),
678 QgsPointXY( mapExtent.xMaximum(), y ) );
679 if ( std::isnan( measure ) )
680 {
681 // TODO report errors to user
682 QgsDebugError( QStringLiteral( "An error occurred while calculating length" ) );
683 continue;
684 }
685
686 measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
687 sumValidMeasures += measure;
688 validMeasureCount++;
689 }
690 catch ( QgsCsException & )
691 {
692 // TODO report errors to user
693 QgsDebugError( QStringLiteral( "An error occurred while calculating length" ) );
694 continue;
695 }
696 }
697
698 if ( validMeasureCount == 0 )
699 return std::numeric_limits< double >::quiet_NaN();
700
701 return sumValidMeasures / validMeasureCount;
702 }
703}
704
705QgsScaleBarRenderer::ScaleBarContext QgsLayoutItemScaleBar::createScaleContext() const
706{
707 QgsScaleBarRenderer::ScaleBarContext scaleContext;
708 scaleContext.size = rect().size();
709 scaleContext.segmentWidth = mSegmentMillimeters;
710 scaleContext.scale = mMap ? mMap->scale() : 1.0;
711 scaleContext.flags = mStyle->flags();
712 return scaleContext;
713}
714
716{
717 mSettings.setLabelVerticalPlacement( placement );
719 emit changed();
720}
721
723{
724 mSettings.setLabelHorizontalPlacement( placement );
726 emit changed();
727}
728
730{
731 mSettings.setAlignment( a );
733 emit changed();
734}
735
737{
738 mSettings.setUnits( u );
739 refreshSegmentMillimeters();
741 emit changed();
742}
743
745{
747 return mSettings.lineJoinStyle();
749}
750
752{
754 if ( mSettings.lineJoinStyle() == style )
755 {
756 //no change
757 return;
758 }
759 mSettings.setLineJoinStyle( style );
761 update();
762 emit changed();
763}
764
766{
768 return mSettings.lineCapStyle();
770}
771
773{
775 if ( mSettings.lineCapStyle() == style )
776 {
777 //no change
778 return;
779 }
780 mSettings.setLineCapStyle( style );
782 update();
783 emit changed();
784}
785
787{
788 //style
789 mStyle = std::make_unique< QgsSingleBoxScaleBarRenderer >();
790
791 //default to no background
792 setBackgroundEnabled( false );
793
794 //get default composer font from settings
795 const QgsSettings settings;
796 const QString defaultFontString = settings.value( QStringLiteral( "LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
797 QgsTextFormat format;
798 QFont f;
799 if ( !defaultFontString.isEmpty() )
800 {
801 QgsFontUtils::setFontFamily( f, defaultFontString );
802 }
803 format.setFont( f );
804 format.setSize( 12.0 );
806
807 mSettings.setTextFormat( format );
808
809 mSettings.setUnits( Qgis::DistanceUnit::Unknown );
811
812 emit changed();
813}
814
816{
817 return renderer->applyDefaultSettings( mSettings );
818}
819
821{
822 if ( !mMap )
824
825 const QgsCoordinateReferenceSystem crs = mMap->crs();
826 // start with crs units
827 Qgis::DistanceUnit unit = crs.mapUnits();
829 {
830 // geographic CRS, use metric units
832 }
833
834 // try to pick reasonable choice between metric / imperial units
835 const double widthInSelectedUnits = mapWidth();
836 if ( std::isnan( widthInSelectedUnits ) )
837 return unit;
838
839 const double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
840 switch ( unit )
841 {
843 {
844 if ( initialUnitsPerSegment > 1000.0 )
845 {
847 }
848 break;
849 }
851 {
852 if ( initialUnitsPerSegment > 5419.95 )
853 {
855 }
856 break;
857 }
858 default:
859 break;
860 }
861
862 return unit;
863}
864
866{
867 mSettings.setUnits( units );
868 if ( mMap )
869 {
870 double upperMagnitudeMultiplier = 1.0;
871 const double widthInSelectedUnits = mapWidth();
872 if ( !std::isnan( widthInSelectedUnits ) )
873 {
874 const double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
875 mSettings.setUnitsPerSegment( initialUnitsPerSegment );
876
878 upperMagnitudeMultiplier = 1;
879
880 const double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
881 const int segmentMagnitude = std::floor( std::log10( segmentWidth ) );
882 double unitsPerSegment = upperMagnitudeMultiplier * ( std::pow( 10.0, segmentMagnitude ) );
883 const double multiplier = std::floor( ( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
884
885 if ( multiplier > 0 )
886 {
887 unitsPerSegment = unitsPerSegment * multiplier;
888 }
889 mSettings.setUnitsPerSegment( unitsPerSegment );
890 mSettings.setMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
891
892 mSettings.setNumberOfSegments( 2 );
893 mSettings.setNumberOfSegmentsLeft( 0 );
894 }
895 }
896
897 refreshSegmentMillimeters();
899 emit changed();
900}
901
903{
904 if ( !mStyle )
905 return;
906
908
909 const QgsScaleBarRenderer::ScaleBarContext scaleContext = createScaleContext();
910 if ( !scaleContext.isValid() )
911 return;
912
913 const double widthMM = mStyle->calculateBoxSize( context, mSettings, scaleContext ).width();
914 QgsLayoutSize currentSize = sizeWithUnits();
915 currentSize.setWidth( mLayout->renderContext().measurementConverter().convert( QgsLayoutMeasurement( widthMM, Qgis::LayoutUnit::Millimeters ), currentSize.units() ).length() );
916 attemptResize( currentSize );
917 update();
918 emit changed();
919}
920
922{
923 //Don't adjust box size for numeric scale bars:
924 if ( mStyle && mStyle->id() != QLatin1String( "Numeric" ) )
925 {
927 }
928 QgsLayoutItem::update();
929}
930
931void QgsLayoutItemScaleBar::updateScale()
932{
933 refreshSegmentMillimeters();
934 //Don't adjust box size for numeric scale bars:
935 if ( mStyle && mStyle->id() != QLatin1String( "Numeric" ) )
936 {
938 }
939 update();
940}
941
942void QgsLayoutItemScaleBar::setStyle( const QString &styleName )
943{
944 //switch depending on style name
945 std::unique_ptr< QgsScaleBarRenderer> renderer( QgsApplication::scaleBarRendererRegistry()->renderer( styleName ) );
946 if ( renderer )
947 {
948 mStyle = std::move( renderer );
949 }
951 emit changed();
952}
953
955{
956 if ( mStyle )
957 {
958 return mStyle->id();
959 }
960 else
961 {
962 return QString();
963 }
964}
965
967{
968 return mSettings.numericFormat();
969}
970
972{
973 mSettings.setNumericFormat( format );
974}
975
977{
978 return mSettings.textFormat().font();
979}
980
982{
984 mSettings.setFont( font );
987 emit changed();
988}
989
991{
992 QColor color = mSettings.textFormat().color();
993 color.setAlphaF( mSettings.textFormat().opacity() );
994 return color;
995}
996
997void QgsLayoutItemScaleBar::setFontColor( const QColor &color )
998{
999 mSettings.textFormat().setColor( color );
1000 mSettings.textFormat().setOpacity( color.alphaF() );
1001}
1002
1004{
1006 return mSettings.fillColor();
1008}
1009
1010void QgsLayoutItemScaleBar::setFillColor( const QColor &color )
1011{
1013 mSettings.setFillColor( color );
1015}
1016
1018{
1020 return mSettings.fillColor2();
1022}
1023
1024void QgsLayoutItemScaleBar::setFillColor2( const QColor &color )
1025{
1027 mSettings.setFillColor2( color );
1029}
1030
1032{
1034 return mSettings.lineColor();
1036}
1037
1038void QgsLayoutItemScaleBar::setLineColor( const QColor &color )
1039{
1041 mSettings.setLineColor( color );
1043}
1044
1046{
1048 return mSettings.lineWidth();
1050}
1051
1053{
1055 mSettings.setLineWidth( width );
1057}
1058
1060{
1062 return mSettings.pen();
1064}
1065
1067{
1069 return mSettings.brush();
1071}
1072
1074{
1076 return mSettings.brush2();
1078}
1079
1080bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScaleBarElem, QDomDocument &doc, const QgsReadWriteContext &rwContext ) const
1081{
1082 composerScaleBarElem.setAttribute( QStringLiteral( "height" ), QString::number( mSettings.height() ) );
1083 composerScaleBarElem.setAttribute( QStringLiteral( "labelBarSpace" ), QString::number( mSettings.labelBarSpace() ) );
1084 composerScaleBarElem.setAttribute( QStringLiteral( "boxContentSpace" ), QString::number( mSettings.boxContentSpace() ) );
1085 composerScaleBarElem.setAttribute( QStringLiteral( "numSegments" ), mSettings.numberOfSegments() );
1086 composerScaleBarElem.setAttribute( QStringLiteral( "numSegmentsLeft" ), mSettings.numberOfSegmentsLeft() );
1087 composerScaleBarElem.setAttribute( QStringLiteral( "numSubdivisions" ), mSettings.numberOfSubdivisions() );
1088 composerScaleBarElem.setAttribute( QStringLiteral( "subdivisionsHeight" ), mSettings.subdivisionsHeight() );
1089 composerScaleBarElem.setAttribute( QStringLiteral( "numUnitsPerSegment" ), QString::number( mSettings.unitsPerSegment() ) );
1090 composerScaleBarElem.setAttribute( QStringLiteral( "segmentSizeMode" ), static_cast< int >( mSettings.segmentSizeMode() ) );
1091 composerScaleBarElem.setAttribute( QStringLiteral( "minBarWidth" ), mSettings.minimumBarWidth() );
1092 composerScaleBarElem.setAttribute( QStringLiteral( "maxBarWidth" ), mSettings.maximumBarWidth() );
1093 composerScaleBarElem.setAttribute( QStringLiteral( "segmentMillimeters" ), QString::number( mSegmentMillimeters ) );
1094 composerScaleBarElem.setAttribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QString::number( mSettings.mapUnitsPerScaleBarUnit() ) );
1095 composerScaleBarElem.setAttribute( QStringLiteral( "method" ), qgsEnumValueToKey( mMethod ) );
1096
1097 const QDomElement textElem = mSettings.textFormat().writeXml( doc, rwContext );
1098 composerScaleBarElem.appendChild( textElem );
1099
1101 // kept just for allowing projects to open in QGIS < 3.14, remove for 4.0
1102 composerScaleBarElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mSettings.lineWidth() ) );
1103 composerScaleBarElem.setAttribute( QStringLiteral( "lineJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mSettings.lineJoinStyle() ) );
1104 composerScaleBarElem.setAttribute( QStringLiteral( "lineCapStyle" ), QgsSymbolLayerUtils::encodePenCapStyle( mSettings.lineCapStyle() ) );
1105 //pen color
1106 QDomElement strokeColorElem = doc.createElement( QStringLiteral( "strokeColor" ) );
1107 strokeColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.lineColor().red() ) );
1108 strokeColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.lineColor().green() ) );
1109 strokeColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.lineColor().blue() ) );
1110 strokeColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.lineColor().alpha() ) );
1111 composerScaleBarElem.appendChild( strokeColorElem );
1113
1114 composerScaleBarElem.setAttribute( QStringLiteral( "unitLabel" ), mSettings.unitLabel() );
1115 composerScaleBarElem.setAttribute( QStringLiteral( "unitType" ), QgsUnitTypes::encodeUnit( mSettings.units() ) );
1116
1117 QDomElement numericFormatElem = doc.createElement( QStringLiteral( "numericFormat" ) );
1118 mSettings.numericFormat()->writeXml( numericFormatElem, doc, rwContext );
1119 composerScaleBarElem.appendChild( numericFormatElem );
1120
1121 //style
1122 if ( mStyle )
1123 {
1124 composerScaleBarElem.setAttribute( QStringLiteral( "style" ), mStyle->id() );
1125 }
1126
1127 //map id
1128 if ( mMap )
1129 {
1130 composerScaleBarElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
1131 }
1132
1133 //colors
1134
1136 // kept just for allowing projects to open in QGIS < 3.14, remove for 4.0
1137
1138 //fill color
1139 QDomElement fillColorElem = doc.createElement( QStringLiteral( "fillColor" ) );
1140 fillColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor().red() ) );
1141 fillColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor().green() ) );
1142 fillColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor().blue() ) );
1143 fillColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor().alpha() ) );
1144 composerScaleBarElem.appendChild( fillColorElem );
1145
1146 //fill color 2
1147 QDomElement fillColor2Elem = doc.createElement( QStringLiteral( "fillColor2" ) );
1148 fillColor2Elem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor2().red() ) );
1149 fillColor2Elem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor2().green() ) );
1150 fillColor2Elem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor2().blue() ) );
1151 fillColor2Elem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor2().alpha() ) );
1152 composerScaleBarElem.appendChild( fillColor2Elem );
1153
1155
1156 //label vertical/horizontal placement
1157 composerScaleBarElem.setAttribute( QStringLiteral( "labelVerticalPlacement" ), QString::number( static_cast< int >( mSettings.labelVerticalPlacement() ) ) );
1158 composerScaleBarElem.setAttribute( QStringLiteral( "labelHorizontalPlacement" ), QString::number( static_cast< int >( mSettings.labelHorizontalPlacement() ) ) );
1159
1160 //alignment
1161 composerScaleBarElem.setAttribute( QStringLiteral( "alignment" ), QString::number( static_cast< int >( mSettings.alignment() ) ) );
1162
1163 QDomElement lineSymbol = doc.createElement( QStringLiteral( "lineSymbol" ) );
1164 const QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QString(),
1165 mSettings.lineSymbol(),
1166 doc,
1167 rwContext );
1168 lineSymbol.appendChild( symbolElem );
1169 composerScaleBarElem.appendChild( lineSymbol );
1170
1171 QDomElement divisionSymbol = doc.createElement( QStringLiteral( "divisionLineSymbol" ) );
1172 const QDomElement divisionSymbolElem = QgsSymbolLayerUtils::saveSymbol( QString(),
1173 mSettings.divisionLineSymbol(),
1174 doc,
1175 rwContext );
1176 divisionSymbol.appendChild( divisionSymbolElem );
1177 composerScaleBarElem.appendChild( divisionSymbol );
1178
1179 QDomElement subdivisionSymbol = doc.createElement( QStringLiteral( "subdivisionLineSymbol" ) );
1180 const QDomElement subdivisionSymbolElem = QgsSymbolLayerUtils::saveSymbol( QString(),
1181 mSettings.subdivisionLineSymbol(),
1182 doc,
1183 rwContext );
1184 subdivisionSymbol.appendChild( subdivisionSymbolElem );
1185 composerScaleBarElem.appendChild( subdivisionSymbol );
1186
1187 QDomElement fillSymbol1Elem = doc.createElement( QStringLiteral( "fillSymbol1" ) );
1188 const QDomElement symbol1Elem = QgsSymbolLayerUtils::saveSymbol( QString(),
1189 mSettings.fillSymbol(),
1190 doc,
1191 rwContext );
1192 fillSymbol1Elem.appendChild( symbol1Elem );
1193 composerScaleBarElem.appendChild( fillSymbol1Elem );
1194
1195 QDomElement fillSymbol2Elem = doc.createElement( QStringLiteral( "fillSymbol2" ) );
1196 const QDomElement symbol2Elem = QgsSymbolLayerUtils::saveSymbol( QString(),
1197 mSettings.alternateFillSymbol(),
1198 doc,
1199 rwContext );
1200 fillSymbol2Elem.appendChild( symbol2Elem );
1201 composerScaleBarElem.appendChild( fillSymbol2Elem );
1202
1203 return true;
1204}
1205
1206
1207bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext &context )
1208{
1209 mSettings.setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
1210 mSettings.setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
1211 mSettings.setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
1212 mSettings.setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
1213 mSettings.setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
1214 mSettings.setNumberOfSubdivisions( itemElem.attribute( QStringLiteral( "numSubdivisions" ), QStringLiteral( "1" ) ).toInt() );
1215 mSettings.setSubdivisionsHeight( itemElem.attribute( QStringLiteral( "subdivisionsHeight" ), QStringLiteral( "1.5" ) ).toDouble() );
1216 mSettings.setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
1217 mSettings.setSegmentSizeMode( static_cast<Qgis::ScaleBarSegmentSizeMode >( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
1218 mSettings.setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
1219 mSettings.setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
1220 mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
1221 mSettings.setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
1222
1223 // default to horizontal bottom to keep same behavior for older projects
1224 mMethod = qgsEnumKeyToValue( itemElem.attribute( QStringLiteral( "method" ) ), Qgis::ScaleCalculationMethod::HorizontalBottom );
1225
1226 const QDomElement lineSymbolElem = itemElem.firstChildElement( QStringLiteral( "lineSymbol" ) );
1227 bool foundLineSymbol = false;
1228 if ( !lineSymbolElem.isNull() )
1229 {
1230 const QDomElement symbolElem = lineSymbolElem.firstChildElement( QStringLiteral( "symbol" ) );
1231 std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
1232 if ( lineSymbol )
1233 {
1234 mSettings.setLineSymbol( lineSymbol.release() );
1235 foundLineSymbol = true;
1236 }
1237 }
1238 const QDomElement divisionSymbolElem = itemElem.firstChildElement( QStringLiteral( "divisionLineSymbol" ) );
1239 if ( !divisionSymbolElem.isNull() )
1240 {
1241 const QDomElement symbolElem = divisionSymbolElem.firstChildElement( QStringLiteral( "symbol" ) );
1242 std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
1243 if ( lineSymbol )
1244 {
1245 mSettings.setDivisionLineSymbol( lineSymbol.release() );
1246 }
1247 }
1248 else if ( foundLineSymbol )
1249 {
1250 mSettings.setDivisionLineSymbol( mSettings.lineSymbol()->clone() );
1251 }
1252 const QDomElement subdivisionSymbolElem = itemElem.firstChildElement( QStringLiteral( "subdivisionLineSymbol" ) );
1253 if ( !subdivisionSymbolElem.isNull() )
1254 {
1255 const QDomElement symbolElem = subdivisionSymbolElem.firstChildElement( QStringLiteral( "symbol" ) );
1256 std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( symbolElem, context ) );
1257 if ( lineSymbol )
1258 {
1259 mSettings.setSubdivisionLineSymbol( lineSymbol.release() );
1260 }
1261 }
1262 else if ( foundLineSymbol )
1263 {
1264 mSettings.setSubdivisionLineSymbol( mSettings.lineSymbol()->clone() );
1265 }
1266
1267 if ( !foundLineSymbol )
1268 {
1269 // old project compatibility
1270 auto lineSymbol = std::make_unique< QgsLineSymbol >();
1271 auto lineSymbolLayer = std::make_unique< QgsSimpleLineSymbolLayer >();
1272 lineSymbolLayer->setWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
1273 lineSymbolLayer->setWidthUnit( Qgis::RenderUnit::Millimeters );
1274 lineSymbolLayer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
1275 lineSymbolLayer->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
1276
1277 //stroke color
1278 const QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
1279 if ( !strokeColorList.isEmpty() )
1280 {
1281 const QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
1282 bool redOk, greenOk, blueOk, alphaOk;
1283 int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
1284
1285 strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1286 strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1287 strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1288 strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1289
1290 if ( redOk && greenOk && blueOk && alphaOk )
1291 {
1292 lineSymbolLayer->setColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
1293 }
1294 }
1295 else
1296 {
1297 lineSymbolLayer->setColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
1298 }
1299
1300 // need to translate the deprecated ScalebarLineWidth and ScalebarLineColor properties to symbol properties,
1301 // and then remove them from the scalebar so they don't interfere and apply to other compatibility workarounds
1306
1307 lineSymbol->changeSymbolLayer( 0, lineSymbolLayer.release() );
1308 mSettings.setLineSymbol( lineSymbol->clone() );
1309 mSettings.setDivisionLineSymbol( lineSymbol->clone() );
1310 mSettings.setSubdivisionLineSymbol( lineSymbol.release() );
1311 }
1312
1313 mSettings.setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
1314
1315 const QDomNodeList textFormatNodeList = itemElem.elementsByTagName( QStringLiteral( "text-style" ) );
1316 if ( !textFormatNodeList.isEmpty() )
1317 {
1318 const QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
1319 mSettings.textFormat().readXml( textFormatElem, context );
1320 }
1321 else
1322 {
1323 QFont f;
1324 if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
1325 {
1326 f.fromString( itemElem.attribute( QStringLiteral( "font" ), QString() ) );
1327 }
1328 mSettings.textFormat().setFont( f );
1329 if ( f.pointSizeF() > 0 )
1330 {
1331 mSettings.textFormat().setSize( f.pointSizeF() );
1332 mSettings.textFormat().setSizeUnit( Qgis::RenderUnit::Points );
1333 }
1334 else if ( f.pixelSize() > 0 )
1335 {
1336 mSettings.textFormat().setSize( f.pixelSize() );
1337 mSettings.textFormat().setSizeUnit( Qgis::RenderUnit::Pixels );
1338 }
1339 }
1340
1341 const QDomNodeList numericFormatNodeList = itemElem.elementsByTagName( QStringLiteral( "numericFormat" ) );
1342 if ( !numericFormatNodeList.isEmpty() )
1343 {
1344 const QDomElement numericFormatElem = numericFormatNodeList.at( 0 ).toElement();
1345 mSettings.setNumericFormat( QgsApplication::numericFormatRegistry()->createFromXml( numericFormatElem, context ) );
1346 }
1347
1348 const QDomElement fillSymbol1Elem = itemElem.firstChildElement( QStringLiteral( "fillSymbol1" ) );
1349 bool foundFillSymbol1 = false;
1350 if ( !fillSymbol1Elem.isNull() )
1351 {
1352 const QDomElement symbolElem = fillSymbol1Elem.firstChildElement( QStringLiteral( "symbol" ) );
1353 std::unique_ptr< QgsFillSymbol > fillSymbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) );
1354 if ( fillSymbol )
1355 {
1356 mSettings.setFillSymbol( fillSymbol.release() );
1357 foundFillSymbol1 = true;
1358 }
1359 }
1360 if ( !foundFillSymbol1 )
1361 {
1362 // old project compatibility
1363 auto fillSymbol = std::make_unique< QgsFillSymbol >();
1364 auto fillSymbolLayer = std::make_unique< QgsSimpleFillSymbolLayer >();
1365 fillSymbolLayer->setStrokeStyle( Qt::NoPen );
1366
1367 //fill color
1368 const QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
1369 if ( !fillColorList.isEmpty() )
1370 {
1371 const QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
1372 bool redOk, greenOk, blueOk, alphaOk;
1373 int fillRed, fillGreen, fillBlue, fillAlpha;
1374
1375 fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1376 fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1377 fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1378 fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1379
1380 if ( redOk && greenOk && blueOk && alphaOk )
1381 {
1382 fillSymbolLayer->setColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1383 }
1384 }
1385 else
1386 {
1387 fillSymbolLayer->setColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
1388 }
1389
1390 // need to translate the deprecated ScalebarFillColor property to symbol properties,
1391 // and then remove them from the scalebar so they don't interfere and apply to other compatibility workarounds
1394
1395 fillSymbol->changeSymbolLayer( 0, fillSymbolLayer.release() );
1396 mSettings.setFillSymbol( fillSymbol.release() );
1397 }
1398
1399 const QDomElement fillSymbol2Elem = itemElem.firstChildElement( QStringLiteral( "fillSymbol2" ) );
1400 bool foundFillSymbol2 = false;
1401 if ( !fillSymbol2Elem.isNull() )
1402 {
1403 const QDomElement symbolElem = fillSymbol2Elem.firstChildElement( QStringLiteral( "symbol" ) );
1404 std::unique_ptr< QgsFillSymbol > fillSymbol( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( symbolElem, context ) );
1405 if ( fillSymbol )
1406 {
1407 mSettings.setAlternateFillSymbol( fillSymbol.release() );
1408 foundFillSymbol2 = true;
1409 }
1410 }
1411 if ( !foundFillSymbol2 )
1412 {
1413 // old project compatibility
1414 auto fillSymbol = std::make_unique< QgsFillSymbol >();
1415 auto fillSymbolLayer = std::make_unique< QgsSimpleFillSymbolLayer >();
1416 fillSymbolLayer->setStrokeStyle( Qt::NoPen );
1417
1418 //fill color 2
1419
1420 const QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
1421 if ( !fillColor2List.isEmpty() )
1422 {
1423 const QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
1424 bool redOk, greenOk, blueOk, alphaOk;
1425 int fillRed, fillGreen, fillBlue, fillAlpha;
1426
1427 fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1428 fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1429 fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1430 fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1431
1432 if ( redOk && greenOk && blueOk && alphaOk )
1433 {
1434 fillSymbolLayer->setColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
1435 }
1436 }
1437 else
1438 {
1439 fillSymbolLayer->setColor( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
1440 }
1441
1442 // need to translate the deprecated ScalebarFillColor2 property to symbol properties,
1443 // and then remove them from the scalebar so they don't interfere and apply to other compatibility workarounds
1446
1447 fillSymbol->changeSymbolLayer( 0, fillSymbolLayer.release() );
1448 mSettings.setAlternateFillSymbol( fillSymbol.release() );
1449
1450 }
1451
1452 //font color
1453 const QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
1454 if ( !textColorList.isEmpty() )
1455 {
1456 const QDomElement textColorElem = textColorList.at( 0 ).toElement();
1457 bool redOk, greenOk, blueOk, alphaOk;
1458 int textRed, textGreen, textBlue, textAlpha;
1459
1460 textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
1461 textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
1462 textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
1463 textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
1464
1465 if ( redOk && greenOk && blueOk && alphaOk )
1466 {
1467 mSettings.textFormat().setColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
1468 }
1469 }
1470 else if ( itemElem.hasAttribute( QStringLiteral( "fontColor" ) ) )
1471 {
1472 QColor c;
1473 c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
1474 mSettings.textFormat().setColor( c );
1475 }
1476
1477 //style
1478 setStyle( itemElem.attribute( QStringLiteral( "style" ), QString() ) );
1479
1480 //call attemptResize after setStyle to ensure the appropriate size limitations are applied
1481 attemptResize( QgsLayoutSize::decodeSize( itemElem.attribute( QStringLiteral( "size" ) ) ) );
1482
1483 if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
1484 {
1486 switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
1487 {
1488 case 0:
1490 break;
1491 case 1:
1493 break;
1494 case 2:
1496 break;
1497 case 3:
1499 break;
1500 }
1501 mSettings.setUnits( u );
1502 }
1503 else
1504 {
1505 mSettings.setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
1506 }
1507
1508 mSettings.setLabelVerticalPlacement( static_cast< Qgis::ScaleBarDistanceLabelVerticalPlacement >( itemElem.attribute( QStringLiteral( "labelVerticalPlacement" ), QStringLiteral( "0" ) ).toInt() ) );
1509 mSettings.setLabelHorizontalPlacement( static_cast< Qgis::ScaleBarDistanceLabelHorizontalPlacement >( itemElem.attribute( QStringLiteral( "labelHorizontalPlacement" ), QStringLiteral( "0" ) ).toInt() ) );
1510
1511 mSettings.setAlignment( static_cast< Qgis::ScaleBarAlignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
1512
1513 //map
1514 disconnectCurrentMap();
1515 mMap = nullptr;
1516 mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
1517 return true;
1518}
1519
1520
1522{
1523 if ( mLayout && !mMapUuid.isEmpty() )
1524 {
1525 disconnectCurrentMap();
1526 mMap = qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) );
1527 if ( mMap )
1528 {
1529 connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
1530 connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
1531 }
1532 }
1533
1534 updateScale();
1535}
1536
1538{
1539 QgsStyleTextFormatEntity entity( mSettings.textFormat() );
1540 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1541 return false;
1542
1543 return true;
1544}
1545
ScaleBarDistanceLabelHorizontalPlacement
Scale bar distance label horizontal placement.
Definition qgis.h:5345
ScaleBarDistanceLabelVerticalPlacement
Scale bar distance label vertical placement.
Definition qgis.h:5331
@ Millimeters
Millimeters.
Definition qgis.h:5204
ScaleBarAlignment
Scalebar alignment.
Definition qgis.h:5302
DistanceUnit
Units of distance.
Definition qgis.h:5013
@ Feet
Imperial feet.
Definition qgis.h:5016
@ Miles
Terrestrial miles.
Definition qgis.h:5019
@ Meters
Meters.
Definition qgis.h:5014
@ Unknown
Unknown distance unit.
Definition qgis.h:5063
@ Degrees
Degrees, for planar geographic CRS distance measurements.
Definition qgis.h:5020
@ NauticalMiles
Nautical miles.
Definition qgis.h:5017
@ Kilometers
Kilometers.
Definition qgis.h:5015
@ Millimeters
Millimeters.
Definition qgis.h:5184
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5188
@ Pixels
Pixels.
Definition qgis.h:5186
ScaleCalculationMethod
Scale calculation logic.
Definition qgis.h:5285
@ HorizontalTop
Calculate horizontally, across top of map.
Definition qgis.h:5286
@ HorizontalMiddle
Calculate horizontally, across midle of map.
Definition qgis.h:5287
@ AtEquator
Always calculate the scale at the equator, regardless of the actual visible map extent....
Definition qgis.h:5290
@ HorizontalAverage
Calculate horizontally, using the average of the top, middle and bottom scales.
Definition qgis.h:5289
@ HorizontalBottom
Calculate horizontally, across bottom of map.
Definition qgis.h:5288
ScaleBarSegmentSizeMode
Modes for setting size for scale bar segments.
Definition qgis.h:5317
@ FitWidth
Scale bar segment size is calculated to fit a size range.
Definition qgis.h:5319
@ Fixed
Scale bar segment size is fixed to a map unit.
Definition qgis.h:5318
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
static QgsScaleBarRendererRegistry * scaleBarRendererRegistry()
Gets the registry of available scalebar renderers.
static QgsNumericFormatRegistry * numericFormatRegistry()
Gets the registry of available numeric formats.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Represents a coordinate reference system (CRS).
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Qgis::DistanceUnit lengthUnits() const
Returns the units of distance for length calculations made by this object.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
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.
static void setFontFamily(QFont &font, const QString &family)
Sets the family for a font object.
void extentChanged()
Emitted when the map's extent changes.
Contains settings and helpers relating to a render of a QgsLayoutItem.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
void setNumberOfSegments(int segments)
Sets the number of segments included in the scalebar.
Q_DECL_DEPRECATED QBrush brush() const
Returns the primary brush for the scalebar.
Q_DECL_DEPRECATED QColor fillColor2() const
Returns the secondary color used for fills in the scalebar.
Q_DECL_DEPRECATED double lineWidth() const
Returns the line width in millimeters for lines in the scalebar.
QIcon icon() const override
Returns the item's icon.
Q_DECL_DEPRECATED void setFillColor(const QColor &color)
Sets the color used for fills in the scalebar.
QgsLineSymbol * divisionLineSymbol() const
Returns the line symbol used to render the scalebar divisions (only used for some scalebar types).
QgsFillSymbol * alternateFillSymbol() const
Returns the secondary fill symbol used to render the scalebar (only used for some scalebar types).
Q_DECL_DEPRECATED QBrush brush2() const
Returns the secondary brush for the scalebar.
double height() const
Returns the scalebar height (in millimeters).
void setMinimumBarWidth(double minWidth)
Sets the minimum width (in millimeters) for scale bar segments.
QgsFillSymbol * fillSymbol() const
Returns the primary fill symbol used to render the scalebar (only used for some scalebar types).
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
Q_DECL_DEPRECATED QColor fontColor() const
Returns the color used for drawing text in the scalebar.
void setMaximumBarWidth(double maxWidth)
Sets the maximum width (in millimeters) for scale bar segments.
Q_DECL_DEPRECATED QColor fillColor() const
Returns the color used for fills in the scalebar.
void setNumericFormat(QgsNumericFormat *format)
Sets the numeric format used for numbers in the scalebar.
Q_DECL_DEPRECATED void setLineColor(const QColor &color)
Sets the color used for lines in the scalebar.
void setDivisionLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the scalebar divisions (only used for some scalebar types).
Q_DECL_DEPRECATED QColor lineColor() const
Returns the color used for lines in the scalebar.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
void update()
Adjusts the scale bar box size and updates the item.
void setFillSymbol(QgsFillSymbol *symbol)
Sets the primary fill symbol used to render the scalebar (only used for some scalebar types).
double unitsPerSegment() const
Returns the number of scalebar units per segment.
void setAlignment(Qgis::ScaleBarAlignment alignment)
Sets the scalebar alignment.
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
bool applyDefaultRendererSettings(QgsScaleBarRenderer *renderer)
Applies any default settings relating to the specified renderer to the item.
double minimumBarWidth() const
Returns the minimum width (in millimeters) for scale bar segments.
QgsLineSymbol * subdivisionLineSymbol() const
Returns the line symbol used to render the scalebar subdivisions (only used for some scalebar types).
Q_DECL_DEPRECATED QFont font() const
Returns the font used for drawing text in the scalebar.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
void setAlternateFillSymbol(QgsFillSymbol *symbol)
Sets the secondary fill symbol used to render the scalebar (only used for some scalebar types).
void setLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the scalebar (only used for some scalebar types).
void setStyle(const QString &name)
Sets the scale bar style by name.
Q_DECL_DEPRECATED void setFillColor2(const QColor &color)
Sets the secondary color used for fills in the scalebar.
void applyDefaultSettings()
Applies the default scalebar settings to the scale bar.
void setLabelVerticalPlacement(Qgis::ScaleBarDistanceLabelVerticalPlacement placement)
Sets the vertical placement of text labels.
void setLabelHorizontalPlacement(Qgis::ScaleBarDistanceLabelHorizontalPlacement placement)
Sets the horizontal placement of text labels.
void setHeight(double height)
Sets the scalebar height (in millimeters).
Q_DECL_DEPRECATED Qt::PenCapStyle lineCapStyle() const
Returns the cap style used for drawing lines in the scalebar.
void setSubdivisionsHeight(double height)
Sets the scalebar subdivisions height (in millimeters) for segments included in the right part of the...
void setNumberOfSegmentsLeft(int segments)
Sets the number of segments included in the left part of the scalebar.
Qgis::DistanceUnit units() const
Returns the distance units used by the scalebar.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::DataDefinedProperty::AllProperties) override
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
Q_DECL_DEPRECATED Qt::PenJoinStyle lineJoinStyle() const
Returns the join style used for drawing lines in the scalebar.
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for drawing text in the scalebar.
void setUnits(Qgis::DistanceUnit units)
Sets the distance units used by the scalebar.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map item linked to the scalebar.
QgsLayoutSize minimumSize() const override
Returns the minimum allowed size of the item, if applicable, or an empty size if item can be freely r...
Q_DECL_DEPRECATED void setLineJoinStyle(Qt::PenJoinStyle style)
Sets the join style used when drawing the lines in the scalebar.
void setSegmentSizeMode(Qgis::ScaleBarSegmentSizeMode mode)
Sets the size mode for scale bar segments.
QgsLineSymbol * lineSymbol() const
Returns the line symbol used to render the scalebar (only used for some scalebar types).
double maximumBarWidth() const
Returns the maximum width (in millimeters) for scale bar segments.
Q_DECL_DEPRECATED void setFontColor(const QColor &color)
Sets the color used for drawing text in the scalebar.
Q_DECL_DEPRECATED void setLineWidth(double width)
Sets the line width in millimeters for lines in the scalebar.
Q_DECL_DEPRECATED QPen pen() const
Returns the pen used for drawing outlines in the scalebar.
void setBoxContentSpace(double space)
Sets the space (margin) between the scalebar box and content in millimeters.
const QgsNumericFormat * numericFormat() const
Returns the numeric format used for numbers in the scalebar.
void setUnitLabel(const QString &label)
Sets the label for units.
QString style() const
Returns the scale bar style name.
ExportLayerBehavior exportLayerBehavior() const override
Returns the behavior of this item during exporting to layered exports (e.g.
QgsTextFormat textFormat() const
Returns the text format used for drawing text in the scalebar.
Q_DECL_DEPRECATED void setLineCapStyle(Qt::PenCapStyle style)
Sets the cap style used when drawing the lines in the scalebar.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void resizeToMinimumWidth()
Resizes the scale bar to its minimum width, without changing the height.
void setUnitsPerSegment(double units)
Sets the number of scalebar units per segment.
static QgsLayoutItemScaleBar * create(QgsLayout *layout)
Returns a new scale bar item for the specified layout.
void setMethod(Qgis::ScaleCalculationMethod method)
Sets the scale calculation method, which determines how the bar's scale will be calculated.
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the font used for drawing text in the scalebar.
Qgis::DistanceUnit guessUnits() const
Attempts to guess the most reasonable unit choice for the scalebar, given the current linked map's sc...
void setSubdivisionLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the scalebar subdivisions (only used for some scalebar types).
void applyDefaultSize(Qgis::DistanceUnit units=Qgis::DistanceUnit::Meters)
Applies the default size to the scale bar (scale bar 1/5 of map item width).
Qgis::ScaleCalculationMethod method() const
Returns the scale calculation method, which determines how the bar's scale will be calculated.
void setNumberOfSubdivisions(int subdivisions)
Sets the number of subdivisions for segments included in the right part of the scalebar (only used fo...
QgsLayoutItemScaleBar(QgsLayout *layout)
Constructor for QgsLayoutItemScaleBar, with the specified parent layout.
friend class QgsLayout
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::DataDefinedProperty::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
QgsLayoutItem(QgsLayout *layout, bool manageZValue=true)
Constructor for QgsLayoutItem, with the specified parent layout.
friend class QgsLayoutItemMap
void refreshItemSize()
Refreshes an item's size by rechecking it against any possible item fixed or minimum sizes.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual QString displayName() const
Gets item display name.
virtual void attemptResize(const QgsLayoutSize &size, bool includesFrame=false)
Attempts to resize the item to a specified target size.
virtual QString uuid() const
Returns the item identification string.
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
@ CanGroupWithItemsOfSameType
Item can only be placed on layers with other items of the same type, but multiple items of this type ...
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
Provides a method of storing measurements for use in QGIS layouts using a variety of different measur...
QgsPropertyCollection mDataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the object's property collection, used for data defined overrides.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
DataDefinedProperty
Data defined properties for different item types.
@ ScalebarMinimumWidth
Scalebar segment minimum width.
@ ScalebarRightSegments
Number of segments on the right of 0.
@ ScalebarLineColor
Scalebar line color (deprecated, use data defined properties on scalebar line symbol instead).
@ ScalebarRightSegmentSubdivisions
Number of subdivisions per segment on right of 0.
@ ScalebarMaximumWidth
Scalebar segment maximum width.
@ ScalebarFillColor2
Scalebar secondary fill color (deprecated, use data defined properties on scalebar fill symbol 2 inst...
@ ScalebarSubdivisionHeight
Scalebar subdivision height.
@ ScalebarFillColor
Scalebar fill color (deprecated, use data defined properties on scalebar fill symbol 1 instead).
@ ScalebarLineWidth
Scalebar line width (deprecated, use data defined properties on scalebar line symbol instead).
@ ScalebarLeftSegments
Number of segments on the left of 0.
@ ScalebarSegmentWidth
Scalebar width in map units of a single segment.
@ AllProperties
All properties for item.
Provides a method of storing sizes, consisting of a width and height, for use in QGIS layouts.
static QgsLayoutSize decodeSize(const QString &string)
Decodes a size from a string.
void setWidth(const double width)
Sets the width for the size.
Qgis::LayoutUnit units() const
Returns the units for the size.
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
static double calculatePrettySize(double minimumSize, double maximumSize)
Calculates a "pretty" size which falls between the range [minimumSize, maximumSize].
A line symbol type, for rendering LineString and MultiLineString geometries.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Abstract base class for numeric formatters, which allow for formatting a numeric value for display.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
A store for object properties.
A container for the context for various read/write operations on objects.
double xMinimum
double yMinimum
double xMaximum
double yMaximum
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
Abstract base class for scale bar renderers.
virtual bool applyDefaultSettings(QgsScaleBarSettings &settings) const
Applies any default settings relating to the scalebar to the passed settings object.
double unitsPerSegment() const
Returns the number of scalebar units per segment.
Stores settings for use within QGIS.
Definition qgssettings.h:65
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A text format entity for QgsStyle databases.
Definition qgsstyle.h:1460
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
static std::unique_ptr< QgsSymbol > loadSymbol(const QDomElement &element, const QgsReadWriteContext &context)
Attempts to load a symbol from a DOM element.
static QString encodePenCapStyle(Qt::PenCapStyle style)
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Container for all settings relating to text rendering.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE Qgis::DistanceUnit decodeDistanceUnit(const QString &string, bool *ok=nullptr)
Decodes a distance unit from a string.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition qgis.h:6817
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7170
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7169
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
#define QgsDebugError(str)
Definition qgslogger.h:57
Contains parameters regarding scalebar calculations.
QSizeF size
Destination size for scalebar.
bool isValid() const
Returns true if the context has valid settings.
QgsScaleBarRenderer::Flags flags
Scalebar renderer flags.
double segmentWidth
The width, in millimeters, of each individual segment drawn.
Contains information relating to the style entity currently being visited.