Start porting label item

This commit is contained in:
Nyall Dawson 2017-10-24 14:18:21 +10:00
parent 87d497eb2b
commit 83f177c1d2
16 changed files with 1495 additions and 1 deletions

View File

@ -189,6 +189,7 @@ Get font color
%End
public slots:
void refreshExpressionContext();

View File

@ -168,7 +168,6 @@
%Include layout/qgslayoutsize.sip
%Include layout/qgslayoutsnapper.sip
%Include layout/qgslayoutundocommand.sip
%Include layout/qgslayoutundostack.sip
%Include layout/qgslayoututils.sip
%Include metadata/qgslayermetadata.sip
%Include metadata/qgslayermetadatavalidator.sip
@ -408,6 +407,7 @@
%Include layout/qgslayoutguidecollection.sip
%Include layout/qgslayoutitem.sip
%Include layout/qgslayoutitemgroup.sip
%Include layout/qgslayoutitemlabel.sip
%Include layout/qgslayoutitemmap.sip
%Include layout/qgslayoutitemmapgrid.sip
%Include layout/qgslayoutitemmapitem.sip
@ -422,6 +422,7 @@
%Include layout/qgslayoutmodel.sip
%Include layout/qgslayoutpagecollection.sip
%Include layout/qgslayoutobject.sip
%Include layout/qgslayoutundostack.sip
%Include symbology/qgscptcityarchive.sip
%Include symbology/qgssvgcache.sip
%Include symbology/qgsstyle.sip

View File

@ -0,0 +1,224 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutitemlabel.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutItemLabel: QgsLayoutItem
{
%Docstring
A layout item subclass for text labels.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitemlabel.h"
%End
public:
enum Mode
{
ModeFont,
ModeHtml,
};
QgsLayoutItemLabel( QgsLayout *layout );
%Docstring
Constructor for QgsLayoutItemLabel, with the specified parent ``layout``.
%End
static QgsLayoutItemLabel *create( QgsLayout *layout ) /Factory/;
%Docstring
Returns a new label item for the specified ``layout``.
The caller takes responsibility for deleting the returned object.
:rtype: QgsLayoutItemLabel
%End
virtual int type() const;
virtual QString stringType() const;
virtual QString displayName() const;
void adjustSizeToText();
%Docstring
Resizes the item so that the label's text fits to the item. Keeps the top left point stationary.
%End
QString text();
%Docstring
Returns the label's preset text.
.. seealso:: currentText()
.. seealso:: setText()
:rtype: str
%End
void setText( const QString &text );
%Docstring
Sets the label's preset ``text``.
.. seealso:: text()
%End
QString currentText() const;
%Docstring
Returns the text as it appears on the label (with evaluated expressions
and other dynamic content).
.. seealso:: text()
:rtype: str
%End
Mode mode() const;
%Docstring
Returns the label's current mode.
.. seealso:: setMode()
:rtype: Mode
%End
void setMode( Mode mode );
%Docstring
Sets the label's current ``mode``, allowing the label
to switch between font based and HTML based rendering.
.. seealso:: mode()
%End
QFont font() const;
%Docstring
Returns the label's current font.
.. seealso:: setFont()
:rtype: QFont
%End
void setFont( const QFont &font );
%Docstring
Sets the label's current ``font``.
.. seealso:: font()
%End
Qt::AlignmentFlag vAlign() const;
%Docstring
Returns for the vertical alignment of the label.
.. seealso:: setVAlign()
.. seealso:: hAlign()
:rtype: Qt.AlignmentFlag
%End
Qt::AlignmentFlag hAlign() const;
%Docstring
Returns the horizontal alignment of the label.
.. seealso:: vAlign()
.. seealso:: setHAlign()
:rtype: Qt.AlignmentFlag
%End
void setHAlign( Qt::AlignmentFlag alignment );
%Docstring
Sets the horizontal ``alignment`` of the label.
.. seealso:: hAlign()
.. seealso:: setVAlign()
%End
void setVAlign( Qt::AlignmentFlag alignment );
%Docstring
Sets for the vertical ``alignment`` of the label.
.. seealso:: vAlign()
.. seealso:: setHAlign()
%End
double marginX() const;
%Docstring
Returns the horizontal margin between the edge of the frame and the label
contents, in layout units.
.. seealso:: setMargin()
.. seealso:: marginY()
:rtype: float
%End
double marginY() const;
%Docstring
Returns the vertical margin between the edge of the frame and the label
contents, in layout units.
.. seealso:: setMargin()
.. seealso:: marginX()
:rtype: float
%End
void setMargin( double margin );
%Docstring
Sets the ``margin`` between the edge of the frame and the label contents.
This method sets both the horizontal and vertical margins to the same
value. The margins can be individually controlled using the setMarginX()
and setMarginY() methods.
Margins are set using the current layout units.
.. seealso:: setMarginX()
.. seealso:: setMarginY()
%End
void setMarginX( double margin );
%Docstring
Sets the horizontal ``margin`` between the edge of the frame and the label
contents, in layout units.
.. seealso:: setMargin()
.. seealso:: setMarginY()
%End
void setMarginY( double margin );
%Docstring
Sets the vertical ``margin`` between the edge of the frame and the label
contents, in layout units.
.. seealso:: setMargin()
.. seealso:: setMarginX()
%End
void setFontColor( const QColor &color );
%Docstring
Sets the label font ``color``.
.. seealso:: fontColor()
%End
QColor fontColor() const;
%Docstring
Returns the label font color.
.. seealso:: setFontColor()
:rtype: QColor
%End
virtual QRectF boundingRect() const;
virtual void setFrameEnabled( const bool drawFrame );
virtual void setFrameStrokeWidth( const QgsLayoutMeasurement &strokeWidth );
public slots:
virtual void refresh();
protected:
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );
virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutitemlabel.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -104,6 +104,7 @@ class QgsLayoutItemRegistry : QObject
LayoutPage,
LayoutMap,
LayoutPicture,
LayoutLabel,
LayoutShape,
LayoutPolygon,
LayoutPolyline,

