mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-29 00:05:09 -04:00
828 lines
29 KiB
C++
828 lines
29 KiB
C++
/***************************************************************************
|
|
qgslayoutitemscalebar.cpp
|
|
-------------------------
|
|
begin : November 2017
|
|
copyright : (C) 2017 by Nyall Dawson
|
|
email : nyall dot dawson at gmail dot com
|
|
***************************************************************************/
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgslayoutitemscalebar.h"
|
|
#include "qgslayoutitemregistry.h"
|
|
#include "qgslayoutitemmap.h"
|
|
#include "qgslayout.h"
|
|
#include "qgslayoututils.h"
|
|
#include "qgsdistancearea.h"
|
|
#include "qgsscalebarrenderer.h"
|
|
#include "qgsdoubleboxscalebarrenderer.h"
|
|
#include "qgsmapsettings.h"
|
|
#include "qgsnumericscalebarrenderer.h"
|
|
#include "qgssingleboxscalebarrenderer.h"
|
|
#include "qgsticksscalebarrenderer.h"
|
|
#include "qgsrectangle.h"
|
|
#include "qgsproject.h"
|
|
#include "qgssymbollayerutils.h"
|
|
#include "qgsfontutils.h"
|
|
#include "qgsunittypes.h"
|
|
#include "qgssettings.h"
|
|
|
|
#include <QDomDocument>
|
|
#include <QDomElement>
|
|
#include <QFontMetricsF>
|
|
#include <QPainter>
|
|
|
|
#include <cmath>
|
|
|
|
QgsLayoutItemScaleBar::QgsLayoutItemScaleBar( QgsLayout *layout )
|
|
: QgsLayoutItem( layout )
|
|
{
|
|
applyDefaultSettings();
|
|
applyDefaultSize();
|
|
}
|
|
|
|
int QgsLayoutItemScaleBar::type() const
|
|
{
|
|
return QgsLayoutItemRegistry::LayoutScaleBar;
|
|
}
|
|
|
|
QIcon QgsLayoutItemScaleBar::icon() const
|
|
{
|
|
return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemScaleBar.svg" ) );
|
|
}
|
|
|
|
QgsLayoutItemScaleBar *QgsLayoutItemScaleBar::create( QgsLayout *layout )
|
|
{
|
|
return new QgsLayoutItemScaleBar( layout );
|
|
}
|
|
|
|
QgsLayoutSize QgsLayoutItemScaleBar::minimumSize() const
|
|
{
|
|
return QgsLayoutSize( mStyle->calculateBoxSize( mSettings, createScaleContext() ), QgsUnitTypes::LayoutMillimeters );
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem * )
|
|
{
|
|
if ( !mStyle )
|
|
return;
|
|
|
|
mStyle->draw( context, mSettings, createScaleContext() );
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setNumberOfSegments( int nSegments )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setNumberOfSegments( nSegments );
|
|
return;
|
|
}
|
|
mSettings.setNumberOfSegments( nSegments );
|
|
resizeToMinimumWidth();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setUnitsPerSegment( double units )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setUnitsPerSegment( units );
|
|
return;
|
|
}
|
|
mSettings.setUnitsPerSegment( units );
|
|
refreshSegmentMillimeters();
|
|
resizeToMinimumWidth();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setSegmentSizeMode( QgsScaleBarSettings::SegmentSizeMode mode )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setSegmentSizeMode( mode );
|
|
return;
|
|
}
|
|
mSettings.setSegmentSizeMode( mode );
|
|
refreshSegmentMillimeters();
|
|
resizeToMinimumWidth();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setMinimumBarWidth( double minWidth )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setMinimumBarWidth( minWidth );
|
|
return;
|
|
}
|
|
mSettings.setMinimumBarWidth( minWidth );
|
|
refreshSegmentMillimeters();
|
|
resizeToMinimumWidth();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setMaximumBarWidth( double maxWidth )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setMaximumBarWidth( maxWidth );
|
|
return;
|
|
}
|
|
mSettings.setMaximumBarWidth( maxWidth );
|
|
refreshSegmentMillimeters();
|
|
resizeToMinimumWidth();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setNumberOfSegmentsLeft( int nSegmentsLeft )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
|
|
return;
|
|
}
|
|
mSettings.setNumberOfSegmentsLeft( nSegmentsLeft );
|
|
resizeToMinimumWidth();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setBoxContentSpace( double space )
|
|
{
|
|
if ( !mStyle )
|
|
{
|
|
mSettings.setBoxContentSpace( space );
|
|
return;
|
|
}
|
|
mSettings.setBoxContentSpace( space );
|
|
refreshItemSize();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setLinkedMap( QgsLayoutItemMap *map )
|
|
{
|
|
disconnectCurrentMap();
|
|
|
|
mMap = map;
|
|
|
|
if ( !map )
|
|
{
|
|
return;
|
|
}
|
|
|
|
connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
|
|
connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
|
|
|
|
refreshSegmentMillimeters();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::disconnectCurrentMap()
|
|
{
|
|
if ( !mMap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
disconnect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
|
|
disconnect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
|
|
mMap = nullptr;
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property )
|
|
{
|
|
QgsExpressionContext context = createExpressionContext();
|
|
|
|
bool forceUpdate = false;
|
|
//updates data defined properties and redraws item to match
|
|
if ( property == QgsLayoutObject::ScalebarFillColor || property == QgsLayoutObject::AllProperties )
|
|
{
|
|
QBrush b = mSettings.brush();
|
|
b.setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarFillColor, context, mSettings.fillColor() ) );
|
|
mSettings.setBrush( b );
|
|
forceUpdate = true;
|
|
}
|
|
if ( property == QgsLayoutObject::ScalebarFillColor2 || property == QgsLayoutObject::AllProperties )
|
|
{
|
|
QBrush b = mSettings.brush2();
|
|
b.setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarFillColor2, context, mSettings.fillColor2() ) );
|
|
mSettings.setBrush2( b );
|
|
forceUpdate = true;
|
|
}
|
|
if ( property == QgsLayoutObject::ScalebarLineColor || property == QgsLayoutObject::AllProperties )
|
|
{
|
|
QPen p = mSettings.pen();
|
|
p.setColor( mDataDefinedProperties.valueAsColor( QgsLayoutObject::ScalebarLineColor, context, mSettings.lineColor() ) );
|
|
mSettings.setPen( p );
|
|
forceUpdate = true;
|
|
}
|
|
if ( property == QgsLayoutObject::ScalebarLineWidth || property == QgsLayoutObject::AllProperties )
|
|
{
|
|
QPen p = mSettings.pen();
|
|
p.setWidthF( mDataDefinedProperties.valueAsDouble( QgsLayoutObject::ScalebarLineWidth, context, mSettings.lineWidth() ) );
|
|
mSettings.setPen( p );
|
|
forceUpdate = true;
|
|
}
|
|
if ( forceUpdate )
|
|
{
|
|
refreshItemSize();
|
|
update();
|
|
}
|
|
|
|
QgsLayoutItem::refreshDataDefinedProperty( property );
|
|
}
|
|
|
|
// nextNiceNumber(4573.23, d) = 5000 (d=1) -> 4600 (d=10) -> 4580 (d=100) -> 4574 (d=1000) -> etc
|
|
inline double nextNiceNumber( double a, double d = 1 )
|
|
{
|
|
double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
|
|
return std::ceil( a / s ) * s;
|
|
}
|
|
|
|
// prevNiceNumber(4573.23, d) = 4000 (d=1) -> 4500 (d=10) -> 4570 (d=100) -> 4573 (d=1000) -> etc
|
|
inline double prevNiceNumber( double a, double d = 1 )
|
|
{
|
|
double s = std::pow( 10.0, std::floor( std::log10( a ) ) ) / d;
|
|
return std::floor( a / s ) * s;
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::refreshSegmentMillimeters()
|
|
{
|
|
if ( mMap )
|
|
{
|
|
//get mm dimension of composer map
|
|
QRectF composerItemRect = mMap->rect();
|
|
|
|
if ( mSettings.segmentSizeMode() == QgsScaleBarSettings::SegmentSizeFixed )
|
|
{
|
|
//calculate size depending on mNumUnitsPerSegment
|
|
mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
|
|
}
|
|
else /*if(mSegmentSizeMode == SegmentSizeFitWidth)*/
|
|
{
|
|
if ( mSettings.maximumBarWidth() < mSettings.minimumBarWidth() )
|
|
{
|
|
mSegmentMillimeters = 0;
|
|
}
|
|
else
|
|
{
|
|
double nSegments = ( mSettings.numberOfSegmentsLeft() != 0 ) + mSettings.numberOfSegments();
|
|
// unitsPerSegments which fit minBarWidth resp. maxBarWidth
|
|
double minUnitsPerSeg = ( mSettings.minimumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
|
|
double maxUnitsPerSeg = ( mSettings.maximumBarWidth() * mapWidth() ) / ( nSegments * composerItemRect.width() );
|
|
|
|
// Start with coarsest "nice" number closest to minUnitsPerSeg resp
|
|
// maxUnitsPerSeg, then proceed to finer numbers as long as neither
|
|
// lowerNiceUnitsPerSeg nor upperNiceUnitsPerSeg are are in
|
|
// [minUnitsPerSeg, maxUnitsPerSeg]
|
|
double lowerNiceUnitsPerSeg = nextNiceNumber( minUnitsPerSeg );
|
|
double upperNiceUnitsPerSeg = prevNiceNumber( maxUnitsPerSeg );
|
|
|
|
double d = 1;
|
|
while ( lowerNiceUnitsPerSeg > maxUnitsPerSeg && upperNiceUnitsPerSeg < minUnitsPerSeg )
|
|
{
|
|
d *= 10;
|
|
lowerNiceUnitsPerSeg = nextNiceNumber( minUnitsPerSeg, d );
|
|
upperNiceUnitsPerSeg = prevNiceNumber( maxUnitsPerSeg, d );
|
|
}
|
|
|
|
// Pick mNumUnitsPerSegment from {lowerNiceUnitsPerSeg, upperNiceUnitsPerSeg}, use the larger if possible
|
|
mSettings.setUnitsPerSegment( upperNiceUnitsPerSeg < minUnitsPerSeg ? lowerNiceUnitsPerSeg : upperNiceUnitsPerSeg );
|
|
mSegmentMillimeters = composerItemRect.width() / mapWidth() * mSettings.unitsPerSegment();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
double QgsLayoutItemScaleBar::mapWidth() const
|
|
{
|
|
if ( !mMap )
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
QgsRectangle mapExtent = mMap->extent();
|
|
if ( mSettings.units() == QgsUnitTypes::DistanceUnknownUnit )
|
|
{
|
|
return mapExtent.width();
|
|
}
|
|
else
|
|
{
|
|
QgsDistanceArea da;
|
|
da.setSourceCrs( mMap->crs(), mLayout->project()->transformContext() );
|
|
da.setEllipsoid( mLayout->project()->ellipsoid() );
|
|
|
|
QgsUnitTypes::DistanceUnit units = da.lengthUnits();
|
|
double measure = da.measureLine( QgsPointXY( mapExtent.xMinimum(), mapExtent.yMinimum() ),
|
|
QgsPointXY( mapExtent.xMaximum(), mapExtent.yMinimum() ) );
|
|
measure /= QgsUnitTypes::fromUnitToUnitFactor( mSettings.units(), units );
|
|
return measure;
|
|
}
|
|
}
|
|
|
|
QgsScaleBarRenderer::ScaleBarContext QgsLayoutItemScaleBar::createScaleContext() const
|
|
{
|
|
QgsScaleBarRenderer::ScaleBarContext scaleContext;
|
|
scaleContext.size = rect().size();
|
|
scaleContext.segmentWidth = mSegmentMillimeters;
|
|
scaleContext.scale = mMap ? mMap->scale() : 1.0;
|
|
return scaleContext;
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setAlignment( QgsScaleBarSettings::Alignment a )
|
|
{
|
|
mSettings.setAlignment( a );
|
|
refreshItemSize();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setUnits( QgsUnitTypes::DistanceUnit u )
|
|
{
|
|
mSettings.setUnits( u );
|
|
refreshSegmentMillimeters();
|
|
refreshItemSize();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setLineJoinStyle( Qt::PenJoinStyle style )
|
|
{
|
|
if ( mSettings.lineJoinStyle() == style )
|
|
{
|
|
//no change
|
|
return;
|
|
}
|
|
mSettings.setLineJoinStyle( style );
|
|
update();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setLineCapStyle( Qt::PenCapStyle style )
|
|
{
|
|
if ( mSettings.lineCapStyle() == style )
|
|
{
|
|
//no change
|
|
return;
|
|
}
|
|
mSettings.setLineCapStyle( style );
|
|
update();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::applyDefaultSettings()
|
|
{
|
|
//style
|
|
mStyle = qgis::make_unique< QgsSingleBoxScaleBarRenderer >();
|
|
|
|
//default to no background
|
|
setBackgroundEnabled( false );
|
|
|
|
//get default composer font from settings
|
|
QgsSettings settings;
|
|
QString defaultFontString = settings.value( QStringLiteral( "Composer/defaultFont" ) ).toString();
|
|
QFont f;
|
|
if ( !defaultFontString.isEmpty() )
|
|
{
|
|
f.setFamily( defaultFontString );
|
|
}
|
|
f.setPointSizeF( 12.0 );
|
|
mSettings.setFont( f );
|
|
|
|
mSettings.setUnits( QgsUnitTypes::DistanceUnknownUnit );
|
|
refreshItemSize();
|
|
|
|
emit changed();
|
|
}
|
|
|
|
QgsUnitTypes::DistanceUnit QgsLayoutItemScaleBar::guessUnits() const
|
|
{
|
|
if ( !mMap )
|
|
return QgsUnitTypes::DistanceMeters;
|
|
|
|
QgsCoordinateReferenceSystem crs = mMap->crs();
|
|
// start with crs units
|
|
QgsUnitTypes::DistanceUnit unit = crs.mapUnits();
|
|
if ( unit == QgsUnitTypes::DistanceDegrees || unit == QgsUnitTypes::DistanceUnknownUnit )
|
|
{
|
|
// geographic CRS, use metric units
|
|
unit = QgsUnitTypes::DistanceMeters;
|
|
}
|
|
|
|
// try to pick reasonable choice between metric / imperial units
|
|
double widthInSelectedUnits = mapWidth();
|
|
double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
|
|
switch ( unit )
|
|
{
|
|
case QgsUnitTypes::DistanceMeters:
|
|
{
|
|
if ( initialUnitsPerSegment > 1000.0 )
|
|
{
|
|
unit = QgsUnitTypes::DistanceKilometers;
|
|
}
|
|
break;
|
|
}
|
|
case QgsUnitTypes::DistanceFeet:
|
|
{
|
|
if ( initialUnitsPerSegment > 5419.95 )
|
|
{
|
|
unit = QgsUnitTypes::DistanceMiles;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return unit;
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::applyDefaultSize( QgsUnitTypes::DistanceUnit units )
|
|
{
|
|
mSettings.setUnits( units );
|
|
if ( mMap )
|
|
{
|
|
double upperMagnitudeMultiplier = 1.0;
|
|
double widthInSelectedUnits = mapWidth();
|
|
double initialUnitsPerSegment = widthInSelectedUnits / 10.0; //default scalebar width equals half the map width
|
|
mSettings.setUnitsPerSegment( initialUnitsPerSegment );
|
|
|
|
setUnitLabel( QgsUnitTypes::toAbbreviatedString( units ) );
|
|
upperMagnitudeMultiplier = 1;
|
|
|
|
double segmentWidth = initialUnitsPerSegment / upperMagnitudeMultiplier;
|
|
int segmentMagnitude = std::floor( std::log10( segmentWidth ) );
|
|
double unitsPerSegment = upperMagnitudeMultiplier * ( std::pow( 10.0, segmentMagnitude ) );
|
|
double multiplier = std::floor( ( widthInSelectedUnits / ( unitsPerSegment * 10.0 ) ) / 2.5 ) * 2.5;
|
|
|
|
if ( multiplier > 0 )
|
|
{
|
|
unitsPerSegment = unitsPerSegment * multiplier;
|
|
}
|
|
mSettings.setUnitsPerSegment( unitsPerSegment );
|
|
mSettings.setMapUnitsPerScaleBarUnit( upperMagnitudeMultiplier );
|
|
|
|
mSettings.setNumberOfSegments( 4 );
|
|
mSettings.setNumberOfSegmentsLeft( 2 );
|
|
}
|
|
|
|
refreshSegmentMillimeters();
|
|
resizeToMinimumWidth();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::resizeToMinimumWidth()
|
|
{
|
|
if ( !mStyle )
|
|
return;
|
|
|
|
double widthMM = mStyle->calculateBoxSize( mSettings, createScaleContext() ).width();
|
|
QgsLayoutSize currentSize = sizeWithUnits();
|
|
currentSize.setWidth( mLayout->renderContext().measurementConverter().convert( QgsLayoutMeasurement( widthMM, QgsUnitTypes::LayoutMillimeters ), currentSize.units() ).length() );
|
|
attemptResize( currentSize );
|
|
update();
|
|
emit changed();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::update()
|
|
{
|
|
//Don't adjust box size for numeric scale bars:
|
|
if ( mStyle && mStyle->name() != QLatin1String( "Numeric" ) )
|
|
{
|
|
refreshItemSize();
|
|
}
|
|
QgsLayoutItem::update();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::updateScale()
|
|
{
|
|
refreshSegmentMillimeters();
|
|
resizeToMinimumWidth();
|
|
update();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setStyle( const QString &styleName )
|
|
{
|
|
//switch depending on style name
|
|
if ( styleName == QLatin1String( "Single Box" ) )
|
|
{
|
|
mStyle = qgis::make_unique< QgsSingleBoxScaleBarRenderer >();
|
|
}
|
|
else if ( styleName == QLatin1String( "Double Box" ) )
|
|
{
|
|
mStyle = qgis::make_unique< QgsDoubleBoxScaleBarRenderer >();
|
|
}
|
|
else if ( styleName == QLatin1String( "Line Ticks Middle" ) || styleName == QLatin1String( "Line Ticks Down" ) || styleName == QLatin1String( "Line Ticks Up" ) )
|
|
{
|
|
std::unique_ptr< QgsTicksScaleBarRenderer > tickStyle = qgis::make_unique< QgsTicksScaleBarRenderer >();
|
|
if ( styleName == QLatin1String( "Line Ticks Middle" ) )
|
|
{
|
|
tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksMiddle );
|
|
}
|
|
else if ( styleName == QLatin1String( "Line Ticks Down" ) )
|
|
{
|
|
tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksDown );
|
|
}
|
|
else if ( styleName == QLatin1String( "Line Ticks Up" ) )
|
|
{
|
|
tickStyle->setTickPosition( QgsTicksScaleBarRenderer::TicksUp );
|
|
}
|
|
mStyle = std::move( tickStyle );
|
|
}
|
|
else if ( styleName == QLatin1String( "Numeric" ) )
|
|
{
|
|
mStyle = qgis::make_unique< QgsNumericScaleBarRenderer >();
|
|
}
|
|
refreshItemSize();
|
|
emit changed();
|
|
}
|
|
|
|
QString QgsLayoutItemScaleBar::style() const
|
|
{
|
|
if ( mStyle )
|
|
{
|
|
return mStyle->name();
|
|
}
|
|
else
|
|
{
|
|
return QString();
|
|
}
|
|
}
|
|
|
|
QFont QgsLayoutItemScaleBar::font() const
|
|
{
|
|
return mSettings.font();
|
|
}
|
|
|
|
void QgsLayoutItemScaleBar::setFont( const QFont &font )
|
|
{
|
|
mSettings.setFont( font );
|
|
refreshItemSize();
|
|
emit changed();
|
|
}
|
|
|
|
bool QgsLayoutItemScaleBar::writePropertiesToElement( QDomElement &composerScaleBarElem, QDomDocument &doc, const QgsReadWriteContext & ) const
|
|
{
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "height" ), QString::number( mSettings.height() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "labelBarSpace" ), QString::number( mSettings.labelBarSpace() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "boxContentSpace" ), QString::number( mSettings.boxContentSpace() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "numSegments" ), mSettings.numberOfSegments() );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "numSegmentsLeft" ), mSettings.numberOfSegmentsLeft() );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "numUnitsPerSegment" ), QString::number( mSettings.unitsPerSegment() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "segmentSizeMode" ), mSettings.segmentSizeMode() );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "minBarWidth" ), mSettings.minimumBarWidth() );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "maxBarWidth" ), mSettings.maximumBarWidth() );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "segmentMillimeters" ), QString::number( mSegmentMillimeters ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QString::number( mSettings.mapUnitsPerScaleBarUnit() ) );
|
|
composerScaleBarElem.appendChild( QgsFontUtils::toXmlElement( mSettings.font(), doc, QStringLiteral( "scaleBarFont" ) ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "outlineWidth" ), QString::number( mSettings.lineWidth() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "unitLabel" ), mSettings.unitLabel() );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "unitType" ), QgsUnitTypes::encodeUnit( mSettings.units() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "lineJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mSettings.lineJoinStyle() ) );
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "lineCapStyle" ), QgsSymbolLayerUtils::encodePenCapStyle( mSettings.lineCapStyle() ) );
|
|
|
|
//style
|
|
if ( mStyle )
|
|
{
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "style" ), mStyle->name() );
|
|
}
|
|
|
|
//map id
|
|
if ( mMap )
|
|
{
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "mapUuid" ), mMap->uuid() );
|
|
}
|
|
|
|
//colors
|
|
|
|
//fill color
|
|
QDomElement fillColorElem = doc.createElement( QStringLiteral( "fillColor" ) );
|
|
fillColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor().red() ) );
|
|
fillColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor().green() ) );
|
|
fillColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor().blue() ) );
|
|
fillColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor().alpha() ) );
|
|
composerScaleBarElem.appendChild( fillColorElem );
|
|
|
|
//fill color 2
|
|
QDomElement fillColor2Elem = doc.createElement( QStringLiteral( "fillColor2" ) );
|
|
fillColor2Elem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fillColor2().red() ) );
|
|
fillColor2Elem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fillColor2().green() ) );
|
|
fillColor2Elem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fillColor2().blue() ) );
|
|
fillColor2Elem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fillColor2().alpha() ) );
|
|
composerScaleBarElem.appendChild( fillColor2Elem );
|
|
|
|
//pen color
|
|
QDomElement strokeColorElem = doc.createElement( QStringLiteral( "strokeColor" ) );
|
|
strokeColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.lineColor().red() ) );
|
|
strokeColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.lineColor().green() ) );
|
|
strokeColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.lineColor().blue() ) );
|
|
strokeColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.lineColor().alpha() ) );
|
|
composerScaleBarElem.appendChild( strokeColorElem );
|
|
|
|
//font color
|
|
QDomElement fontColorElem = doc.createElement( QStringLiteral( "textColor" ) );
|
|
fontColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mSettings.fontColor().red() ) );
|
|
fontColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mSettings.fontColor().green() ) );
|
|
fontColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mSettings.fontColor().blue() ) );
|
|
fontColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mSettings.fontColor().alpha() ) );
|
|
composerScaleBarElem.appendChild( fontColorElem );
|
|
|
|
//alignment
|
|
composerScaleBarElem.setAttribute( QStringLiteral( "alignment" ), QString::number( static_cast< int >( mSettings.alignment() ) ) );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool QgsLayoutItemScaleBar::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
|
|
{
|
|
mSettings.setHeight( itemElem.attribute( QStringLiteral( "height" ), QStringLiteral( "5.0" ) ).toDouble() );
|
|
mSettings.setLabelBarSpace( itemElem.attribute( QStringLiteral( "labelBarSpace" ), QStringLiteral( "3.0" ) ).toDouble() );
|
|
mSettings.setBoxContentSpace( itemElem.attribute( QStringLiteral( "boxContentSpace" ), QStringLiteral( "1.0" ) ).toDouble() );
|
|
mSettings.setNumberOfSegments( itemElem.attribute( QStringLiteral( "numSegments" ), QStringLiteral( "2" ) ).toInt() );
|
|
mSettings.setNumberOfSegmentsLeft( itemElem.attribute( QStringLiteral( "numSegmentsLeft" ), QStringLiteral( "0" ) ).toInt() );
|
|
mSettings.setUnitsPerSegment( itemElem.attribute( QStringLiteral( "numUnitsPerSegment" ), QStringLiteral( "1.0" ) ).toDouble() );
|
|
mSettings.setSegmentSizeMode( static_cast<QgsScaleBarSettings::SegmentSizeMode>( itemElem.attribute( QStringLiteral( "segmentSizeMode" ), QStringLiteral( "0" ) ).toInt() ) );
|
|
mSettings.setMinimumBarWidth( itemElem.attribute( QStringLiteral( "minBarWidth" ), QStringLiteral( "50" ) ).toDouble() );
|
|
mSettings.setMaximumBarWidth( itemElem.attribute( QStringLiteral( "maxBarWidth" ), QStringLiteral( "150" ) ).toDouble() );
|
|
mSegmentMillimeters = itemElem.attribute( QStringLiteral( "segmentMillimeters" ), QStringLiteral( "0.0" ) ).toDouble();
|
|
mSettings.setMapUnitsPerScaleBarUnit( itemElem.attribute( QStringLiteral( "numMapUnitsPerScaleBarUnit" ), QStringLiteral( "1.0" ) ).toDouble() );
|
|
mSettings.setLineWidth( itemElem.attribute( QStringLiteral( "outlineWidth" ), QStringLiteral( "0.3" ) ).toDouble() );
|
|
mSettings.setUnitLabel( itemElem.attribute( QStringLiteral( "unitLabel" ) ) );
|
|
mSettings.setLineJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( itemElem.attribute( QStringLiteral( "lineJoinStyle" ), QStringLiteral( "miter" ) ) ) );
|
|
mSettings.setLineCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( itemElem.attribute( QStringLiteral( "lineCapStyle" ), QStringLiteral( "square" ) ) ) );
|
|
QFont f;
|
|
if ( !QgsFontUtils::setFromXmlChildNode( f, itemElem, QStringLiteral( "scaleBarFont" ) ) )
|
|
{
|
|
f.fromString( itemElem.attribute( QStringLiteral( "font" ), QLatin1String( "" ) ) );
|
|
}
|
|
mSettings.setFont( f );
|
|
|
|
//colors
|
|
//fill color
|
|
QDomNodeList fillColorList = itemElem.elementsByTagName( QStringLiteral( "fillColor" ) );
|
|
if ( !fillColorList.isEmpty() )
|
|
{
|
|
QDomElement fillColorElem = fillColorList.at( 0 ).toElement();
|
|
bool redOk, greenOk, blueOk, alphaOk;
|
|
int fillRed, fillGreen, fillBlue, fillAlpha;
|
|
|
|
fillRed = fillColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
|
|
fillGreen = fillColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
|
|
fillBlue = fillColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
|
|
fillAlpha = fillColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
|
|
|
|
if ( redOk && greenOk && blueOk && alphaOk )
|
|
{
|
|
mSettings.setFillColor( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mSettings.setFillColor( QColor( itemElem.attribute( QStringLiteral( "brushColor" ), QStringLiteral( "#000000" ) ) ) );
|
|
}
|
|
|
|
//fill color 2
|
|
QDomNodeList fillColor2List = itemElem.elementsByTagName( QStringLiteral( "fillColor2" ) );
|
|
if ( !fillColor2List.isEmpty() )
|
|
{
|
|
QDomElement fillColor2Elem = fillColor2List.at( 0 ).toElement();
|
|
bool redOk, greenOk, blueOk, alphaOk;
|
|
int fillRed, fillGreen, fillBlue, fillAlpha;
|
|
|
|
fillRed = fillColor2Elem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
|
|
fillGreen = fillColor2Elem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
|
|
fillBlue = fillColor2Elem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
|
|
fillAlpha = fillColor2Elem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
|
|
|
|
if ( redOk && greenOk && blueOk && alphaOk )
|
|
{
|
|
mSettings.setFillColor2( QColor( fillRed, fillGreen, fillBlue, fillAlpha ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mSettings.setFillColor2( QColor( itemElem.attribute( QStringLiteral( "brush2Color" ), QStringLiteral( "#ffffff" ) ) ) );
|
|
}
|
|
|
|
//stroke color
|
|
QDomNodeList strokeColorList = itemElem.elementsByTagName( QStringLiteral( "strokeColor" ) );
|
|
if ( !strokeColorList.isEmpty() )
|
|
{
|
|
QDomElement strokeColorElem = strokeColorList.at( 0 ).toElement();
|
|
bool redOk, greenOk, blueOk, alphaOk;
|
|
int strokeRed, strokeGreen, strokeBlue, strokeAlpha;
|
|
|
|
strokeRed = strokeColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
|
|
strokeGreen = strokeColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
|
|
strokeBlue = strokeColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
|
|
strokeAlpha = strokeColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
|
|
|
|
if ( redOk && greenOk && blueOk && alphaOk )
|
|
{
|
|
mSettings.setLineColor( QColor( strokeRed, strokeGreen, strokeBlue, strokeAlpha ) );
|
|
QPen p = mSettings.pen();
|
|
p.setColor( mSettings.lineColor() );
|
|
mSettings.setPen( p );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mSettings.setLineColor( QColor( itemElem.attribute( QStringLiteral( "penColor" ), QStringLiteral( "#000000" ) ) ) );
|
|
QPen p = mSettings.pen();
|
|
p.setColor( mSettings.lineColor() );
|
|
mSettings.setPen( p );
|
|
}
|
|
|
|
//font color
|
|
QDomNodeList textColorList = itemElem.elementsByTagName( QStringLiteral( "textColor" ) );
|
|
if ( !textColorList.isEmpty() )
|
|
{
|
|
QDomElement textColorElem = textColorList.at( 0 ).toElement();
|
|
bool redOk, greenOk, blueOk, alphaOk;
|
|
int textRed, textGreen, textBlue, textAlpha;
|
|
|
|
textRed = textColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
|
|
textGreen = textColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
|
|
textBlue = textColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
|
|
textAlpha = textColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
|
|
|
|
if ( redOk && greenOk && blueOk && alphaOk )
|
|
{
|
|
mSettings.setFontColor( QColor( textRed, textGreen, textBlue, textAlpha ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
QColor c;
|
|
c.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
|
|
mSettings.setFontColor( c );
|
|
}
|
|
|
|
//style
|
|
QString styleString = itemElem.attribute( QStringLiteral( "style" ), QLatin1String( "" ) );
|
|
setStyle( styleString.toLocal8Bit().data() );
|
|
|
|
if ( itemElem.attribute( QStringLiteral( "unitType" ) ).isEmpty() )
|
|
{
|
|
QgsUnitTypes::DistanceUnit u = QgsUnitTypes::DistanceUnknownUnit;
|
|
switch ( itemElem.attribute( QStringLiteral( "units" ) ).toInt() )
|
|
{
|
|
case 0:
|
|
u = QgsUnitTypes::DistanceUnknownUnit;
|
|
break;
|
|
case 1:
|
|
u = QgsUnitTypes::DistanceMeters;
|
|
break;
|
|
case 2:
|
|
u = QgsUnitTypes::DistanceFeet;
|
|
break;
|
|
case 3:
|
|
u = QgsUnitTypes::DistanceNauticalMiles;
|
|
break;
|
|
}
|
|
mSettings.setUnits( u );
|
|
}
|
|
else
|
|
{
|
|
mSettings.setUnits( QgsUnitTypes::decodeDistanceUnit( itemElem.attribute( QStringLiteral( "unitType" ) ) ) );
|
|
}
|
|
mSettings.setAlignment( static_cast< QgsScaleBarSettings::Alignment >( itemElem.attribute( QStringLiteral( "alignment" ), QStringLiteral( "0" ) ).toInt() ) );
|
|
|
|
//map
|
|
mMapUuid.clear();
|
|
mMapId = -1;
|
|
|
|
mMapId = itemElem.attribute( QStringLiteral( "mapId" ), QStringLiteral( "-1" ) ).toInt();
|
|
mMapUuid = itemElem.attribute( QStringLiteral( "mapUuid" ) );
|
|
return true;
|
|
}
|
|
|
|
|
|
void QgsLayoutItemScaleBar::finalizeRestoreFromXml()
|
|
{
|
|
#if 0 //TODO
|
|
if ( mMapId >= 0 )
|
|
{
|
|
const QgsLayoutItemMap *composerMap = mComposition->getComposerMapById( mapId );
|
|
mMap = const_cast< QgsComposerMap *>( composerMap );
|
|
if ( mMap )
|
|
{
|
|
connect( mMap, &QgsComposerMap::extentChanged, this, &QgsLayoutItemScaleBar::updateSegmentSize );
|
|
connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::invalidateCurrentMap );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( !mLayout || mMapUuid.isEmpty() )
|
|
{
|
|
mMap = nullptr;
|
|
}
|
|
else
|
|
{
|
|
disconnectCurrentMap();
|
|
mMap = qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) );
|
|
if ( mMap )
|
|
{
|
|
connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemScaleBar::updateScale );
|
|
connect( mMap, &QObject::destroyed, this, &QgsLayoutItemScaleBar::disconnectCurrentMap );
|
|
}
|
|
}
|
|
|
|
updateScale();
|
|
}
|