Skip to content

Commit e8c3afa

Browse files
committed
[FEATURE][composer] Custom format for grid annotations (fix #9292)
Allows composer map grid annotations in custom formats which are evaluated using QgsExpressions. Made possible through the use of Expression Contexts(tm)!
1 parent c3a1415 commit e8c3afa

File tree

8 files changed

+168
-107
lines changed

8 files changed

+168
-107
lines changed

python/core/composer/qgscomposermapgrid.sip

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,10 @@ class QgsComposerMapGrid : QgsComposerMapItem
182182
DegreeMinuteSecond, /*!< degree/minutes/seconds, use NSEW suffix */
183183
DecimalWithSuffix, /*!< decimal degrees, use NSEW suffix */
184184
DegreeMinuteNoSuffix, /*!< degree/minutes, use - for S/W coordinates */
185-
DegreeMinutePadded, /*!< degree/minutes, with minutes using leading zeros were required */
185+
DegreeMinutePadded, /*!< degree/minutes, with minutes using leading zeros where required */
186186
DegreeMinuteSecondNoSuffix, /*!< degree/minutes/seconds, use - for S/W coordinates */
187-
DegreeMinuteSecondPadded /*!< degree/minutes/seconds, with minutes using leading zeros were required */
187+
DegreeMinuteSecondPadded, /*!< degree/minutes/seconds, with minutes using leading zeros where required */
188+
CustomFormat /*!< custom expression-based format */
188189
};
189190

190191
/** Border sides for annotations
@@ -586,6 +587,22 @@ class QgsComposerMapGrid : QgsComposerMapItem
586587
*/
587588
AnnotationFormat annotationFormat() const;
588589

590+
/** Sets the expression used for drawing grid annotations. This is only used when annotationFormat()
591+
* is QgsComposerMapGrid::CustomFormat.
592+
* @param expression expression for evaluating custom grid annotations
593+
* @see annotationExpression
594+
* @note added in QGIS 2.12
595+
*/
596+
void setAnnotationExpression( const QString& expression );
597+
598+
/** Returns the expression used for drawing grid annotations. This is only used when annotationFormat()
599+
* is QgsComposerMapGrid::CustomFormat.
600+
* @returns expression for evaluating custom grid annotations
601+
* @see setAnnotationExpression
602+
* @note added in QGIS 2.12
603+
*/
604+
QString annotationExpression() const;
605+
589606
//
590607
// GRID FRAME
591608
//
@@ -735,4 +752,6 @@ class QgsComposerMapGrid : QgsComposerMapItem
735752
*/
736753
QColor frameFillColor2() const;
737754

755+
virtual QgsExpressionContext* createExpressionContext() const;
756+
738757
};

src/app/composer/qgscomposermapwidget.cpp

Lines changed: 37 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,15 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap )
7474
insertFrameDisplayEntries( mFrameDivisionsTopComboBox );
7575
insertFrameDisplayEntries( mFrameDivisionsBottomComboBox );
7676

77-
mAnnotationFormatComboBox->insertItem( 0, tr( "Decimal" ) );
78-
mAnnotationFormatComboBox->insertItem( 1, tr( "Decimal with suffix" ) );
79-
mAnnotationFormatComboBox->insertItem( 2, tr( "Degree, minute" ) );
80-
mAnnotationFormatComboBox->insertItem( 3, tr( "Degree, minute with suffix" ) );
81-
mAnnotationFormatComboBox->insertItem( 4, tr( "Degree, minute aligned" ) );
82-
mAnnotationFormatComboBox->insertItem( 5, tr( "Degree, minute, second" ) );
83-
mAnnotationFormatComboBox->insertItem( 6, tr( "Degree, minute, second with suffix" ) );
84-
mAnnotationFormatComboBox->insertItem( 7, tr( "Degree, minute, second aligned" ) );
77+
mAnnotationFormatComboBox->addItem( tr( "Decimal" ), QgsComposerMapGrid::Decimal );
78+
mAnnotationFormatComboBox->addItem( tr( "Decimal with suffix" ), QgsComposerMapGrid::DecimalWithSuffix );
79+
mAnnotationFormatComboBox->addItem( tr( "Degree, minute" ), QgsComposerMapGrid::DegreeMinuteNoSuffix );
80+
mAnnotationFormatComboBox->addItem( tr( "Degree, minute with suffix" ), QgsComposerMapGrid::DegreeMinute );
81+
mAnnotationFormatComboBox->addItem( tr( "Degree, minute aligned" ), QgsComposerMapGrid::DegreeMinutePadded );
82+
mAnnotationFormatComboBox->addItem( tr( "Degree, minute, second" ), QgsComposerMapGrid::DegreeMinuteSecondNoSuffix );
83+
mAnnotationFormatComboBox->addItem( tr( "Degree, minute, second with suffix" ), QgsComposerMapGrid::DegreeMinuteSecond );
84+
mAnnotationFormatComboBox->addItem( tr( "Degree, minute, second aligned" ), QgsComposerMapGrid::DegreeMinuteSecondPadded );
85+
mAnnotationFormatComboBox->addItem( tr( "Custom" ), QgsComposerMapGrid::CustomFormat );
8586