View File

@ -369,6 +369,7 @@ SET(QGIS_CORE_SRCS
layout/qgslayoutitem.cpp
layout/qgslayoutitemgroup.cpp
layout/qgslayoutitemgroupundocommand.cpp
layout/qgslayoutitemlabel.cpp
layout/qgslayoutitemmap.cpp
layout/qgslayoutitemmapgrid.cpp
layout/qgslayoutitemmapitem.cpp
@ -728,6 +729,7 @@ SET(QGIS_CORE_MOC_HDRS
layout/qgslayoutitem.h
layout/qgslayoutitemgroup.h
layout/qgslayoutitemgroupundocommand.h
layout/qgslayoutitemlabel.h
layout/qgslayoutitemmap.h
layout/qgslayoutitemmapgrid.h
layout/qgslayoutitemmapitem.h

View File

@ -170,6 +170,7 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
virtual void setFrameStrokeWidth( const double strokeWidth ) override;
public slots:
void refreshExpressionContext();

View File

@ -0,0 +1,603 @@
/***************************************************************************
qgslayoutitemlabel.cpp
-------------------
begin : October 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 "qgslayoutitemlabel.h"
#include "qgslayoutitemregistry.h"
#include "qgslayout.h"
#include "qgslayoututils.h"
#include "qgslayoutmodel.h"
#include "qgsexpression.h"
#include "qgsnetworkaccessmanager.h"
#include "qgscomposermodel.h"
#include "qgsvectorlayer.h"
#include "qgsproject.h"
#include "qgsdistancearea.h"
#include "qgsfontutils.h"
#include "qgsexpressioncontext.h"
#include "qgsmapsettings.h"
#include "qgscomposermap.h"
#include "qgssettings.h"
#include "qgswebview.h"
#include "qgswebframe.h"
#include "qgswebpage.h"
#include <QCoreApplication>
#include <QDate>
#include <QDomElement>
#include <QPainter>
#include <QTimer>
#include <QEventLoop>
QgsLayoutItemLabel::QgsLayoutItemLabel( QgsLayout *layout )
: QgsLayoutItem( layout )
{
mDistanceArea.reset( new QgsDistanceArea() );
mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
//get default composer font from settings
QgsSettings settings;
QString defaultFontString = settings.value( QStringLiteral( "Composer/defaultFont" ) ).toString();
if ( !defaultFontString.isEmpty() )
{
mFont.setFamily( defaultFontString );
}
//default to a 10 point font size
mFont.setPointSizeF( 10 );
//default to no background
setBackgroundEnabled( false );
//a label added while atlas preview is enabled needs to have the expression context set,
//otherwise fields in the label aren't correctly evaluated until atlas preview feature changes (#9457)
refreshExpressionContext();
if ( mLayout )
{
#if 0 //TODO
//connect to atlas feature changes
//to update the expression context
connect( &mLayout->atlasComposition(), &QgsAtlasComposition::featureChanged, this, &QgsLayoutItemLabel::refreshExpressionContext );
#endif
}
mWebPage.reset( new QgsWebPage( this ) );
mWebPage->setIdentifier( tr( "Layout label item" ) );
mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
//This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
QPalette palette = mWebPage->palette();
palette.setBrush( QPalette::Base, Qt::transparent );
mWebPage->setPalette( palette );
mWebPage->mainFrame()->setZoomFactor( 10.0 );
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
connect( mWebPage.get(), &QWebPage::loadFinished, this, &QgsLayoutItemLabel::loadingHtmlFinished );
}
QgsLayoutItemLabel *QgsLayoutItemLabel::create( QgsLayout *layout )
{
return new QgsLayoutItemLabel( layout );
}
int QgsLayoutItemLabel::type() const
{
return QgsLayoutItemRegistry::LayoutLabel;
}
QString QgsLayoutItemLabel::stringType() const
{
return QStringLiteral( "ItemLabel" );
}
void QgsLayoutItemLabel::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem * )
{
QPainter *painter = context.painter();
painter->save();
// painter is scaled to dots, so scale back to layout units
painter->scale( context.scaleFactor(), context.scaleFactor() );
double penWidth = hasFrame() ? ( pen().widthF() / 2.0 ) : 0;
double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
QRectF painterRect( xPenAdjust + mMarginX, yPenAdjust + mMarginY, rect().width() - 2 * xPenAdjust - 2 * mMarginX, rect().height() - 2 * yPenAdjust - 2 * mMarginY );
switch ( mMode )
{
case ModeHtml:
{
if ( mFirstRender )
{
contentChanged();
mFirstRender = false;
}
painter->scale( 1.0 / mHtmlUnitsToLayoutUnits / 10.0, 1.0 / mHtmlUnitsToLayoutUnits / 10.0 );
mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToLayoutUnits * 10.0, painterRect.height() * mHtmlUnitsToLayoutUnits * 10.0 ) );
mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
mWebPage->mainFrame()->render( painter );
break;
}
case ModeFont:
{
const QString textToDraw = currentText();
painter->setFont( mFont );
QgsLayoutUtils::drawText( painter, painterRect, textToDraw, mFont, mFontColor, mHAlignment, mVAlignment, Qt::TextWordWrap );
break;
}
}
painter->restore();
}
void QgsLayoutItemLabel::contentChanged()
{
switch ( mMode )
{
case ModeHtml:
{
const QString textToDraw = currentText();
//mHtmlLoaded tracks whether the QWebPage has completed loading
//its html contents, set it initially to false. The loadingHtmlFinished slot will
//set this to true after html is loaded.
mHtmlLoaded = false;
const QUrl baseUrl = QUrl::fromLocalFile( mLayout->project()->fileInfo().absoluteFilePath() );
mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
//For very basic html labels with no external assets, the html load will already be
//complete before we even get a chance to start the QEventLoop. Make sure we check
//this before starting the loop
if ( !mHtmlLoaded )
{
//Setup event loop and timeout for rendering html
QEventLoop loop;
//Connect timeout and webpage loadFinished signals to loop
connect( mWebPage.get(), &QWebPage::loadFinished, &loop, &QEventLoop::quit );
// Start a 20 second timeout in case html loading will never complete
QTimer timeoutTimer;
timeoutTimer.setSingleShot( true );
connect( &timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit );
timeoutTimer.start( 20000 );
// Pause until html is loaded
loop.exec( QEventLoop::ExcludeUserInputEvents );
}
break;
}
case ModeFont:
break;
}
}
void QgsLayoutItemLabel::loadingHtmlFinished( bool result )
{
Q_UNUSED( result );
mHtmlLoaded = true;
}
double QgsLayoutItemLabel::htmlUnitsToLayoutUnits()
{
if ( !mLayout )
{
return 1.0;
}
//TODO : fix this more precisely so that the label's default text size is the same with or without "display as html"
return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( mLayout->context().dpi() / 72.0, QgsUnitTypes::LayoutMillimeters ) ); //webkit seems to assume a standard dpi of 72
}
void QgsLayoutItemLabel::setText( const QString &text )
{
mText = text;
emit changed();
contentChanged();
if ( mLayout && id().isEmpty() && mMode != ModeHtml )
{
//notify the model that the display name has changed
mLayout->itemsModel()->updateItemDisplayName( this );
}
}
void QgsLayoutItemLabel::setMode( Mode mode )
{
if ( mode == mMode )
{
return;
}
mMode = mode;
contentChanged();
if ( mLayout && id().isEmpty() )
{
//notify the model that the display name has changed
mLayout->itemsModel()->updateItemDisplayName( this );
}
}
void QgsLayoutItemLabel::refreshExpressionContext()
{
if ( !mLayout )
return;
QgsVectorLayer *layer = nullptr;
#if 0 //TODO
if ( mComposition->atlasComposition().enabled() )
{
layer = mComposition->atlasComposition().coverageLayer();
}
#endif
//setup distance area conversion
if ( layer )
{
mDistanceArea->setSourceCrs( layer->crs() );
}
else
{
#if 0 //TODO
//set to composition's reference map's crs
QgsLayoutItemMap *referenceMap = mComposition->referenceMap();
if ( referenceMap )
mDistanceArea->setSourceCrs( referenceMap->crs() );
#endif
}
mDistanceArea->setEllipsoid( mLayout->project()->ellipsoid() );
contentChanged();
update();
}
QString QgsLayoutItemLabel::currentText() const
{
QString displayText = mText;
replaceDateText( displayText );
QgsExpressionContext context = createExpressionContext();
return QgsExpression::replaceExpressionText( displayText, &context, mDistanceArea.get() );
}
void QgsLayoutItemLabel::replaceDateText( QString &text ) const
{
QString constant = QStringLiteral( "$CURRENT_DATE" );
int currentDatePos = text.indexOf( constant );
if ( currentDatePos != -1 )
{
//check if there is a bracket just after $CURRENT_DATE
QString formatText;
int openingBracketPos = text.indexOf( '(', currentDatePos );
int closingBracketPos = text.indexOf( ')', openingBracketPos + 1 );
if ( openingBracketPos != -1 &&
closingBracketPos != -1 &&
( closingBracketPos - openingBracketPos ) > 1 &&
openingBracketPos == currentDatePos + constant.size() )
{
formatText = text.mid( openingBracketPos + 1, closingBracketPos - openingBracketPos - 1 );
text.replace( currentDatePos, closingBracketPos - currentDatePos + 1, QDate::currentDate().toString( formatText ) );
}
else //no bracket
{
text.replace( QLatin1String( "$CURRENT_DATE" ), QDate::currentDate().toString() );
}
}
}
void QgsLayoutItemLabel::setFont( const QFont &f )
{
mFont = f;
}
void QgsLayoutItemLabel::setMargin( const double m )
{
mMarginX = m;
mMarginY = m;
prepareGeometryChange();
}
void QgsLayoutItemLabel::setMarginX( const double margin )
{
mMarginX = margin;
prepareGeometryChange();
}
void QgsLayoutItemLabel::setMarginY( const double margin )
{
mMarginY = margin;
prepareGeometryChange();
}
void QgsLayoutItemLabel::adjustSizeToText()
{
double textWidth = QgsLayoutUtils::textWidthMM( mFont, currentText() );
double fontHeight = QgsLayoutUtils::fontHeightMM( mFont );
double penWidth = hasFrame() ? ( pen().widthF() / 2.0 ) : 0;
double width = textWidth + 2 * mMarginX + 2 * penWidth + 1;
double height = fontHeight + 2 * mMarginY + 2 * penWidth;
//keep alignment point constant
double xShift = 0;
double yShift = 0;
QSizeF newSize = mLayout->convertToLayoutUnits( QgsLayoutSize( width, height, QgsUnitTypes::LayoutMillimeters ) );
itemShiftAdjustSize( newSize.width(), newSize.height(), xShift, yShift );
//update rect for data defined size and position
attemptSetSceneRect( QRectF( pos().x() + xShift, pos().y() + yShift, width, height ) );
}
QFont QgsLayoutItemLabel::font() const
{
return mFont;
}
bool QgsLayoutItemLabel::writePropertiesToElement( QDomElement &composerLabelElem, QDomDocument &doc, const QgsReadWriteContext & ) const
{
composerLabelElem.setAttribute( QStringLiteral( "htmlState" ), static_cast< int >( mMode ) );
composerLabelElem.setAttribute( QStringLiteral( "labelText" ), mText );
composerLabelElem.setAttribute( QStringLiteral( "marginX" ), QString::number( mMarginX ) );
composerLabelElem.setAttribute( QStringLiteral( "marginY" ), QString::number( mMarginY ) );
composerLabelElem.setAttribute( QStringLiteral( "halign" ), mHAlignment );
composerLabelElem.setAttribute( QStringLiteral( "valign" ), mVAlignment );
//font
QDomElement labelFontElem = QgsFontUtils::toXmlElement( mFont, doc, QStringLiteral( "LabelFont" ) );
composerLabelElem.appendChild( labelFontElem );
//font color
QDomElement fontColorElem = doc.createElement( QStringLiteral( "FontColor" ) );
fontColorElem.setAttribute( QStringLiteral( "red" ), mFontColor.red() );
fontColorElem.setAttribute( QStringLiteral( "green" ), mFontColor.green() );
fontColorElem.setAttribute( QStringLiteral( "blue" ), mFontColor.blue() );
composerLabelElem.appendChild( fontColorElem );
return true;
}
bool QgsLayoutItemLabel::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
{
//restore label specific properties
//text
mText = itemElem.attribute( QStringLiteral( "labelText" ) );
//html state
mMode = static_cast< Mode >( itemElem.attribute( QStringLiteral( "htmlState" ) ).toInt() );
//margin
bool marginXOk = false;
bool marginYOk = false;
mMarginX = itemElem.attribute( QStringLiteral( "marginX" ) ).toDouble( &marginXOk );
mMarginY = itemElem.attribute( QStringLiteral( "marginY" ) ).toDouble( &marginYOk );
if ( !marginXOk || !marginYOk )
{
//upgrade old projects where margins where stored in a single attribute
double margin = itemElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "1.0" ) ).toDouble();
mMarginX = margin;
mMarginY = margin;
}
//Horizontal alignment
mHAlignment = static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "halign" ) ).toInt() );
//Vertical alignment
mVAlignment = static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "valign" ) ).toInt() );
//font
QgsFontUtils::setFromXmlChildNode( mFont, itemElem, QStringLiteral( "LabelFont" ) );
//font color
QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral( "FontColor" ) );
if ( !fontColorList.isEmpty() )
{
QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
int red = fontColorElem.attribute( QStringLiteral( "red" ), QStringLiteral( "0" ) ).toInt();
int green = fontColorElem.attribute( QStringLiteral( "green" ), QStringLiteral( "0" ) ).toInt();
int blue = fontColorElem.attribute( QStringLiteral( "blue" ), QStringLiteral( "0" ) ).toInt();
mFontColor = QColor( red, green, blue );
}
else
{
mFontColor = QColor( 0, 0, 0 );
}
return true;
}
QString QgsLayoutItemLabel::displayName() const
{
if ( !id().isEmpty() )
{
return id();
}
switch ( mMode )
{
case ModeHtml:
return tr( "<HTML Label>" );
case ModeFont:
{
//if no id, default to portion of label text
QString text = mText;
if ( text.isEmpty() )
{
return tr( "<Label>" );
}
if ( text.length() > 25 )
{
return QString( tr( "%1..." ) ).arg( text.left( 25 ).simplified() );
}
else
{
return text.simplified();
}
}
}
return QString(); // no warnings
}
QRectF QgsLayoutItemLabel::boundingRect() const
{
QRectF rectangle = rect();
double penWidth = hasFrame() ? ( pen().widthF() / 2.0 ) : 0;
rectangle.adjust( -penWidth, -penWidth, penWidth, penWidth );
if ( mMarginX < 0 )
{
rectangle.adjust( mMarginX, 0, -mMarginX, 0 );
}
if ( mMarginY < 0 )
{
rectangle.adjust( 0, mMarginY, 0, -mMarginY );
}
return rectangle;
}
void QgsLayoutItemLabel::setFrameEnabled( const bool drawFrame )
{
QgsLayoutItem::setFrameEnabled( drawFrame );
prepareGeometryChange();
}
void QgsLayoutItemLabel::setFrameStrokeWidth( const QgsLayoutMeasurement &strokeWidth )
{
QgsLayoutItem::setFrameStrokeWidth( strokeWidth );
prepareGeometryChange();
}
void QgsLayoutItemLabel::refresh()
{
contentChanged();
}
void QgsLayoutItemLabel::itemShiftAdjustSize( double newWidth, double newHeight, double &xShift, double &yShift ) const
{
//keep alignment point constant
double currentWidth = rect().width();
double currentHeight = rect().height();
xShift = 0;
yShift = 0;
double r = rotation();
if ( r >= 0 && r < 90 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
xShift = - ( newWidth - currentWidth ) / 2.0;
}
else if ( mHAlignment == Qt::AlignRight )
{
xShift = - ( newWidth - currentWidth );
}
if ( mVAlignment == Qt::AlignVCenter )
{
yShift = -( newHeight - currentHeight ) / 2.0;
}
else if ( mVAlignment == Qt::AlignBottom )
{
yShift = - ( newHeight - currentHeight );
}
}
if ( r >= 90 && r < 180 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
yShift = -( newHeight - currentHeight ) / 2.0;
}
else if ( mHAlignment == Qt::AlignRight )
{
yShift = -( newHeight - currentHeight );
}
if ( mVAlignment == Qt::AlignTop )
{
xShift = -( newWidth - currentWidth );
}
else if ( mVAlignment == Qt::AlignVCenter )
{
xShift = -( newWidth - currentWidth / 2.0 );
}
}
else if ( r >= 180 && r < 270 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
xShift = -( newWidth - currentWidth ) / 2.0;
}
else if ( mHAlignment == Qt::AlignLeft )
{
xShift = -( newWidth - currentWidth );
}
if ( mVAlignment == Qt::AlignVCenter )
{
yShift = ( newHeight - currentHeight ) / 2.0;
}
else if ( mVAlignment == Qt::AlignTop )
{
yShift = ( newHeight - currentHeight );
}
}
else if ( r >= 270 && r < 360 )
{
if ( mHAlignment == Qt::AlignHCenter )
{
yShift = -( newHeight - currentHeight ) / 2.0;
}
else if ( mHAlignment == Qt::AlignLeft )
{
yShift = -( newHeight - currentHeight );
}
if ( mVAlignment == Qt::AlignBottom )
{
xShift = -( newWidth - currentWidth );
}
else if ( mVAlignment == Qt::AlignVCenter )
{
xShift = -( newWidth - currentWidth / 2.0 );
}
}
}
QUrl QgsLayoutItemLabel::createStylesheetUrl() const
{
QString stylesheet;
stylesheet += QStringLiteral( "body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
stylesheet += QgsFontUtils::asCSS( mFont, 0.352778 * mHtmlUnitsToLayoutUnits );
stylesheet += QStringLiteral( "color: %1;" ).arg( mFontColor.name() );
stylesheet += QStringLiteral( "text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral( "left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral( "right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral( "center" ) : QStringLiteral( "justify" ) );
QByteArray ba;
ba.append( stylesheet.toUtf8() );
QUrl cssFileURL = QUrl( "data:text/css;charset=utf-8;base64," + ba.toBase64() );
return cssFileURL;
}

View File

@ -0,0 +1,271 @@
/***************************************************************************
qgslayoutitemlabel.h
-------------------
begin : October 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. *
* *
***************************************************************************/
#ifndef QGSLAYOUTITEMLABEL_H
#define QGSLAYOUTITEMLABEL_H
#include "qgis_core.h"
#include "qgslayoutitem.h"
#include "qgswebpage.h"
#include <QFont>
class QgsVectorLayer;
class QgsFeature;
class QgsDistanceArea;
/**
* \ingroup core
* A layout item subclass for text labels.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutItemLabel: public QgsLayoutItem
{
Q_OBJECT
public:
//! Label modes
enum Mode
{
ModeFont, //!< Label displays text rendered using a single font
ModeHtml, //!< Label displays rendered HTML content
};
/**
* Constructor for QgsLayoutItemLabel, with the specified parent \a layout.
*/
QgsLayoutItemLabel( QgsLayout *layout );
/**
* Returns a new label item for the specified \a layout.
*
* The caller takes responsibility for deleting the returned object.
*/
static QgsLayoutItemLabel *create( QgsLayout *layout ) SIP_FACTORY;
int type() const override;
QString stringType() const override;
//Overridden to contain part of label's text
virtual QString displayName() const override;
/**
* Resizes the item so that the label's text fits to the item. Keeps the top left point stationary.
*/
void adjustSizeToText();
/**
* Returns the label's preset text.
* \see currentText()
* \see setText()
*/
QString text() { return mText; }
/**
* Sets the label's preset \a text.
* \see text()
*/
void setText( const QString &text );
/**
* Returns the text as it appears on the label (with evaluated expressions
* and other dynamic content).
* \see text()
*/
QString currentText() const;
/**
* Returns the label's current mode.
* \see setMode()
*/
Mode mode() const { return mMode; }
/**
* Sets the label's current \a mode, allowing the label
* to switch between font based and HTML based rendering.
* \see mode()
*/
void setMode( Mode mode );
/**
* Returns the label's current font.
* \see setFont()
*/
QFont font() const;
/**
* Sets the label's current \a font.
* \see font()
*/
void setFont( const QFont &font );
/**
* Returns for the vertical alignment of the label.
* \see setVAlign()
* \see hAlign()
*/
Qt::AlignmentFlag vAlign() const { return mVAlignment; }
/**
* Returns the horizontal alignment of the label.
* \see vAlign()
* \see setHAlign()
*/
Qt::AlignmentFlag hAlign() const { return mHAlignment; }
/**
* Sets the horizontal \a alignment of the label.
* \see hAlign()
* \see setVAlign()
*/
void setHAlign( Qt::AlignmentFlag alignment ) { mHAlignment = alignment; }
/**
* Sets for the vertical \a alignment of the label.
* \see vAlign()
* \see setHAlign()
*/
void setVAlign( Qt::AlignmentFlag alignment ) { mVAlignment = alignment; }
/**
* Returns the horizontal margin between the edge of the frame and the label
* contents, in layout units.
* \see setMargin()
* \see marginY()
*/
double marginX() const { return mMarginX; }
/**
* Returns the vertical margin between the edge of the frame and the label
* contents, in layout units.
* \see setMargin()
* \see marginX()
*/
double marginY() const { return mMarginY; }
/**
* Sets the \a margin between the edge of the frame and the label contents.
* This method sets both the horizontal and vertical margins to the same
* value. The margins can be individually controlled using the setMarginX()
* and setMarginY() methods.
*
* Margins are set using the current layout units.
* \see setMarginX()
* \see setMarginY()
*/
void setMargin( double margin );
/**
* Sets the horizontal \a margin between the edge of the frame and the label
* contents, in layout units.
* \see setMargin()
* \see setMarginY()
*/
void setMarginX( double margin );
/**
* Sets the vertical \a margin between the edge of the frame and the label
* contents, in layout units.
* \see setMargin()
* \see setMarginX()
*/
void setMarginY( double margin );
/**
* Sets the label font \a color.
* \see fontColor()
*/
void setFontColor( const QColor &color ) { mFontColor = color; }
/**
* Returns the label font color.
* \see setFontColor()
*/
QColor fontColor() const { return mFontColor; }
// In case of negative margins, the bounding rect may be larger than the
// label's frame
QRectF boundingRect() const override;
// Reimplemented to call prepareGeometryChange after toggling frame
void setFrameEnabled( const bool drawFrame ) override;
// Reimplemented to call prepareGeometryChange after changing stroke width
void setFrameStrokeWidth( const QgsLayoutMeasurement &strokeWidth ) override;
public slots:
void refresh() override;
protected:
void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ) override;
private slots:
//! Track when QWebPage has finished loading its html contents
void loadingHtmlFinished( bool );
void refreshExpressionContext();
private:
bool mFirstRender = true;
// Text
QString mText;
Mode mMode = ModeFont;
double mHtmlUnitsToLayoutUnits = 1.0;
double htmlUnitsToLayoutUnits(); //calculate scale factor
bool mHtmlLoaded = false;
//! Helper function to calculate x/y shift for adjustSizeToText() depending on rotation, current size and alignment
void itemShiftAdjustSize( double newWidth, double newHeight, double &xShift, double &yShift ) const;
//! Called when the content is changed to handle HTML loading
void contentChanged();
//! Font
QFont mFont;
//! Horizontal margin between contents and frame (in mm)
double mMarginX = 0.0;
//! Vertical margin between contents and frame (in mm)
double mMarginY = 0.0;
//! Font color
QColor mFontColor = QColor( 0, 0, 0 );
//! Horizontal Alignment
Qt::AlignmentFlag mHAlignment = Qt::AlignJustify;
//! Vertical Alignment
Qt::AlignmentFlag mVAlignment = Qt::AlignTop;
//! Replaces replace '$CURRENT_DATE<(FORMAT)>' with the current date (e.g. $CURRENT_DATE(d 'June' yyyy)
void replaceDateText( QString &text ) const;
//! Creates an encoded stylesheet url using the current font and label appearance settings
QUrl createStylesheetUrl() const;
std::unique_ptr< QgsDistanceArea > mDistanceArea;
std::unique_ptr< QgsWebPage > mWebPage;
};
#endif //QGSLAYOUTITEMLABEL_H

