Allow the use of expressions inside a composer label

This commit is contained in:
Hugo Mercier 2012-09-26 16:13:45 +02:00
parent cc452d1ffc
commit f076c2e5da
9 changed files with 137 additions and 17 deletions

View File

@ -650,6 +650,7 @@ void QgsComposer::on_mActionExportAsPDF_triggered()
if ( progress.wasCanceled() )
{
atlasRender.end();
break;
}
try
@ -717,6 +718,7 @@ void QgsComposer::on_mActionPrint_triggered()
if ( progress.wasCanceled() )
{
atlasRender.end();
break;
}
try
@ -893,6 +895,7 @@ void QgsComposer::on_mActionExportAsImage_triggered()
if ( progress.wasCanceled() )
{
atlasRender.end();
break;
}
try

View File

@ -18,6 +18,8 @@
#include "qgscomposerlabelwidget.h"
#include "qgscomposerlabel.h"
#include "qgscomposeritemwidget.h"
#include "qgsexpressionbuilderdialog.h"
#include <QColorDialog>
#include <QFontDialog>
#include <QWidget>
@ -98,6 +100,33 @@ void QgsComposerLabelWidget::on_mFontColorButton_clicked()
mComposerLabel->endCommand();
}
void QgsComposerLabelWidget::on_mInsertExpressionButton_clicked()
{
if ( !mComposerLabel)
{
return;
}
QString selText = mTextEdit->textCursor().selectedText();
// edit the selected expression if there's one
if ( selText.startsWith( "[%" ) && selText.endsWith( "%]" ) )
selText = selText.mid( 2, selText.size() - 4 );
QgsExpressionBuilderDialog exprDlg( /* layer = */ 0, selText, this );
exprDlg.setWindowTitle( tr( "Insert expression" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
if ( !expression.isEmpty() )
{
mComposerLabel->beginCommand( tr( "Insert expression" ) );
mTextEdit->insertPlainText( "[%" + expression + "%]" );
mComposerLabel->endCommand();
}
}
}
void QgsComposerLabelWidget::on_mCenterRadioButton_clicked()
{
if ( mComposerLabel )

View File

@ -34,6 +34,7 @@ class QgsComposerLabelWidget: public QWidget, private Ui::QgsComposerLabelWidget
public slots:
void on_mTextEdit_textChanged();
void on_mFontButton_clicked();
void on_mInsertExpressionButton_clicked();
void on_mMarginDoubleSpinBox_valueChanged( double d );
void on_mFontColorButton_clicked();
void on_mCenterRadioButton_clicked();

View File

@ -16,12 +16,15 @@
***************************************************************************/
#include "qgscomposerlabel.h"
#include "qgsexpression.h"
#include <QDate>
#include <QDomElement>
#include <QPainter>
QgsComposerLabel::QgsComposerLabel( QgsComposition *composition ): QgsComposerItem( composition ), mMargin( 1.0 ), mFontColor( QColor( 0, 0, 0 ) ),
mHAlignment( Qt::AlignLeft ), mVAlignment( Qt::AlignTop )
QgsComposerLabel::QgsComposerLabel( QgsComposition *composition ):
QgsComposerItem( composition ), mMargin( 1.0 ), mFontColor( QColor( 0, 0, 0 ) ),
mHAlignment( Qt::AlignLeft ), mVAlignment( Qt::AlignTop ),
mExpressionFeature( 0 ), mExpressionLayer( 0 )
{
//default font size is 10 point
mFont.setPointSizeF( 10 );
@ -75,11 +78,17 @@ void QgsComposerLabel::setText( const QString& text )
emit itemChanged();
}
void QgsComposerLabel::setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer )
{
mExpressionFeature = feature;
mExpressionLayer = layer;
}
QString QgsComposerLabel::displayText() const
{
QString displayText = mText;
replaceDateText( displayText );
return displayText;
return QgsExpression::replaceExpressionText( displayText, mExpressionFeature, mExpressionLayer );
}
void QgsComposerLabel::replaceDateText( QString& text ) const

View File

@ -19,6 +19,9 @@
#include "qgscomposeritem.h"
class QgsVectorLayer;
class QgsFeature;
/** \ingroup MapComposer
* A label that can be placed onto a map composition.
*/
@ -45,6 +48,8 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
@note this function was added in version 1.2*/
QString displayText() const;
void setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer );
QFont font() const;
void setFont( const QFont& f );
/** Accessor for the vertical alignment of the label
@ -120,6 +125,9 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
double mTextBoxWidth;
/**Height of the text box. This is different to rectangle().height() in case there is rotation*/
double mTextBoxHeight;
QgsFeature* mExpressionFeature;
QgsVectorLayer* mExpressionLayer;
};
#endif