8687
mAnnotationFontColorButton->setColorDialogTitle( tr( "Select font color" ) );
8788
mAnnotationFontColorButton->setAllowAlpha( true );
@@ -1494,34 +1495,8 @@ void QgsComposerMapWidget::setGridItems( const QgsComposerMapGrid* grid )
14941495

14951496
mAnnotationFontColorButton->setColor( grid->annotationFontColor() );
14961497

1497-
//mAnnotationFormatComboBox
1498-
switch ( grid->annotationFormat() )
1499-
{
1500-
case QgsComposerMapGrid::Decimal:
1501-
mAnnotationFormatComboBox->setCurrentIndex( 0 );
1502-
break;
1503-
case QgsComposerMapGrid::DegreeMinute:
1504-
mAnnotationFormatComboBox->setCurrentIndex( 3 );
1505-
break;
1506-
case QgsComposerMapGrid::DegreeMinuteSecond:
1507-
mAnnotationFormatComboBox->setCurrentIndex( 6 );
1508-
break;
1509-
case QgsComposerMapGrid::DecimalWithSuffix:
1510-
mAnnotationFormatComboBox->setCurrentIndex( 1 );
1511-
break;
1512-
case QgsComposerMapGrid::DegreeMinuteNoSuffix:
1513-
mAnnotationFormatComboBox->setCurrentIndex( 2 );
1514-
break;
1515-
case QgsComposerMapGrid::DegreeMinutePadded:
1516-
mAnnotationFormatComboBox->setCurrentIndex( 4 );
1517-
break;
1518-
case QgsComposerMapGrid::DegreeMinuteSecondNoSuffix:
1519-
mAnnotationFormatComboBox->setCurrentIndex( 5 );
1520-
break;
1521-
case QgsComposerMapGrid::DegreeMinuteSecondPadded:
1522-
mAnnotationFormatComboBox->setCurrentIndex( 7 );
1523-
break;
1524-
}
1498+
mAnnotationFormatComboBox->setCurrentIndex( mAnnotationFormatComboBox->findData( grid->annotationFormat() ) );
1499+
mAnnotationFormatButton->setEnabled( grid->annotationFormat() == QgsComposerMapGrid::CustomFormat );
15251500
mDistanceToMapFrameSpinBox->setValue( grid->annotationFrameDistance() );
15261501
mCoordinatePrecisionSpinBox->setValue( grid->annotationPrecision() );
15271502

@@ -2023,6 +1998,30 @@ void QgsComposerMapWidget::on_mDrawAnnotationGroupBox_toggled( bool state )
20231998
mComposerMap->endCommand();
20241999
}
20252000

2001+
void QgsComposerMapWidget::on_mAnnotationFormatButton_clicked()
2002+
{
2003+
QgsComposerMapGrid* grid = currentGrid();
2004+
if ( !grid )
2005+
{
2006+
return;
2007+
}
2008+
2009+
QScopedPointer< QgsExpressionContext> expressionContext( grid->createExpressionContext() );
2010+
2011+
QgsExpressionBuilderDialog exprDlg( 0, grid->annotationExpression(), this, "generic", *expressionContext );
2012+
exprDlg.setWindowTitle( tr( "Expression based annotation" ) );
2013+
2014+
if ( exprDlg.exec() == QDialog::Accepted )
2015+
{
2016+
QString expression = exprDlg.expressionText();
2017+
mComposerMap->beginCommand( tr( "Annotation format changed" ) );
2018+
grid->setAnnotationExpression( expression );
2019+
mComposerMap->updateBoundingRect();
2020+
mComposerMap->update();
2021+
mComposerMap->endCommand();
2022+
}
2023+
}
2024+
20262025
void QgsComposerMapWidget::on_mAnnotationDisplayLeftComboBox_currentIndexChanged( const QString &text )
20272026
{
20282027
handleChangedAnnotationDisplay( QgsComposerMapGrid::Left, text );
@@ -2142,41 +2141,14 @@ void QgsComposerMapWidget::on_mAnnotationFormatComboBox_currentIndexChanged( int
21422141

21432142
mComposerMap->beginCommand( tr( "Annotation format changed" ) );
21442143

2145-
switch ( index )
2146-
{
2147-
case 0:
2148-
grid->setAnnotationFormat( QgsComposerMapGrid::Decimal );
2149-
break;
2150-
case 3:
2151-
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinute );
2152-
break;
2153-
case 6:
2154-
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteSecond );
2155-
break;
2156-
case 1:
2157-
grid->setAnnotationFormat( QgsComposerMapGrid::DecimalWithSuffix );
2158-
break;
2159-
case 2:
2160-
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteNoSuffix );
2161-
break;
2162-
case 4:
2163-
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinutePadded );
2164-
break;
2165-
case 5:
2166-
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteSecondNoSuffix );
2167-
break;
2168-
case 7:
2169-
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteSecondPadded );
2170-
break;
2171-
}
2144+
grid->setAnnotationFormat(( QgsComposerMapGrid::AnnotationFormat )mAnnotationFormatComboBox->itemData( index ).toInt() );
2145+
mAnnotationFormatButton->setEnabled( grid->annotationFormat() == QgsComposerMapGrid::CustomFormat );
21722146

