Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #40220 from nyalldawson/papercut_dd_grid
Don't show degrees based annotation format options for non-geographic map grids
  • Loading branch information
nyalldawson committed Nov 23, 2020
2 parents 3234489 + b6f3da3 commit 6a86642
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 19 deletions.
7 changes: 7 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitemmap.sip.in
Expand Up @@ -988,6 +988,13 @@ Emitted when the map's associated ``theme`` is changed.
is linked to a different theme then it previously was.

.. versionadded:: 3.14
%End

void crsChanged();
%Docstring
Emitted when the map's coordinate reference system is changed.

.. versionadded:: 3.18
%End

public slots:
Expand Down
9 changes: 9 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitemmapgrid.sip.in
Expand Up @@ -1118,6 +1118,15 @@ Retrieves the second fill color for the grid frame.
virtual void refresh();


signals:

void crsChanged();
%Docstring
Emitted whenever the grid's CRS is changed.

.. versionadded:: 3.18
%End

};

QFlags<QgsLayoutItemMapGrid::FrameSideFlag> operator|(QgsLayoutItemMapGrid::FrameSideFlag f1, QFlags<QgsLayoutItemMapGrid::FrameSideFlag> f2);
Expand Down
23 changes: 16 additions & 7 deletions src/core/layout/qgslayoutitemmap.cpp
Expand Up @@ -300,7 +300,11 @@ QgsCoordinateReferenceSystem QgsLayoutItemMap::crs() const

void QgsLayoutItemMap::setCrs( const QgsCoordinateReferenceSystem &crs )
{
if ( mCrs == crs )
return;

mCrs = crs;
emit crsChanged();
}

QList<QgsMapLayer *> QgsLayoutItemMap::layers() const
Expand Down Expand Up @@ -707,15 +711,13 @@ bool QgsLayoutItemMap::readPropertiesFromElement( const QDomElement &itemElem, c
}

QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
QgsCoordinateReferenceSystem crs;
if ( !crsNodeList.isEmpty() )
{
QDomElement crsElem = crsNodeList.at( 0 ).toElement();
mCrs.readXml( crsElem );
}
else
{
mCrs = QgsCoordinateReferenceSystem();
crs.readXml( crsElem );
}
setCrs( crs );

//map rotation
mMapRotation = itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble();
Expand Down Expand Up @@ -1856,9 +1858,15 @@ void QgsLayoutItemMap::refreshDataDefinedProperty( const QgsLayoutObject::DataDe
if ( property == QgsLayoutObject::MapCrs || property == QgsLayoutObject::AllProperties )
{
bool ok;
QString crsVar = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapCrs, context, QString(), &ok );
const QString crsVar = mDataDefinedProperties.valueAsString( QgsLayoutObject::MapCrs, context, QString(), &ok );
if ( ok && QgsCoordinateReferenceSystem( crsVar ).isValid() )
mCrs = QgsCoordinateReferenceSystem( crsVar );
{
const QgsCoordinateReferenceSystem newCrs( crsVar );
if ( newCrs.isValid() )
{
setCrs( newCrs );
}
}
}
//updates data defined properties and redraws item to match
if ( property == QgsLayoutObject::MapRotation || property == QgsLayoutObject::MapScale ||
Expand Down Expand Up @@ -1992,6 +2000,7 @@ void QgsLayoutItemMap::connectUpdateSlot()
{
//using project CRS, which just changed....
invalidateCache();
emit crsChanged();
}
} );

Expand Down
7 changes: 7 additions & 0 deletions src/core/layout/qgslayoutitemmap.h
Expand Up @@ -910,6 +910,13 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan
*/
void themeChanged( const QString &theme );

/**
* Emitted when the map's coordinate reference system is changed.
*
* \since QGIS 3.18
*/
void crsChanged();

public slots:

void refresh() override;
Expand Down
9 changes: 9 additions & 0 deletions src/core/layout/qgslayoutitemmapgrid.cpp
Expand Up @@ -203,6 +203,11 @@ QgsLayoutItemMapGrid::QgsLayoutItemMapGrid( const QString &name, QgsLayoutItemMa

connect( mMap, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemMapGrid::refreshDataDefinedProperties );
connect( mMap, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemMapGrid::refreshDataDefinedProperties );
connect( mMap, &QgsLayoutItemMap::crsChanged, this, [ = ]
{
if ( !mCRS.isValid() )
emit crsChanged();
} );
}

