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() ) if ( progress.wasCanceled() )
{ {
atlasRender.end();
break; break;
} }
try try
@ -717,6 +718,7 @@ void QgsComposer::on_mActionPrint_triggered()
if ( progress.wasCanceled() ) if ( progress.wasCanceled() )
{ {
atlasRender.end();
break; break;
} }
try try
@ -893,6 +895,7 @@ void QgsComposer::on_mActionExportAsImage_triggered()
if ( progress.wasCanceled() ) if ( progress.wasCanceled() )
{ {
atlasRender.end();
break; break;
} }
try try

View File

@ -18,6 +18,8 @@
#include "qgscomposerlabelwidget.h" #include "qgscomposerlabelwidget.h"
#include "qgscomposerlabel.h" #include "qgscomposerlabel.h"
#include "qgscomposeritemwidget.h" #include "qgscomposeritemwidget.h"
#include "qgsexpressionbuilderdialog.h"
#include <QColorDialog> #include <QColorDialog>
#include <QFontDialog> #include <QFontDialog>
#include <QWidget> #include <QWidget>
@ -98,6 +100,33 @@ void QgsComposerLabelWidget::on_mFontColorButton_clicked()
mComposerLabel->endCommand(); 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() void QgsComposerLabelWidget::on_mCenterRadioButton_clicked()
{ {
if ( mComposerLabel ) if ( mComposerLabel )

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#include "qgscomposerpicture.h" #include "qgscomposerpicture.h"
#include "qgscomposerscalebar.h" #include "qgscomposerscalebar.h"
#include "qgscomposershape.h" #include "qgscomposershape.h"
#include "qgscomposerlabel.h"
#include "qgscomposerattributetable.h" #include "qgscomposerattributetable.h"
#include "qgsaddremovemultiframecommand.h" #include "qgsaddremovemultiframecommand.h"
#include "qgscomposermultiframecommand.h" #include "qgscomposermultiframecommand.h"
@ -57,6 +58,8 @@ struct QgsAtlasRendering::QgsAtlasRenderingImpl
QgsRectangle origExtent; QgsRectangle origExtent;
bool restoreLayer; bool restoreLayer;
std::auto_ptr<QgsExpression> filenameExpr; std::auto_ptr<QgsExpression> filenameExpr;
size_t pageNumber;
size_t numberOfPages;
}; };
QgsAtlasRendering::QgsAtlasRendering( QgsComposition* composition ) QgsAtlasRendering::QgsAtlasRendering( QgsComposition* composition )
@ -125,6 +128,10 @@ void QgsAtlasRendering::begin( const QString& filenamePattern )
layerSet.removeAt( removeAt ); 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 ) void QgsAtlasRendering::prepareForFeature( size_t featureI )
@ -133,6 +140,7 @@ void QgsAtlasRendering::prepareForFeature( size_t featureI )
if ( impl->filenamePattern.size() > 0 ) if ( impl->filenamePattern.size() > 0 )
{ {
QgsExpression::setSpecialColumn( "$feature", QVariant( (int)featureI + 1 ) );
QVariant filenameRes = impl->filenameExpr->evaluate( &*fit ); QVariant filenameRes = impl->filenameExpr->evaluate( &*fit );
if ( impl->filenameExpr->hasEvalError() ) if ( impl->filenameExpr->hasEvalError() )
{ {
@ -204,7 +212,20 @@ void QgsAtlasRendering::prepareForFeature( size_t featureI )
new_extent.scale( 1 + impl->composition->atlasMap()->atlasMargin() ); 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 size_t QgsAtlasRendering::numFeatures() const
@ -212,13 +233,21 @@ size_t QgsAtlasRendering::numFeatures() const
return impl->nFeatures; return impl->nFeatures;
} }
QString QgsAtlasRendering::currentFilename() const const QString& QgsAtlasRendering::currentFilename() const
{ {
return impl->currentFilename; return impl->currentFilename;
} }
void QgsAtlasRendering::end() 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 // restore the coverage visibility
if ( impl->restoreLayer ) if ( impl->restoreLayer )
{ {
@ -242,6 +271,11 @@ QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ) :
mPrintResolution = 300; //hardcoded default mPrintResolution = 300; //hardcoded default
loadSettings(); 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(): QgsComposition::QgsComposition():
@ -250,6 +284,11 @@ QgsComposition::QgsComposition():
mAtlasMap( 0 ) mAtlasMap( 0 )
{ {
loadSettings(); 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() QgsComposition::~QgsComposition()
@ -341,6 +380,16 @@ QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position )
return 0; 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*> QgsComposition::selectedComposerItems()
{ {
QList<QgsComposerItem*> composerItemList; QList<QgsComposerItem*> composerItemList;

View File

@ -59,7 +59,8 @@ class QgsAtlasRendering
size_t numFeatures() const; size_t numFeatures() const;
void prepareForFeature( size_t i ); void prepareForFeature( size_t i );
QString currentFilename() const;
const QString& currentFilename() const;
private: private:
struct QgsAtlasRenderingImpl; struct QgsAtlasRenderingImpl;
@ -136,6 +137,12 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Returns the topmost composer item. Ignores mPaperItem*/ /**Returns the topmost composer item. Ignores mPaperItem*/
QgsComposerItem* composerItemAt( const QPointF & position ); 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(); QList<QgsComposerItem*> selectedComposerItems();
/**Returns pointers to all composer maps in the scene*/ /**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 + " " ); 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 #if QT_VERSION >= 0x040700
txtSearchEdit->setPlaceholderText( tr( "Search" ) ); txtSearchEdit->setPlaceholderText( tr( "Search" ) );
#endif #endif

View File

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