21732147
mComposerMap->updateBoundingRect();
21742148
mComposerMap->update();
21752149
mComposerMap->endCommand();
21762150
}
21772151

2178-
2179-
21802152
void QgsComposerMapWidget::on_mCoordinatePrecisionSpinBox_valueChanged( int value )
21812153
{
21822154
QgsComposerMapGrid* grid = currentGrid();

src/app/composer/qgscomposermapwidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class QgsComposerMapWidget: public QgsComposerItemBaseWidget, private Ui::QgsCom
106106
void on_mFrameDivisionsBottomComboBox_currentIndexChanged( int index );
107107

108108
void on_mDrawAnnotationGroupBox_toggled( bool state );
109+
void on_mAnnotationFormatButton_clicked();
109110

110111
//annotation display
111112
void on_mAnnotationDisplayLeftComboBox_currentIndexChanged( const QString& text );

src/core/composer/qgscomposermapgrid.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "qgscoordinatereferencesystem.h"
2929
#include "qgslogger.h"
3030
#include "qgsfontutils.h"
31+
#include "qgsexpressioncontext.h"
3132

3233
#include <QPainter>
3334
#include <QPen>
@@ -296,6 +297,7 @@ bool QgsComposerMapGrid::writeXML( QDomElement& elem, QDomDocument& doc ) const
296297

297298
mapGridElem.setAttribute( "annotationFormat", mGridAnnotationFormat );
298299
mapGridElem.setAttribute( "showAnnotation", mShowGridAnnotation );
300+
mapGridElem.setAttribute( "annotationExpression", mGridAnnotationExpressionString );
299301
mapGridElem.setAttribute( "leftAnnotationDisplay", mLeftGridAnnotationDisplay );
300302
mapGridElem.setAttribute( "rightAnnotationDisplay", mRightGridAnnotationDisplay );
301303
mapGridElem.setAttribute( "topAnnotationDisplay", mTopGridAnnotationDisplay );
@@ -395,6 +397,8 @@ bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocumen
395397
//annotation
396398
mShowGridAnnotation = ( itemElem.attribute( "showAnnotation", "0" ) != "0" );
397399
mGridAnnotationFormat = QgsComposerMapGrid::AnnotationFormat( itemElem.attribute( "annotationFormat", "0" ).toInt() );
400+
mGridAnnotationExpressionString = itemElem.attribute( "annotationExpression" );
401+
mGridAnnotationExpression.reset();
398402
mLeftGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "leftAnnotationPosition", "0" ).toInt() );
399403
mRightGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "rightAnnotationPosition", "0" ).toInt() );
400404
mTopGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "topAnnotationPosition", "0" ).toInt() );
@@ -689,7 +693,7 @@ void QgsComposerMapGrid::draw( QPainter* p )
689693

690694
if ( mShowGridAnnotation )
691695
{
692-
drawCoordinateAnnotations( p, horizontalLines, verticalLines );
696+
drawCoordinateAnnotations( p, horizontalLines, verticalLines, context.expressionContext() );
693697
}
694698
}
695699

@@ -1037,7 +1041,7 @@ void QgsComposerMapGrid::drawGridFrameLineBorder( QPainter* p, QgsComposerMapGri
10371041
}
10381042
}
10391043