void QgsLayoutItemMapGrid::createDefaultGridLineSymbol()
Expand Down Expand Up @@ -438,8 +443,12 @@ bool QgsLayoutItemMapGrid::readXml( const QDomElement &itemElem, const QDomDocum

void QgsLayoutItemMapGrid::setCrs( const QgsCoordinateReferenceSystem &crs )
{
if ( mCRS == crs )
return;

mCRS = crs;
mTransformDirty = true;
emit crsChanged();
}

bool QgsLayoutItemMapGrid::usesAdvancedEffects() const
Expand Down
9 changes: 9 additions & 0 deletions src/core/layout/qgslayoutitemmapgrid.h
Expand Up @@ -1006,6 +1006,15 @@ class CORE_EXPORT QgsLayoutItemMapGrid : public QgsLayoutItemMapItem
bool accept( QgsStyleEntityVisitorInterface *visitor ) const override;
void refresh() override;

signals:

/**
* Emitted whenever the grid's CRS is changed.
*
* \since QGIS 3.18
*/
void crsChanged();

private:

QgsLayoutItemMapGrid() = delete;
Expand Down
70 changes: 58 additions & 12 deletions src/gui/layout/qgslayoutmapgridwidget.cpp
Expand Up @@ -48,9 +48,9 @@ QgsLayoutMapGridWidget::QgsLayoutMapGridWidget( QgsLayoutItemMapGrid *mapGrid, Q
mFrameStyleComboBox->addItem( tr( "Line Border (Nautical)" ), QgsLayoutItemMapGrid::LineBorderNautical );

mRotatedTicksLengthModeComboBox->addItem( tr( "Orthogonal" ), QgsLayoutItemMapGrid::OrthogonalTicks );
mRotatedTicksLengthModeComboBox->addItem( tr( "Fixed length" ), QgsLayoutItemMapGrid::NormalizedTicks );
mRotatedTicksLengthModeComboBox->addItem( tr( "Fixed Length" ), QgsLayoutItemMapGrid::NormalizedTicks );
mRotatedAnnotationsLengthModeComboBox->addItem( tr( "Orthogonal" ), QgsLayoutItemMapGrid::OrthogonalTicks );
mRotatedAnnotationsLengthModeComboBox->addItem( tr( "Fixed length" ), QgsLayoutItemMapGrid::NormalizedTicks );
mRotatedAnnotationsLengthModeComboBox->addItem( tr( "Fixed Length" ), QgsLayoutItemMapGrid::NormalizedTicks );

mGridFrameMarginSpinBox->setShowClearButton( true );
mGridFrameMarginSpinBox->setClearValue( 0 );
Expand Down Expand Up @@ -133,16 +133,6 @@ QgsLayoutMapGridWidget::QgsLayoutMapGridWidget( QgsLayoutItemMapGrid *mapGrid, Q
insertFrameDisplayEntries( mFrameDivisionsTopComboBox );
insertFrameDisplayEntries( mFrameDivisionsBottomComboBox );

mAnnotationFormatComboBox->addItem( tr( "Decimal" ), QgsLayoutItemMapGrid::Decimal );
mAnnotationFormatComboBox->addItem( tr( "Decimal with Suffix" ), QgsLayoutItemMapGrid::DecimalWithSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute" ), QgsLayoutItemMapGrid::DegreeMinuteNoSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute with Suffix" ), QgsLayoutItemMapGrid::DegreeMinute );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute Aligned" ), QgsLayoutItemMapGrid::DegreeMinutePadded );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute, Second" ), QgsLayoutItemMapGrid::DegreeMinuteSecondNoSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute, Second with Suffix" ), QgsLayoutItemMapGrid::DegreeMinuteSecond );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute, Second Aligned" ), QgsLayoutItemMapGrid::DegreeMinuteSecondPadded );
mAnnotationFormatComboBox->addItem( tr( "Custom" ), QgsLayoutItemMapGrid::CustomFormat );

insertAnnotationDisplayEntries( mAnnotationDisplayLeftComboBox );
insertAnnotationDisplayEntries( mAnnotationDisplayRightComboBox );
insertAnnotationDisplayEntries( mAnnotationDisplayTopComboBox );
Expand Down Expand Up @@ -201,6 +191,9 @@ QgsLayoutMapGridWidget::QgsLayoutMapGridWidget( QgsLayoutItemMapGrid *mapGrid, Q
registerDataDefinedButton( mFrameDivisionsTopDDBtn, QgsLayoutObject::MapGridFrameDivisionsTop );
registerDataDefinedButton( mFrameDivisionsBottomDDBtn, QgsLayoutObject::MapGridFrameDivisionsBottom );

// call to initially populate mAnnotationFormatComboBox
onCrsChanged();

updateGuiElements();

blockAllSignals( false );
Expand All @@ -220,6 +213,8 @@ QgsLayoutMapGridWidget::QgsLayoutMapGridWidget( QgsLayoutItemMapGrid *mapGrid, Q
}
mAnnotationFontButton->setLayer( coverageLayer() );
mAnnotationFontButton->registerExpressionContextGenerator( mMapGrid );

connect( mMapGrid, &QgsLayoutItemMapGrid::crsChanged, this, &QgsLayoutMapGridWidget::onCrsChanged );
}