View File

@ -28,6 +28,7 @@
#include "qgscomposerpicture.h"
#include "qgscomposerscalebar.h"
#include "qgscomposershape.h"
#include "qgscomposerlabel.h"
#include "qgscomposerattributetable.h"
#include "qgsaddremovemultiframecommand.h"
#include "qgscomposermultiframecommand.h"
@ -57,6 +58,8 @@ struct QgsAtlasRendering::QgsAtlasRenderingImpl
QgsRectangle origExtent;
bool restoreLayer;
std::auto_ptr<QgsExpression> filenameExpr;
size_t pageNumber;
size_t numberOfPages;
};
QgsAtlasRendering::QgsAtlasRendering( QgsComposition* composition )
@ -125,6 +128,10 @@ void QgsAtlasRendering::begin( const QString& filenamePattern )
layerSet.removeAt( removeAt );
}
}
// special columns for expressions
QgsExpression::setSpecialColumn( "$numfeatures", QVariant( (int)impl->nFeatures ) );
QgsExpression::setSpecialColumn( "$numpages", QVariant( (int)impl->composition->numPages() ) );
}
void QgsAtlasRendering::prepareForFeature( size_t featureI )
@ -133,6 +140,7 @@ void QgsAtlasRendering::prepareForFeature( size_t featureI )
if ( impl->filenamePattern.size() > 0 )
{
QgsExpression::setSpecialColumn( "$feature", QVariant( (int)featureI + 1 ) );
QVariant filenameRes = impl->filenameExpr->evaluate( &*fit );
if ( impl->filenameExpr->hasEvalError() )
{
@ -204,7 +212,20 @@ void QgsAtlasRendering::prepareForFeature( size_t featureI )
new_extent.scale( 1 + impl->composition->atlasMap()->atlasMargin() );
}
}
impl->composition->atlasMap()->setNewExtent( new_extent );
// evaluate label expressions
QList<QgsComposerLabel*> labels;
impl->composition->composerItems( labels );
QgsExpression::setSpecialColumn( "$feature", QVariant( (int)featureI + 1 ) );
for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit )
{
QgsExpression::setSpecialColumn( "$page", QVariant( (int)impl->composition->itemPageNumber( *lit ) + 1 ) );
(*lit)->setExpressionContext( fit, impl->composition->atlasMap()->atlasCoverageLayer() );
}
// set the new extent (and render)
impl->composition->atlasMap()->setNewExtent( new_extent );
}
size_t QgsAtlasRendering::numFeatures() const
@ -212,13 +233,21 @@ size_t QgsAtlasRendering::numFeatures() const
return impl->nFeatures;
}
QString QgsAtlasRendering::currentFilename() const
const QString& QgsAtlasRendering::currentFilename() const
{
return impl->currentFilename;
}
void QgsAtlasRendering::end()
{
// reset label expression contexts
QList<QgsComposerLabel*> labels;
impl->composition->composerItems( labels );
for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit )
{
(*lit)->setExpressionContext( 0, 0 );
}
// restore the coverage visibility
if ( impl->restoreLayer )
{
@ -242,6 +271,11 @@ QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ) :
mPrintResolution = 300; //hardcoded default
loadSettings();
QgsExpression::setSpecialColumn( "$page", QVariant((int)0) );
QgsExpression::setSpecialColumn( "$feature", QVariant((int)0) );
QgsExpression::setSpecialColumn( "$numpages", QVariant((int)0) );
QgsExpression::setSpecialColumn( "$numfeatures", QVariant((int)0) );
}
QgsComposition::QgsComposition():
@ -250,6 +284,11 @@ QgsComposition::QgsComposition():
mAtlasMap( 0 )
{
loadSettings();
QgsExpression::setSpecialColumn( "$page", QVariant((int)0) );
QgsExpression::setSpecialColumn( "$feature", QVariant((int)0) );
QgsExpression::setSpecialColumn( "$numpages", QVariant((int)0) );
QgsExpression::setSpecialColumn( "$numfeatures", QVariant((int)0) );
}
QgsComposition::~QgsComposition()
@ -341,6 +380,16 @@ QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position )
return 0;
}
int QgsComposition::pageNumberAt( const QPointF& position ) const
{
return position.y() / (paperHeight() + spaceBetweenPages() );
}
int QgsComposition::itemPageNumber( const QgsComposerItem* item ) const
{
return pageNumberAt( QPointF( item->transform().dx(), item->transform().dy()) );
}
QList<QgsComposerItem*> QgsComposition::selectedComposerItems()
{
QList<QgsComposerItem*> composerItemList;

View File

@ -59,7 +59,8 @@ class QgsAtlasRendering
size_t numFeatures() const;
void prepareForFeature( size_t i );
QString currentFilename() const;
const QString& currentFilename() const;
private:
struct QgsAtlasRenderingImpl;
@ -136,6 +137,12 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Returns the topmost composer item. Ignores mPaperItem*/
QgsComposerItem* composerItemAt( const QPointF & position );
/** Returns the page number (0-bsaed) given a coordinate */
int pageNumberAt( const QPointF& position ) const;
/** Returns on which page number (0-based) is displayed an item */
int itemPageNumber( const QgsComposerItem* ) const;
QList<QgsComposerItem*> selectedComposerItems();
/**Returns pointers to all composer maps in the scene*/

View File

@ -97,6 +97,13 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
registerItem( func.mGroup, func.mName, " " + name + " " );
}
QList<QgsExpression::FunctionDef> specials = QgsExpression::specialColumns();
for ( int i = 0; i < specials.size(); ++i )
{
QString name = specials[i].mName;
registerItem( specials[i].mGroup, name, " " + name + " " );
}
#if QT_VERSION >= 0x040700
txtSearchEdit->setPlaceholderText( tr( "Search" ) );
#endif

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>274</width>
<height>488</height>
<width>307</width>
<height>525</height>
</rect>
</property>
<property name="sizePolicy">
@ -30,8 +30,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>271</width>
<height>470</height>
<width>276</width>
<height>503</height>
</rect>
</property>
<attribute name="label">
@ -45,14 +45,14 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="mFontColorButton">
<property name="text">
<string>Font color...</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QGroupBox" name="buttonGroup1">
<property name="title">
<string>Horizontal Alignment:</string>
@ -98,7 +98,7 @@
</layout>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="QGroupBox" name="buttonGroup2">
<property name="title">
<string>Vertical Alignment:</string>
@ -141,7 +141,7 @@
</layout>
</widget>
</item>
<item row="5" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<widget class="QDoubleSpinBox" name="mMarginDoubleSpinBox">
<property name="prefix">
<string>Margin </string>
@ -151,7 +151,7 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="mRotationLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
@ -170,14 +170,14 @@
</property>
</widget>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QDoubleSpinBox" name="mRotationSpinBox">
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="QPushButton" name="mFontButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
@ -190,6 +190,13 @@
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPushButton" name="mInsertExpressionButton">
<property name="text">
<string>Insert an expression</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>