Skip to content
Permalink
Browse files

[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)!
  • Loading branch information
nyalldawson committed Sep 8, 2015
1 parent c3a1415 commit e8c3afa3984cee32b98b52ba65bcf5ed630ae72d
@@ -182,9 +182,10 @@ class QgsComposerMapGrid : QgsComposerMapItem
DegreeMinuteSecond, /*!< degree/minutes/seconds, use NSEW suffix */
DecimalWithSuffix, /*!< decimal degrees, use NSEW suffix */
DegreeMinuteNoSuffix, /*!< degree/minutes, use - for S/W coordinates */
DegreeMinutePadded, /*!< degree/minutes, with minutes using leading zeros were required */
DegreeMinutePadded, /*!< degree/minutes, with minutes using leading zeros where required */
DegreeMinuteSecondNoSuffix, /*!< degree/minutes/seconds, use - for S/W coordinates */
DegreeMinuteSecondPadded /*!< degree/minutes/seconds, with minutes using leading zeros were required */
DegreeMinuteSecondPadded, /*!< degree/minutes/seconds, with minutes using leading zeros where required */
CustomFormat /*!< custom expression-based format */
};

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

/** Sets the expression used for drawing grid annotations. This is only used when annotationFormat()
* is QgsComposerMapGrid::CustomFormat.
* @param expression expression for evaluating custom grid annotations
* @see annotationExpression
* @note added in QGIS 2.12
*/
void setAnnotationExpression( const QString& expression );

/** Returns the expression used for drawing grid annotations. This is only used when annotationFormat()
* is QgsComposerMapGrid::CustomFormat.
* @returns expression for evaluating custom grid annotations
* @see setAnnotationExpression
* @note added in QGIS 2.12
*/
QString annotationExpression() const;

//
// GRID FRAME
//
@@ -735,4 +752,6 @@ class QgsComposerMapGrid : QgsComposerMapItem
*/
QColor frameFillColor2() const;

virtual QgsExpressionContext* createExpressionContext() const;

};
@@ -74,14 +74,15 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap )
insertFrameDisplayEntries( mFrameDivisionsTopComboBox );
insertFrameDisplayEntries( mFrameDivisionsBottomComboBox );

mAnnotationFormatComboBox->insertItem( 0, tr( "Decimal" ) );
mAnnotationFormatComboBox->insertItem( 1, tr( "Decimal with suffix" ) );
mAnnotationFormatComboBox->insertItem( 2, tr( "Degree, minute" ) );
mAnnotationFormatComboBox->insertItem( 3, tr( "Degree, minute with suffix" ) );
mAnnotationFormatComboBox->insertItem( 4, tr( "Degree, minute aligned" ) );
mAnnotationFormatComboBox->insertItem( 5, tr( "Degree, minute, second" ) );
mAnnotationFormatComboBox->insertItem( 6, tr( "Degree, minute, second with suffix" ) );
mAnnotationFormatComboBox->insertItem( 7, tr( "Degree, minute, second aligned" ) );
mAnnotationFormatComboBox->addItem( tr( "Decimal" ), QgsComposerMapGrid::Decimal );
mAnnotationFormatComboBox->addItem( tr( "Decimal with suffix" ), QgsComposerMapGrid::DecimalWithSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, minute" ), QgsComposerMapGrid::DegreeMinuteNoSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, minute with suffix" ), QgsComposerMapGrid::DegreeMinute );
mAnnotationFormatComboBox->addItem( tr( "Degree, minute aligned" ), QgsComposerMapGrid::DegreeMinutePadded );
mAnnotationFormatComboBox->addItem( tr( "Degree, minute, second" ), QgsComposerMapGrid::DegreeMinuteSecondNoSuffix );
mAnnotationFormatComboBox->addItem( tr( "Degree, minute, second with suffix" ), QgsComposerMapGrid::DegreeMinuteSecond );
mAnnotationFormatComboBox->addItem( tr( "Degree, minute, second aligned" ), QgsComposerMapGrid::DegreeMinuteSecondPadded );
mAnnotationFormatComboBox->addItem( tr( "Custom" ), QgsComposerMapGrid::CustomFormat );

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

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

//mAnnotationFormatComboBox
switch ( grid->annotationFormat() )
{
case QgsComposerMapGrid::Decimal:
mAnnotationFormatComboBox->setCurrentIndex( 0 );
break;
case QgsComposerMapGrid::DegreeMinute:
mAnnotationFormatComboBox->setCurrentIndex( 3 );
break;
case QgsComposerMapGrid::DegreeMinuteSecond:
mAnnotationFormatComboBox->setCurrentIndex( 6 );
break;
case QgsComposerMapGrid::DecimalWithSuffix:
mAnnotationFormatComboBox->setCurrentIndex( 1 );
break;
case QgsComposerMapGrid::DegreeMinuteNoSuffix:
mAnnotationFormatComboBox->setCurrentIndex( 2 );
break;
case QgsComposerMapGrid::DegreeMinutePadded:
mAnnotationFormatComboBox->setCurrentIndex( 4 );
break;
case QgsComposerMapGrid::DegreeMinuteSecondNoSuffix:
mAnnotationFormatComboBox->setCurrentIndex( 5 );
break;
case QgsComposerMapGrid::DegreeMinuteSecondPadded:
mAnnotationFormatComboBox->setCurrentIndex( 7 );
break;
}
mAnnotationFormatComboBox->setCurrentIndex( mAnnotationFormatComboBox->findData( grid->annotationFormat() ) );
mAnnotationFormatButton->setEnabled( grid->annotationFormat() == QgsComposerMapGrid::CustomFormat );
mDistanceToMapFrameSpinBox->setValue( grid->annotationFrameDistance() );
mCoordinatePrecisionSpinBox->setValue( grid->annotationPrecision() );

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

void QgsComposerMapWidget::on_mAnnotationFormatButton_clicked()
{
QgsComposerMapGrid* grid = currentGrid();
if ( !grid )
{
return;
}

QScopedPointer< QgsExpressionContext> expressionContext( grid->createExpressionContext() );

QgsExpressionBuilderDialog exprDlg( 0, grid->annotationExpression(), this, "generic", *expressionContext );
exprDlg.setWindowTitle( tr( "Expression based annotation" ) );

if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
mComposerMap->beginCommand( tr( "Annotation format changed" ) );
grid->setAnnotationExpression( expression );
mComposerMap->updateBoundingRect();
mComposerMap->update();
mComposerMap->endCommand();
}
}

void QgsComposerMapWidget::on_mAnnotationDisplayLeftComboBox_currentIndexChanged( const QString &text )
{
handleChangedAnnotationDisplay( QgsComposerMapGrid::Left, text );
@@ -2142,41 +2141,14 @@ void QgsComposerMapWidget::on_mAnnotationFormatComboBox_currentIndexChanged( int

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

switch ( index )
{
case 0:
grid->setAnnotationFormat( QgsComposerMapGrid::Decimal );
break;
case 3:
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinute );
break;
case 6:
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteSecond );
break;
case 1:
grid->setAnnotationFormat( QgsComposerMapGrid::DecimalWithSuffix );
break;
case 2:
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteNoSuffix );
break;
case 4:
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinutePadded );
break;
case 5:
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteSecondNoSuffix );
break;
case 7:
grid->setAnnotationFormat( QgsComposerMapGrid::DegreeMinuteSecondPadded );
break;
}
grid->setAnnotationFormat(( QgsComposerMapGrid::AnnotationFormat )mAnnotationFormatComboBox->itemData( index ).toInt() );
mAnnotationFormatButton->setEnabled( grid->annotationFormat() == QgsComposerMapGrid::CustomFormat );

mComposerMap->updateBoundingRect();
mComposerMap->update();
mComposerMap->endCommand();
}



void QgsComposerMapWidget::on_mCoordinatePrecisionSpinBox_valueChanged( int value )
{
QgsComposerMapGrid* grid = currentGrid();
@@ -106,6 +106,7 @@ class QgsComposerMapWidget: public QgsComposerItemBaseWidget, private Ui::QgsCom
void on_mFrameDivisionsBottomComboBox_currentIndexChanged( int index );

void on_mDrawAnnotationGroupBox_toggled( bool state );
void on_mAnnotationFormatButton_clicked();

//annotation display
void on_mAnnotationDisplayLeftComboBox_currentIndexChanged( const QString& text );
@@ -28,6 +28,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgslogger.h"
#include "qgsfontutils.h"
#include "qgsexpressioncontext.h"

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

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

if ( mShowGridAnnotation )
{
drawCoordinateAnnotations( p, horizontalLines, verticalLines );
drawCoordinateAnnotations( p, horizontalLines, verticalLines, context.expressionContext() );
}
}

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

void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QgsExpressionContext &expressionContext ) const
{
if ( !p )
{
@@ -1048,15 +1052,15 @@ void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QP
QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
for ( ; it != hLines.constEnd(); ++it )
{
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude );
currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, expressionContext );
drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Latitude );
drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Latitude );
}

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

QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord ) const
QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord, QgsExpressionContext &expressionContext ) const
{
//check if we are using degrees (ie, geographic crs)
bool geographic = false;
@@ -1432,6 +1436,17 @@ QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGr
return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
}
}
else if ( mGridAnnotationFormat == CustomFormat )
{
expressionContext.lastScope()->setVariable( "grid_number", value );
expressionContext.lastScope()->setVariable( "grid_axis", coord == QgsComposerMapGrid::Longitude ? "x" : "y" );
if ( !mGridAnnotationExpression.data() )
{
mGridAnnotationExpression.reset( new QgsExpression( mGridAnnotationExpressionString ) );
mGridAnnotationExpression->prepare( &expressionContext );
}
return mGridAnnotationExpression->evaluate( &expressionContext ).toString();
}

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

const QgsMapSettings& ms = mComposerMap->composition()->mapSettings();

QScopedPointer< QgsExpressionContext> expressionContext( createExpressionContext() );

QStringList coordStrings;
if ( mCRS.isValid() && mCRS != ms.destinationCrs() )
{
@@ -2030,12 +2048,12 @@ double QgsComposerMapGrid::maxExtension() const
QList< QPair< double, QPolygonF > >::const_iterator it = xGridLines.constBegin();
for ( ; it != xGridLines.constEnd(); ++it )
{
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, *expressionContext ) );
}
it = yGridLines.constBegin();
for ( ; it != yGridLines.constEnd(); ++it )
{
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude, *expressionContext ) );
}
}
else
@@ -2052,13 +2070,13 @@ double QgsComposerMapGrid::maxExtension() const
QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
for ( ; it != xLines.constEnd(); ++it )
{
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude, *expressionContext ) );
}

it = yLines.constBegin();
for ( ; it != yLines.constEnd(); ++it )
{
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude, *expressionContext ) );
}
}

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

QgsExpressionContext* QgsComposerMapGrid::createExpressionContext() const
{
QgsExpressionContext* context = QgsComposerObject::createExpressionContext();
context->appendScope( new QgsExpressionContextScope( tr( "Grid" ) ) );
context->lastScope()->setVariable( "grid_number", 0 );
context->lastScope()->setVariable( "grid_axis", "x" );
context->setHighlightedVariables( QStringList() << "grid_number" << "grid_axis" );
return context;
}

bool QgsComposerMapGrid::testFrameSideFlag( QgsComposerMapGrid::FrameSideFlag flag ) const
{
return mGridFrameSides.testFlag( flag );

0 comments on commit e8c3afa

Please sign in to comment.
You can’t perform that action at this time.