View File

@ -17,6 +17,7 @@
#include "qgslayoutitemregistry.h"
#include "qgslayoutitemshape.h"
#include "qgslayoutitemmap.h"
#include "qgslayoutitemlabel.h"
#include "qgslayoutitempolygon.h"
#include "qgslayoutitempolyline.h"
#include "qgslayoutitempage.h"
@ -52,6 +53,7 @@ bool QgsLayoutItemRegistry::populate()
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPage, QStringLiteral( "Page" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileNew.svg" ) ), QgsLayoutItemPage::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutMap, QStringLiteral( "Map" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddMap.svg" ) ), QgsLayoutItemMap::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPicture, QStringLiteral( "Picture" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ), QgsLayoutItemPicture::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutLabel, QStringLiteral( "Label" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLabel.svg" ) ), QgsLayoutItemLabel::create ) );
addLayoutItemType( new QgsLayoutItemMetadata( LayoutShape, QStringLiteral( "Shape" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), []( QgsLayout * layout )
{
QgsLayoutItemShape *shape = new QgsLayoutItemShape( layout );

View File

@ -186,6 +186,7 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
LayoutPage, //!< Page items
LayoutMap, //!< Map item
LayoutPicture, //!< Picture item
LayoutLabel, //!< Label item
LayoutShape, //!< Shape item
LayoutPolygon, //!< Polygon shape item
LayoutPolyline, //!< Polyline shape item

View File

@ -135,6 +135,7 @@ SET(TESTS
testqgslayoutcontext.cpp
testqgslayoutitem.cpp
testqgslayoutitemgroup.cpp
testqgslayoutlabel.cpp
testqgslayoutmap.cpp
testqgslayoutmapgrid.cpp
testqgslayoutmapoverview.cpp

View File

@ -0,0 +1,291 @@
/***************************************************************************
testqgslayoutlabel.cpp
----------------------
begin : October 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 "qgsapplication.h"
#include "qgslayout.h"
#include "qgslayoutitemlabel.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsmultirenderchecker.h"
#include "qgsfontutils.h"
#include "qgsproject.h"
#include <QObject>
#include "qgstest.h"
class TestQgsLayoutLabel : public QObject
{
Q_OBJECT
public:
TestQgsLayoutLabel() = default;
private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
// test simple expression evaluation
void evaluation();
// test expression evaluation when a feature is set
void feature_evaluation();
// test page expressions
void page_evaluation();
void marginMethods(); //tests getting/setting margins
void render();
void renderAsHtml();
void renderAsHtmlRelative();
private:
QgsVectorLayer *mVectorLayer = nullptr;
QString mReport;
};
void TestQgsLayoutLabel::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();
//create maplayers from testdata and add to layer registry
QFileInfo vectorFileInfo( QStringLiteral( TEST_DATA_DIR ) + '/' + "france_parts.shp" );
mVectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
QStringLiteral( "ogr" ) );
}
void TestQgsLayoutLabel::cleanupTestCase()
{
QString myReportFile = QDir::tempPath() + "/qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
}
delete mVectorLayer;
QgsApplication::exitQgis();
}
void TestQgsLayoutLabel::init()
{
}
void TestQgsLayoutLabel::cleanup()
{
}
void TestQgsLayoutLabel::evaluation()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
#if 0 //TODO
l.atlasComposition().setCoverageLayer( mVectorLayer );
#endif
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
qWarning() << "composer label font: " << label->font().toString() << " exactMatch:" << label->font().exactMatch();
{
// $CURRENT_DATE evaluation
QString expected = "__" + QDate::currentDate().toString() + "__";
label->setText( QStringLiteral( "__$CURRENT_DATE__" ) );
QString evaluated = label->currentText();
QCOMPARE( evaluated, expected );
}
{
// $CURRENT_DATE() evaluation
QDateTime now = QDateTime::currentDateTime();
QString expected = "__" + now.toString( QStringLiteral( "dd" ) ) + "(ok)__";
label->setText( QStringLiteral( "__$CURRENT_DATE(dd)(ok)__" ) );
QString evaluated = label->currentText();
QCOMPARE( evaluated, expected );
}
{
// $CURRENT_DATE() evaluation (inside an expression)
QDate now = QDate::currentDate();
int dd = now.day();
QString expected = "__" + QStringLiteral( "%1" ).arg( dd + 1 ) + "(ok)__";
label->setText( QStringLiteral( "__[%$CURRENT_DATE(dd) + 1%](ok)__" ) );
QString evaluated = label->currentText();
QCOMPARE( evaluated, expected );
}
{
// expression evaluation (without feature)
QString expected = QStringLiteral( "__[NAME_1]42__" );
label->setText( QStringLiteral( "__[%\"NAME_1\"%][%21*2%]__" ) );
QString evaluated = label->currentText();
QCOMPARE( evaluated, expected );
}
}
void TestQgsLayoutLabel::feature_evaluation()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
#if 0 //TODO
l.atlasComposition().setCoverageLayer( mVectorLayer );
#endif
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
#if 0 //TODO
l.atlasComposition().setEnabled( true );
l.setAtlasMode( QgsComposition::ExportAtlas );
l.atlasComposition().updateFeatures();
l.atlasComposition().prepareForFeature( 0 );
{
// evaluation with a feature
label->setText( QStringLiteral( "[%\"NAME_1\"||'_ok'%]" ) );
QString evaluated = label->displayText();
QString expected = QStringLiteral( "Basse-Normandie_ok" );
QCOMPARE( evaluated, expected );
}
mComposition->atlasComposition().prepareForFeature( 1 );
{
// evaluation with a feature
label->setText( QStringLiteral( "[%\"NAME_1\"||'_ok'%]" ) );
QString evaluated = label->displayText();
QString expected = QStringLiteral( "Bretagne_ok" );
QCOMPARE( evaluated, expected );
}
mComposition->atlasComposition().setEnabled( false );
#endif
}
void TestQgsLayoutLabel::page_evaluation()
{
#if 0 //TODO
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
mComposition->atlasComposition().setCoverageLayer( mVectorLayer );
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
mComposition->setNumPages( 2 );
{
label->setText( QStringLiteral( "[%@layout_page||'/'||@layout_numpages%]" ) );
QString evaluated = label->displayText();
QString expected = QStringLiteral( "1/2" );
QCOMPARE( evaluated, expected );
// move to the second page and re-evaluate
label->setItemPosition( 0, 320 );
QCOMPARE( label->displayText(), QString( "2/2" ) );
}
#endif
}
void TestQgsLayoutLabel::marginMethods()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
//test setting margins separately
label->setMarginX( 3.0 );
label->setMarginY( 4.0 );
QCOMPARE( label->marginX(), 3.0 );
QCOMPARE( label->marginY(), 4.0 );
//test setting margins together
label->setMargin( 5.0 );
QCOMPARE( label->marginX(), 5.0 );
QCOMPARE( label->marginY(), 5.0 );
}
void TestQgsLayoutLabel::render()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
label->setText( QStringLiteral( "test label" ) );
label->setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ), 48 ) );
label->attemptMove( QgsLayoutPoint( 70, 70 ) );
label->adjustSizeToText();
QgsLayoutChecker checker( QStringLiteral( "composerlabel_render" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_label" ) );
QVERIFY( checker.testLayout( mReport, 0, 0 ) );
}
void TestQgsLayoutLabel::renderAsHtml()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
label->setFontColor( QColor( 200, 40, 60 ) );
label->setText( QStringLiteral( "test <i>html</i>" ) );
label->setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ), 48 ) );
label->setPos( 70, 70 );
label->adjustSizeToText();
label->setMode( QgsLayoutItemLabel::ModeHtml );
label->update();
QgsLayoutChecker checker( QStringLiteral( "composerlabel_renderhtml" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_label" ) );
QVERIFY( checker.testLayout( mReport, 0, 10 ) );
}
void TestQgsLayoutLabel::renderAsHtmlRelative()
{
QgsLayout l( QgsProject::instance() );
l.initializeDefaults();
QgsLayoutItemLabel *label = new QgsLayoutItemLabel( &l );
label->setMargin( 1 );
l.addLayoutItem( label );
QgsProject::instance()->setFileName( QStringLiteral( TEST_DATA_DIR ) + QDir::separator() + "test.qgs" );
label->setFontColor( QColor( 200, 40, 60 ) );
label->setText( QStringLiteral( "test <img src=\"small_sample_image.png\" />" ) );
label->setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ), 48 ) );
label->setPos( 70, 70 );
label->adjustSizeToText();
label->setMode( QgsLayoutItemLabel::ModeHtml );
label->update();
QgsLayoutChecker checker( QStringLiteral( "composerlabel_renderhtmlrelative" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_label" ) );
QVERIFY( checker.testLayout( mReport, 0, 0 ) );
}
QGSTEST_MAIN( TestQgsLayoutLabel )
#include "testqgslayoutlabel.moc"

View File

@ -86,6 +86,7 @@ ADD_PYTHON_TEST(PyQgsLayoutGridSettings test_qgslayoutgridsettings.py)
ADD_PYTHON_TEST(PyQgsLayoutGuide test_qgslayoutguides.py)
ADD_PYTHON_TEST(PyQgsLayoutItem test_qgslayoutitem.py)
ADD_PYTHON_TEST(PyQgsLayoutItemPropertiesDialog test_qgslayoutitempropertiesdialog.py)
ADD_PYTHON_TEST(PyQgsLayoutLabel test_qgslayoutlabel.py)
ADD_PYTHON_TEST(PyQgsLayoutMap test_qgslayoutmap.py)
ADD_PYTHON_TEST(PyQgsLayoutMapGrid test_qgslayoutmapgrid.py)
ADD_PYTHON_TEST(PyQgsLayoutPicture test_qgslayoutpicture.py)

View File

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsLayoutItemLabel.
.. note:: 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.
"""
__author__ = '(C) 2017 by Nyall Dawson'
__date__ = '23/10/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.testing import start_app, unittest
from qgis.PyQt.QtCore import QFileInfo, QDate, QDateTime
from qgis.core import QgsVectorLayer, QgsLayout, QgsLayoutItemLabel, QgsProject
from utilities import unitTestDataPath
start_app()
class TestQgsLayoutItemLabel(unittest.TestCase):
def testCase(self):
TEST_DATA_DIR = unitTestDataPath()
vectorFileInfo = QFileInfo(TEST_DATA_DIR + "/france_parts.shp")
mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr")
QgsProject.instance().addMapLayers([mVectorLayer])
layout = QgsLayout(QgsProject.instance())
layout.initializeDefaults()
label = QgsLayoutItemLabel(layout)
layout.addLayoutItem(label)
self.evaluation_test(layout, label)
self.feature_evaluation_test(layout, label, mVectorLayer)
self.page_evaluation_test(layout, label, mVectorLayer)
def evaluation_test(self, layout, label):
# $CURRENT_DATE evaluation
label.setText("__$CURRENT_DATE__")
assert label.currentText() == ("__" + QDate.currentDate().toString() + "__")
# $CURRENT_DATE() evaluation
label.setText("__$CURRENT_DATE(dd)(ok)__")
expected = "__" + QDateTime.currentDateTime().toString("dd") + "(ok)__"
assert label.currentText() == expected
# $CURRENT_DATE() evaluation (inside an expression)
label.setText("__[%$CURRENT_DATE(dd) + 1%](ok)__")
dd = QDate.currentDate().day()
expected = "__%d(ok)__" % (dd + 1)
assert label.currentText() == expected
# expression evaluation (without associated feature)
label.setText("__[%\"NAME_1\"%][%21*2%]__")
assert label.currentText() == "__[NAME_1]42__"
def feature_evaluation_test(self, layout, label, mVectorLayer):
pass
# TODO
#atlas = layout.atlasComposition()
#atlas.setCoverageLayer(mVectorLayer)
#atlas.setEnabled(True)
#layout.setAtlasMode(QgsComposition.ExportAtlas)
#label.setText("[%\"NAME_1\"||'_ok'%]")
#atlas.beginRender()
#atlas.prepareForFeature(0)
#assert label.currentText() == "Basse-Normandie_ok"
#atlas.prepareForFeature(1)
#assert label.currentText() == "Bretagne_ok"
def page_evaluation_test(self, layout, label, mVectorLayer):
pass
# TODO
#layout.setNumPages(2)
#label.setText("[%@layout_page||'/'||@layout_numpages%]")
#assert label.currentText() == "1/2"
# move the the second page and re-evaluate
#label.setItemPosition(0, 320)
#assert label.currentText() == "2/2"
if __name__ == '__main__':
unittest.main()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB