Skip to content

Commit

Permalink
[FEATURE][composer] Custom format for grid annotations (fix #9292)
Browse files Browse the repository at this point in the history
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 e8c3afa
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 107 deletions.
23 changes: 21 additions & 2 deletions python/core/composer/qgscomposermapgrid.sip
Expand Up @@ -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
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -735,4 +752,6 @@ class QgsComposerMapGrid : QgsComposerMapItem
*/
QColor frameFillColor2() const;

virtual QgsExpressionContext* createExpressionContext() const;

};
102 changes: 37 additions & 65 deletions src/app/composer/qgscomposermapwidget.cpp
Expand Up @@ -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 );
Expand Down Expand Up @@ -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() );

Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/app/composer/qgscomposermapwidget.h
Expand Up @@ -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 );
Expand Down
46 changes: 37 additions & 9 deletions src/core/composer/qgscomposermapgrid.cpp
Expand Up @@ -28,6 +28,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgslogger.h"
#include "qgsfontutils.h"
#include "qgsexpressioncontext.h"

#include <QPainter>
#include <QPen>
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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() );
Expand Down Expand Up @@ -689,7 +693,7 @@ void QgsComposerMapGrid::draw( QPainter* p )

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

Expand Down Expand Up @@ -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 )
{
Expand All @@ -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 );
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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() )
{
Expand All @@ -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
Expand All @@ -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 ) );
}
}

Expand Down Expand Up @@ -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 );
Expand Down

0 comments on commit e8c3afa

Please sign in to comment.