1040-
void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
1044+
void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QgsExpressionContext &expressionContext ) const
10411045
{
10421046
if ( !p )
10431047
{
@@ -1048,15 +1052,15 @@ void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QP
10481052
QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
10491053
for ( ; it != hLines.constEnd(); ++it )
10501054
{
1051-
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude );
1055+
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, expressionContext );
10521056
drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Latitude );
10531057
drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Latitude );
10541058
}
10551059

10561060
it = vLines.constBegin();
10571061
for ( ; it != vLines.constEnd(); ++it )
10581062
{
1059-
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Longitude );
1063+
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Longitude, expressionContext );
10601064
drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Longitude );
10611065
drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Longitude );
10621066
}
@@ -1369,7 +1373,7 @@ void QgsComposerMapGrid::drawAnnotation( QPainter* p, const QPointF& pos, int ro
13691373
p->restore();
13701374
}
13711375

1372-
QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord ) const
1376+
QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord, QgsExpressionContext &expressionContext ) const
13731377
{
13741378
//check if we are using degrees (ie, geographic crs)
13751379
bool geographic = false;
@@ -1432,6 +1436,17 @@ QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGr
14321436
return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
14331437
}
14341438
}
1439+
else if ( mGridAnnotationFormat == CustomFormat )
1440+
{
1441+
expressionContext.lastScope()->setVariable( "grid_number", value );
1442+
expressionContext.lastScope()->setVariable( "grid_axis", coord == QgsComposerMapGrid::Longitude ? "x" : "y" );
1443+
if ( !mGridAnnotationExpression.data() )
1444+
{
1445+
mGridAnnotationExpression.reset( new QgsExpression( mGridAnnotationExpressionString ) );
1446+
mGridAnnotationExpression->prepare( &expressionContext );
1447+
}
1448+
return mGridAnnotationExpression->evaluate( &expressionContext ).toString();
1449+
}
14351450

14361451
QgsPoint p;
14371452
p.setX( coord == QgsComposerMapGrid::Longitude ? value : 0 );
@@ -2008,6 +2023,9 @@ double QgsComposerMapGrid::maxExtension() const
20082023
}
20092024

20102025
const QgsMapSettings& ms = mComposerMap->composition()->mapSettings();
2026+
2027+
QScopedPointer< QgsExpressionContext> expressionContext( createExpressionContext() );
2028+
20112029
QStringList coordStrings;
20122030
if ( mCRS.isValid() && mCRS != ms.destinationCrs() )
20132031
{
@@ -2030,12 +2048,12 @@ double QgsComposerMapGrid::maxExtension() const
20302048
QList< QPair< double, QPolygonF > >::const_iterator it = xGridLines.constBegin();
20312049
for ( ; it != xGridLines.constEnd(); ++it )
20322050
{
2033-
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
2051+
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, *expressionContext ) );
20342052
}
20352053
it = yGridLines.constBegin();
20362054
for ( ; it != yGridLines.constEnd(); ++it )
20372055
{
2038-
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
2056+
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude, *expressionContext ) );
20392057
}
20402058
}
20412059
else
@@ -2052,13 +2070,13 @@ double QgsComposerMapGrid::maxExtension() const
20522070
QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
20532071
for ( ; it != xLines.constEnd(); ++it )
20542072
{
2055-
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
2073+
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, *expressionContext ) );
20562074
}
20572075

20582076
it = yLines.constBegin();
20592077
for ( ; it != yLines.constEnd(); ++it )
20602078
{
2061-
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
2079+
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude, *expressionContext ) );
20622080
}
20632081
}
20642082

@@ -2183,6 +2201,16 @@ QgsComposerMapGrid::FrameSideFlags QgsComposerMapGrid::frameSideFlags() const
21832201
return mGridFrameSides;
21842202
}
21852203

2204+
QgsExpressionContext* QgsComposerMapGrid::createExpressionContext() const
2205+
{
2206+
QgsExpressionContext* context = QgsComposerObject::createExpressionContext();
2207+
context->appendScope( new QgsExpressionContextScope( tr( "Grid" ) ) );
2208+
context->lastScope()->setVariable( "grid_number", 0 );
2209+
context->lastScope()->setVariable( "grid_axis", "x" );
2210+
context->setHighlightedVariables( QStringList() << "grid_number" << "grid_axis" );
2211+
return context;
2212+
}
2213+
21862214
bool QgsComposerMapGrid::testFrameSideFlag( QgsComposerMapGrid::FrameSideFlag flag ) const
21872215
{
21882216
return mGridFrameSides.testFlag( flag );

0 commit comments

Comments
 (0)