void QgsLayoutMapGridWidget::populateDataDefinedButtons()
Expand Down Expand Up @@ -1079,6 +1074,55 @@ void QgsLayoutMapGridWidget::annotationTextFormatChanged()
mMap->update();
}

void QgsLayoutMapGridWidget::onCrsChanged()
{
mBlockAnnotationFormatUpdates++;
const QgsLayoutItemMapGrid::AnnotationFormat prevFormat = static_cast< QgsLayoutItemMapGrid::AnnotationFormat >( mAnnotationFormatComboBox->currentData().toInt() );

mAnnotationFormatComboBox->clear();
mAnnotationFormatComboBox->addItem( tr( "Decimal" ), QgsLayoutItemMapGrid::Decimal );
mAnnotationFormatComboBox->addItem( tr( "Decimal with Suffix" ), QgsLayoutItemMapGrid::DecimalWithSuffix );

// only show degree based options for geographic CRSes
const QgsCoordinateReferenceSystem crs = mMapGrid->crs().isValid() ? mMapGrid->crs() : mMap->crs();
switch ( crs.mapUnits() )
{
case QgsUnitTypes::DistanceMeters:
case QgsUnitTypes::DistanceKilometers:
case QgsUnitTypes::DistanceFeet:
case QgsUnitTypes::DistanceNauticalMiles:
case QgsUnitTypes::DistanceYards:
case QgsUnitTypes::DistanceMiles:
case QgsUnitTypes::DistanceCentimeters:
case QgsUnitTypes::DistanceMillimeters:
break;

case QgsUnitTypes::DistanceDegrees:
case QgsUnitTypes::DistanceUnknownUnit:
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute" ), QgsLayoutItemMapGrid::DegreeMinuteNoSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute with Suffix" ), QgsLayoutItemMapGrid::DegreeMinute );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute Aligned" ), QgsLayoutItemMapGrid::DegreeMinutePadded );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute, Second" ), QgsLayoutItemMapGrid::DegreeMinuteSecondNoSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute, Second with Suffix" ), QgsLayoutItemMapGrid::DegreeMinuteSecond );
mAnnotationFormatComboBox->addItem( tr( "Degree, Minute, Second Aligned" ), QgsLayoutItemMapGrid::DegreeMinuteSecondPadded );
break;
}
mAnnotationFormatComboBox->addItem( tr( "Custom" ), QgsLayoutItemMapGrid::CustomFormat );

const int prevIndex = mAnnotationFormatComboBox->findData( prevFormat );
if ( prevIndex >= 0 )
mAnnotationFormatComboBox->setCurrentIndex( prevIndex );
else
mAnnotationFormatComboBox->setCurrentIndex( 0 );
mBlockAnnotationFormatUpdates--;

const QgsLayoutItemMapGrid::AnnotationFormat newFormat = static_cast< QgsLayoutItemMapGrid::AnnotationFormat >( mAnnotationFormatComboBox->currentData().toInt() );
if ( newFormat != prevFormat )
{
mAnnotationFormatComboBox_currentIndexChanged( mAnnotationFormatComboBox->currentIndex() );
}
}

void QgsLayoutMapGridWidget::mGridBlendComboBox_currentIndexChanged( int index )
{
Q_UNUSED( index )
Expand Down Expand Up @@ -1335,6 +1379,8 @@ void QgsLayoutMapGridWidget::mAnnotationFormatComboBox_currentIndexChanged( int
{
return;
}
if ( mBlockAnnotationFormatUpdates )
return;

mMap->beginCommand( tr( "Change Annotation Format" ) );

Expand Down
2 changes: 2 additions & 0 deletions src/gui/layout/qgslayoutmapgridwidget.h
Expand Up @@ -124,10 +124,12 @@ class GUI_EXPORT QgsLayoutMapGridWidget: public QgsLayoutItemBaseWidget, private
void minIntervalChanged( double interval );
void maxIntervalChanged( double interval );
void annotationTextFormatChanged();
void onCrsChanged();

private:
QPointer< QgsLayoutItemMap > mMap;
QPointer< QgsLayoutItemMapGrid > mMapGrid;
int mBlockAnnotationFormatUpdates = 0;

//! Blocks / unblocks the signals of all GUI elements
void blockAllSignals( bool b );
Expand Down
38 changes: 38 additions & 0 deletions tests/src/python/test_qgslayoutmap.py
Expand Up @@ -822,6 +822,44 @@ def testMainAnnotationLayer(self):
TestQgsLayoutMap.report += checker.report()
self.assertTrue(result, message)

def testCrsChanged(self):
"""
Test that the CRS changed signal is emitted in the right circumstances
"""
p = QgsProject()
layout = QgsLayout(p)
p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
map = QgsLayoutItemMap(layout)

spy = QSignalSpy(map.crsChanged)
# map has no explicit crs set, so follows project crs => signal should be emitted
# when project crs is changed
p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
self.assertEqual(len(spy), 1)
p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
self.assertEqual(len(spy), 2)
# set explicit crs on map item
map.setCrs(QgsCoordinateReferenceSystem('EPSG:28356'))
self.assertEqual(len(spy), 3)
map.setCrs(QgsCoordinateReferenceSystem('EPSG:28356'))
self.assertEqual(len(spy), 3)
map.setCrs(QgsCoordinateReferenceSystem('EPSG:28355'))
self.assertEqual(len(spy), 4)
# should not care about project crs changes anymore..
p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
self.assertEqual(len(spy), 4)
# set back to project crs
map.setCrs(QgsCoordinateReferenceSystem())
self.assertEqual(len(spy), 5)

map.setCrs(QgsCoordinateReferenceSystem('EPSG:28355'))
self.assertEqual(len(spy), 6)
# data defined crs
map.dataDefinedProperties().setProperty(QgsLayoutObject.MapCrs, QgsProperty.fromValue('EPSG:4283'))
self.assertEqual(len(spy), 6)
map.refresh()
self.assertEqual(len(spy), 7)


if __name__ == '__main__':
unittest.main()
52 changes: 52 additions & 0 deletions tests/src/python/test_qgslayoutmapgrid.py
Expand Up @@ -14,6 +14,7 @@

from qgis.PyQt.QtCore import QRectF, QDir
from qgis.PyQt.QtGui import QPainter, QColor
from qgis.PyQt.QtTest import QSignalSpy

from qgis.core import (QgsLayoutItemMap,
QgsLayoutItemMapGrid,
Expand Down Expand Up @@ -852,6 +853,57 @@ def testDynamicInterval(self):
self.report += checker.report()
self.assertTrue(myTestResult, myMessage)

def testCrsChanged(self):
"""
Test that the CRS changed signal is emitted in the right circumstances
"""
p = QgsProject()
layout = QgsLayout(p)
p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
map = QgsLayoutItemMap(layout)

grid = map.grid()

spy = QSignalSpy(grid.crsChanged)
# map grid and map have no explicit crs set, so follows project crs => signal should be emitted
# when project crs is changed
p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
self.assertEqual(len(spy), 1)
p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
self.assertEqual(len(spy), 2)
# set explicit crs on map item
map.setCrs(QgsCoordinateReferenceSystem('EPSG:28356'))
self.assertEqual(len(spy), 3)
map.setCrs(QgsCoordinateReferenceSystem('EPSG:28356'))
self.assertEqual(len(spy), 3)
map.setCrs(QgsCoordinateReferenceSystem('EPSG:28355'))
self.assertEqual(len(spy), 4)
# should not care about project crs changes anymore..
p.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
self.assertEqual(len(spy), 4)
# set back to project crs
map.setCrs(QgsCoordinateReferenceSystem())
self.assertEqual(len(spy), 5)

map.setCrs(QgsCoordinateReferenceSystem('EPSG:28355'))
self.assertEqual(len(spy), 6)
# data defined crs
map.dataDefinedProperties().setProperty(QgsLayoutObject.MapCrs, QgsProperty.fromValue('EPSG:4283'))
self.assertEqual(len(spy), 6)
map.refresh()
self.assertEqual(len(spy), 7)

# explicit crs for map grid
grid.setCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
self.assertEqual(len(spy), 8)
grid.setCrs(QgsCoordinateReferenceSystem('EPSG:3857'))
self.assertEqual(len(spy), 8)
map.dataDefinedProperties().setProperty(QgsLayoutObject.MapCrs, QgsProperty.fromValue('EPSG:3111'))
map.refresh()
self.assertEqual(len(spy), 8)
grid.setCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
self.assertEqual(len(spy), 9)


if __name__ == '__main__':
unittest.main()

0 comments on commit 6a86642

Please sign in to comment.