288 changes: 288 additions & 0 deletions src/app/composer/qgsatlascompositionwidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
/***************************************************************************
qgsatlascompositionwidget.cpp
-----------------------------
begin : October 2012
copyright : (C) 2012 Hugo Mercier
email : hugo dot mercier at oslandia 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 "qgsatlascompositionwidget.h"
#include "qgsatlascomposition.h"
#include "qgscomposition.h"
#include "qgsmaplayerregistry.h"
#include "qgsvectorlayer.h"
#include "qgsexpressionbuilderdialog.h"
#include "qgscomposermap.h"

QgsAtlasCompositionWidget::QgsAtlasCompositionWidget( QWidget* parent, QgsAtlasComposition* atlas, QgsComposition* c ):
QWidget( parent ), mAtlas( atlas ), mComposition( c )
{
setupUi( this );

// populate the layer list
mAtlasCoverageLayerComboBox->clear();
QMap< QString, QgsMapLayer * >& layers = QgsMapLayerRegistry::instance()->mapLayers();
int idx = 0;
for ( QMap<QString, QgsMapLayer*>::const_iterator it = layers.begin(); it != layers.end(); ++it )
{
// Only consider vector layers
if ( dynamic_cast<QgsVectorLayer*>(it.value()) )
{
mAtlasCoverageLayerComboBox->insertItem( idx++, it.key(), /* userdata */ qVariantFromValue( (void*)it.value() ) );
}
}

// Connect to addition / removal of layers
QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance();
if ( layerRegistry )
{
connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( onLayerRemoved( QString ) ) );
connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerAdded( QgsMapLayer* ) ) );
}

// update the composer map combo box
// populate the map list
mComposerMapComboBox->clear();
QList<const QgsComposerMap*> availableMaps = mComposition->composerMapItems();
QList<const QgsComposerMap*>::const_iterator mapItemIt = availableMaps.constBegin();
for ( ; mapItemIt != availableMaps.constEnd(); ++mapItemIt )
{
mComposerMapComboBox->addItem( tr( "Map %1" ).arg(( *mapItemIt )->id() ), qVariantFromValue( (void*)*mapItemIt ) );
}

// Connect to addition / removal of maps
connect( mComposition, SIGNAL( composerMapAdded( QgsComposerMap* ) ), this, SLOT( onComposerMapAdded( QgsComposerMap* ) ) );
connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( onItemRemoved( QgsComposerItem* ) ) );

// connect to updates
connect( mAtlas, SIGNAL( parameterChanged() ), this, SLOT( updateGuiElements() ) );

updateGuiElements();
}

QgsAtlasCompositionWidget::~QgsAtlasCompositionWidget()
{
}

void QgsAtlasCompositionWidget::on_mUseAtlasCheckBox_stateChanged( int state )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( state == Qt::Checked )
{
atlasMap->setEnabled( true );
mAtlasFrame->setEnabled( true );
}
else
{
atlasMap->setEnabled( false );
mAtlasFrame->setEnabled( false );
}
}

void QgsAtlasCompositionWidget::onLayerRemoved( QString layerName )
{
// update the atlas coverage layer combo box
for ( int i = 0; i < mAtlasCoverageLayerComboBox->count(); ++i )
{
if ( mAtlasCoverageLayerComboBox->itemText( i ) == layerName )
{
mAtlasCoverageLayerComboBox->removeItem( i );
break;
}
}
if ( mAtlasCoverageLayerComboBox->count() == 0 )
{
mAtlas->setCoverageLayer( 0 );
}
}

void QgsAtlasCompositionWidget::onLayerAdded( QgsMapLayer* map )
{
// update the atlas coverage layer combo box
QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( map );
if ( vectorLayer )
{
mAtlasCoverageLayerComboBox->addItem( map->id(), qVariantFromValue( (void*)map ) );
}
if ( mAtlasCoverageLayerComboBox->count() == 1 )
{
mAtlas->setCoverageLayer( vectorLayer );
}
}

void QgsAtlasCompositionWidget::onComposerMapAdded( QgsComposerMap* map )
{
mComposerMapComboBox->addItem( tr( "Map %1" ).arg( map->id() ), qVariantFromValue( (void*)map ) );
if ( mComposerMapComboBox->count() == 1 )
{
mAtlas->setComposerMap( map );
}
}

void QgsAtlasCompositionWidget::onItemRemoved( QgsComposerItem* item )
{
QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
if ( map )
{
int idx = mComposerMapComboBox->findData( qVariantFromValue( (void*)map ) );
if ( idx != -1 )
{
mComposerMapComboBox->removeItem( idx );
}
}
if ( mComposerMapComboBox->count() == 0 )
{
mAtlas->setComposerMap( 0 );
}
}

void QgsAtlasCompositionWidget::on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap )
{
return;
}
if ( index == -1 )
{
atlasMap->setCoverageLayer( 0 );
}
else
{
QgsVectorLayer* layer = reinterpret_cast<QgsVectorLayer*>(mAtlasCoverageLayerComboBox->itemData( index ).value<void*>());
atlasMap->setCoverageLayer( layer );
}
}

void QgsAtlasCompositionWidget::on_mComposerMapComboBox_currentIndexChanged( int index )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap )
{
return;
}
if ( index == -1 )
{
atlasMap->setComposerMap( 0 );
}
else
{
QgsComposerMap* map = reinterpret_cast<QgsComposerMap*>(mComposerMapComboBox->itemData( index ).value<void*>());
atlasMap->setComposerMap( map );
}
}

void QgsAtlasCompositionWidget::on_mAtlasFilenamePatternEdit_textChanged( const QString& text )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap )
{
return;
}

atlasMap->setFilenamePattern( text );
}

void QgsAtlasCompositionWidget::on_mAtlasFilenameExpressionButton_clicked()
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap || !atlasMap->coverageLayer() )
{
return;
}

QgsExpressionBuilderDialog exprDlg( atlasMap->coverageLayer(), mAtlasFilenamePatternEdit->text(), this );
exprDlg.setWindowTitle( tr( "Expression based filename" ) );
if ( exprDlg.exec() == QDialog::Accepted )
{
QString expression = exprDlg.expressionText();
if ( !expression.isEmpty() )
{
// will emit a textChanged signal
mAtlasFilenamePatternEdit->setText( expression );
}
}
}

void QgsAtlasCompositionWidget::on_mAtlasHideCoverageCheckBox_stateChanged( int state )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap )
{
return;
}
atlasMap->setHideCoverage( state == Qt::Checked );
}

void QgsAtlasCompositionWidget::on_mAtlasFixedScaleCheckBox_stateChanged( int state )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap )
{
return;
}
atlasMap->setFixedScale( state == Qt::Checked );

// in fixed scale mode, the margin is meaningless
if ( state == Qt::Checked )
{
mAtlasMarginSpinBox->setEnabled( false );
}
else
{
mAtlasMarginSpinBox->setEnabled( true );
}
}

void QgsAtlasCompositionWidget::on_mAtlasSingleFileCheckBox_stateChanged( int state )
{
QgsAtlasComposition* atlasMap = mAtlas;
if ( !atlasMap )
{
return;
}
atlasMap->setSingleFile( state == Qt::Checked );
}

void QgsAtlasCompositionWidget::updateGuiElements()
{
if ( mAtlas->enabled() )
{
mUseAtlasCheckBox->setCheckState( Qt::Checked );
}
else
{
mUseAtlasCheckBox->setCheckState( Qt::Unchecked );
}

int idx = mAtlasCoverageLayerComboBox->findData( qVariantFromValue( (void*)mAtlas->coverageLayer() ));
if ( idx != -1 )
{
mAtlasCoverageLayerComboBox->setCurrentIndex( idx );
}
idx = mComposerMapComboBox->findData( qVariantFromValue( (void*)mAtlas->composerMap() ));
if ( idx != -1 )
{
mComposerMapComboBox->setCurrentIndex( idx );
}

mAtlasMarginSpinBox->setValue( static_cast<int>(mAtlas->margin() * 100) );
mAtlasFilenamePatternEdit->setText( mAtlas->filenamePattern() );
mAtlasFixedScaleCheckBox->setCheckState( mAtlas->fixedScale() ? Qt::Checked : Qt::Unchecked );
mAtlasHideCoverageCheckBox->setCheckState( mAtlas->hideCoverage() ? Qt::Checked : Qt::Unchecked );
mAtlasSingleFileCheckBox->setCheckState( mAtlas->singleFile() ? Qt::Checked : Qt::Unchecked );
}

void QgsAtlasCompositionWidget::blockAllSignals( bool b )
{
mUseAtlasCheckBox->blockSignals( b );
mAtlasFrame->blockSignals( b );
}
60 changes: 60 additions & 0 deletions src/app/composer/qgsatlascompositionwidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/***************************************************************************
qgsatlascompositionwidget.h
---------------------------
begin : October 2012
copyright : (C) 2012 Hugo Mercier
email : hugo dot mercier at oslandia 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 "ui_qgsatlascompositionwidgetbase.h"

class QgsComposition;
class QgsAtlasComposition;
class QgsMapLayer;
class QgsComposerMap;
class QgsComposerItem;

/** \ingroup MapComposer
* Input widget for QgsAtlasComposition
*/
class QgsAtlasCompositionWidget:
public QWidget,
private Ui::QgsAtlasCompositionWidgetBase
{
Q_OBJECT
public:
QgsAtlasCompositionWidget( QWidget* parent, QgsAtlasComposition* atlas, QgsComposition* c );
~QgsAtlasCompositionWidget();

public slots:
void on_mUseAtlasCheckBox_stateChanged( int state );
void on_mComposerMapComboBox_currentIndexChanged( int index );
void on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index );
void on_mAtlasFilenamePatternEdit_textChanged( const QString& text );
void on_mAtlasFilenameExpressionButton_clicked();
void on_mAtlasHideCoverageCheckBox_stateChanged( int state );
void on_mAtlasFixedScaleCheckBox_stateChanged( int state );
void on_mAtlasSingleFileCheckBox_stateChanged( int state );

private slots:
void onLayerRemoved( QString );
void onLayerAdded( QgsMapLayer* );
void onComposerMapAdded( QgsComposerMap* );
void onItemRemoved( QgsComposerItem* );

void updateGuiElements();

private:
QgsAtlasComposition* mAtlas;
QgsComposition* mComposition;

void blockAllSignals( bool b );
};
555 changes: 488 additions & 67 deletions src/app/composer/qgscomposer.cpp

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/app/composer/qgscomposer.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class QgsComposerAttributeTable;
class QgsComposerView;
class QgsComposition;
class QgsMapCanvas;
class QgsAtlasComposition;

class QGridLayout;
class QDomNode;
Expand Down Expand Up @@ -311,6 +312,9 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
//! Current composition
QgsComposition *mComposition;

//! Atlas map
QgsAtlasComposition* mAtlasComposition;

//! Pointer to QGIS application
QgisApp *mQgis;

Expand Down Expand Up @@ -341,6 +345,7 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
QDockWidget* mItemDock;
QDockWidget* mUndoDock;
QDockWidget* mGeneralDock;
QDockWidget* mAtlasDock;

QMenu* mPanelMenu;
QMenu* mToolbarMenu;
Expand Down
29 changes: 29 additions & 0 deletions src/app/composer/qgscomposerlabelwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "qgscomposerlabelwidget.h"
#include "qgscomposerlabel.h"
#include "qgscomposeritemwidget.h"
#include "qgsexpressionbuilderdialog.h"

#include <QColorDialog>
#include <QFontDialog>
#include <QWidget>
Expand Down Expand Up @@ -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 )
Expand Down
1 change: 1 addition & 0 deletions src/app/composer/qgscomposerlabelwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions src/app/composer/qgscomposermapwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@
//#include "qgssymbolv2propertiesdialog.h"
#include "qgssymbolv2selectordialog.h"
#include "qgssymbollayerv2utils.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsmaplayerregistry.h"
#include "qgscomposershape.h"
#include "qgspaperitem.h"
#include "qgsexpressionbuilderdialog.h"
#include <QColorDialog>
#include <QFontDialog>
#include <QMessageBox>

QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap ): QWidget(), mComposerMap( composerMap )
{
Expand Down Expand Up @@ -903,6 +910,11 @@ void QgsComposerMapWidget::showEvent( QShowEvent * event )
QWidget::showEvent( event );
}

void QgsComposerMapWidget::addPageToToolbox( QWidget* widget, const QString& name )
{
toolBox->addItem( widget, name );
}

void QgsComposerMapWidget::insertAnnotationPositionEntries( QComboBox* c )
{
c->insertItem( 0, tr( "Inside frame" ) );
Expand Down
11 changes: 7 additions & 4 deletions src/app/composer/qgscomposermapwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "ui_qgscomposermapwidgetbase.h"
#include "qgscomposermap.h"
class QgsMapLayer;

/** \ingroup MapComposer
* Input widget for the configuration of QgsComposerMap
Expand All @@ -31,7 +32,7 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
public:

QgsComposerMapWidget( QgsComposerMap* composerMap );
~QgsComposerMapWidget();
virtual ~QgsComposerMapWidget();

public slots:
void on_mWidthLineEdit_editingFinished();
Expand Down Expand Up @@ -86,6 +87,11 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
protected:
void showEvent( QShowEvent * event );

void addPageToToolbox( QWidget * widget, const QString& name );

/**Sets the current composer map values to the GUI elements*/
virtual void updateGuiElements();

private slots:

/**Sets the GUI elements to the values of mPicture*/
Expand All @@ -94,9 +100,6 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
private:
QgsComposerMap* mComposerMap;

/**Sets the current composer map values to the GUI elements*/
void updateGuiElements();

/**Sets extent of composer map from line edits*/
void updateComposerExtentFromGui();

Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ SET(QGIS_CORE_SRCS
composer/qgscomposertexttable.cpp
composer/qgscomposerscalebar.cpp
composer/qgscomposershape.cpp
composer/qgsatlascomposition.cpp
composer/qgslegendmodel.cpp
composer/qgscomposerlegend.cpp
composer/qgspaperitem.cpp
Expand Down Expand Up @@ -302,6 +303,7 @@ SET(QGIS_CORE_MOC_HDRS
composer/qgscomposerattributetable.h
composer/qgscomposerhtml.h
composer/qgscomposermultiframe.h
composer/qgsatlascomposition.h
composer/qgscomposition.h

composer/qgslegendmodel.h
Expand Down
337 changes: 337 additions & 0 deletions src/core/composer/qgsatlascomposition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
/***************************************************************************
qgsatlascomposition.cpp
-----------------------
begin : October 2012
copyright : (C) 2005 by Hugo Mercier
email : hugo dot mercier at oslandia 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 <stdexcept>

#include "qgsatlascomposition.h"
#include "qgsvectorlayer.h"
#include "qgscomposermap.h"
#include "qgsvectordataprovider.h"
#include "qgsexpression.h"
#include "qgsgeometry.h"
#include "qgscomposerlabel.h"
#include "qgsmaplayerregistry.h"

QgsAtlasComposition::QgsAtlasComposition( QgsComposition* composition ) :
mComposition( composition ),
mEnabled( false ),
mComposerMap( 0 ),
mHideCoverage( false ), mFixedScale( false ), mMargin( 0.10 ), mFilenamePattern( "'output_'||$feature" ),
mCoverageLayer( 0 ), mSingleFile( false )
{

// declare special columns with a default value
QgsExpression::setSpecialColumn( "$page", QVariant(( int )1 ) );
QgsExpression::setSpecialColumn( "$feature", QVariant(( int )0 ) );
QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )1 ) );
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )0 ) );
}

QgsAtlasComposition::~QgsAtlasComposition()
{
}

void QgsAtlasComposition::setCoverageLayer( QgsVectorLayer* layer )
{
mCoverageLayer = layer;

if ( mCoverageLayer != 0 )
{
// update the number of features
QgsVectorDataProvider* provider = mCoverageLayer->dataProvider();
QgsExpression::setSpecialColumn( "$numfeatures", QVariant( (int)provider->featureCount() ) );
}
}

void QgsAtlasComposition::beginRender()
{
if ( !mComposerMap || !mCoverageLayer )
{
return;
}

const QgsCoordinateReferenceSystem& coverage_crs = mCoverageLayer->crs();
const QgsCoordinateReferenceSystem& destination_crs = mComposerMap->mapRenderer()->destinationCrs();
// transformation needed for feature geometries
mTransform.setSourceCrs( coverage_crs );
mTransform.setDestCRS( destination_crs );

QgsVectorDataProvider* provider = mCoverageLayer->dataProvider();

QgsFieldMap fieldmap = provider->fields();

if ( mFilenamePattern.size() > 0 )
{
mFilenameExpr = std::auto_ptr<QgsExpression>( new QgsExpression( mFilenamePattern ) );
// expression used to evaluate each filename
// test for evaluation errors
if ( mFilenameExpr->hasParserError() )
{
throw std::runtime_error( "Filename parsing error: " + mFilenameExpr->parserErrorString().toStdString() );
}

// prepare the filename expression
mFilenameExpr->prepare( fieldmap );
}

// select all features with all attributes
provider->select( provider->attributeIndexes() );

// We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process
// We thus store the feature ids for future extraction
QgsFeature feat;
while ( provider->nextFeature( feat ) )
{
mFeatureIds.push_back( feat.id() );
}

mOrigExtent = mComposerMap->extent();

mRestoreLayer = false;
QStringList& layerSet = mComposition->mapRenderer()->layerSet();
if ( mHideCoverage )
{
// look for the layer in the renderer's set
int removeAt = layerSet.indexOf( mCoverageLayer->id() );
if ( removeAt != -1 )
{
mRestoreLayer = true;
layerSet.removeAt( removeAt );
}
}

// special columns for expressions
QgsExpression::setSpecialColumn( "$numpages", QVariant( mComposition->numPages() ) );
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )provider->featureCount() ) );
}

void QgsAtlasComposition::endRender()
{
if ( !mComposerMap || !mCoverageLayer )
{
return;
}

// reset label expression contexts
QList<QgsComposerLabel*> labels;
mComposition->composerItems( labels );
for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit )
{
( *lit )->setExpressionContext( 0, 0 );
}

// restore the coverage visibility
if ( mRestoreLayer )
{
QStringList& layerSet = mComposition->mapRenderer()->layerSet();

layerSet.push_back( mCoverageLayer->id() );
mComposerMap->cache();
mComposerMap->update();
}
mComposerMap->setNewExtent( mOrigExtent );
}

size_t QgsAtlasComposition::numFeatures() const
{
if ( mCoverageLayer )
{
return mCoverageLayer->dataProvider()->featureCount();
}
return 0;
}

void QgsAtlasComposition::prepareForFeature( size_t featureI )
{
if ( !mComposerMap || !mCoverageLayer )
{
return;
}

QgsVectorDataProvider* provider = mCoverageLayer->dataProvider();
// retrieve the next feature, based on its id
provider->featureAtId( mFeatureIds[ featureI ], mCurrentFeature, /* fetchGeometry = */ true, provider->attributeIndexes() );

if ( mFilenamePattern.size() > 0 )
{
QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) );
QVariant filenameRes = mFilenameExpr->evaluate( &mCurrentFeature );
if ( mFilenameExpr->hasEvalError() )
{
throw std::runtime_error( "Filename eval error: " + mFilenameExpr->evalErrorString().toStdString() );
}

mCurrentFilename = filenameRes.toString();
}

//
// compute the new extent
// keep the original aspect ratio
// and apply a margin

// QgsGeometry::boundingBox is expressed in the geometry"s native CRS
// We have to transform the grometry to the destination CRS and ask for the bounding box
// Note: we cannot directly take the transformation of the bounding box, since transformations are not linear

QgsGeometry tgeom( *mCurrentFeature.geometry() );
tgeom.transform( mTransform );
QgsRectangle geom_rect = tgeom.boundingBox();

double xa1 = geom_rect.xMinimum();
double xa2 = geom_rect.xMaximum();
double ya1 = geom_rect.yMinimum();
double ya2 = geom_rect.yMaximum();
QgsRectangle new_extent = geom_rect;

// restore the original extent
// (successive calls to setNewExtent tend to deform the original rectangle)
mComposerMap->setNewExtent( mOrigExtent );

if ( mFixedScale )
{
// only translate, keep the original scale (i.e. width x height)

double geom_center_x = ( xa1 + xa2 ) / 2.0;
double geom_center_y = ( ya1 + ya2 ) / 2.0;
double xx = geom_center_x - mOrigExtent.width() / 2.0;
double yy = geom_center_y - mOrigExtent.height() / 2.0;
new_extent = QgsRectangle( xx,
yy,
xx + mOrigExtent.width(),
yy + mOrigExtent.height() );
}
else
{
// auto scale

double geom_ratio = geom_rect.width() / geom_rect.height();
double map_ratio = mOrigExtent.width() / mOrigExtent.height();

// geometry height is too big
if ( geom_ratio < map_ratio )
{
new_extent = QgsRectangle(( xa1 + xa2 + map_ratio * ( ya1 - ya2 ) ) / 2.0,
ya1,
xa1 + map_ratio * ( ya2 - ya1 ),
ya2 );
}
// geometry width is too big
else if ( geom_ratio > map_ratio )
{
new_extent = QgsRectangle( xa1,
( ya1 + ya2 + ( xa1 - xa2 ) / map_ratio ) / 2.0,
xa2,
ya1 + ( xa2 - xa1 ) / map_ratio );
}
if ( mMargin > 0.0 )
{
new_extent.scale( 1 + mMargin );
}
}

// evaluate label expressions
QList<QgsComposerLabel*> labels;
mComposition->composerItems( labels );
QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) );

for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit )
{
( *lit )->setExpressionContext( &mCurrentFeature, mCoverageLayer );
}

// set the new extent (and render)
mComposerMap->setNewExtent( new_extent );
}

const QString& QgsAtlasComposition::currentFilename() const
{
return mCurrentFilename;
}

void QgsAtlasComposition::writeXML( QDomElement& elem, QDomDocument& doc ) const
{
QDomElement atlasElem = doc.createElement( "Atlas" );
atlasElem.setAttribute( "enabled", mEnabled ? "true" : "false" );
if ( !mEnabled )
{
return;
}

if ( mCoverageLayer )
{
atlasElem.setAttribute( "coverageLayer", mCoverageLayer->id() );
}
else
{
atlasElem.setAttribute( "coverageLayer", "" );
}
if ( mComposerMap )
{
atlasElem.setAttribute( "composerMap", mComposerMap->id() );
}
else
{
atlasElem.setAttribute( "composerMap", "" );
}
atlasElem.setAttribute( "hideCoverage", mHideCoverage ? "true" : "false" );
atlasElem.setAttribute( "fixedScale", mFixedScale ? "true" : "false" );
atlasElem.setAttribute( "singleFile", mSingleFile ? "true" : "false" );
atlasElem.setAttribute( "margin", QString::number(mMargin) );
atlasElem.setAttribute( "filenamePattern", mFilenamePattern );

elem.appendChild( atlasElem );
}

void QgsAtlasComposition::readXML( const QDomElement& atlasElem, const QDomDocument& )
{
mEnabled = atlasElem.attribute( "enabled", "false" ) == "true" ? true : false;
if ( !mEnabled )
{
emit parameterChanged();
return;
}

// look for stored layer name
mCoverageLayer = 0;
QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers();
for ( QMap<QString, QgsMapLayer*>::const_iterator it = layers.begin(); it != layers.end(); ++it )
{
if ( it.key() == atlasElem.attribute("coverageLayer") )
{
mCoverageLayer = dynamic_cast<QgsVectorLayer*>(it.value());
break;
}
}
// look for stored composer map
mComposerMap = 0;
QList<const QgsComposerMap*> maps = mComposition->composerMapItems();
for ( QList<const QgsComposerMap*>::const_iterator it = maps.begin(); it != maps.end(); ++it )
{
if ( (*it)->id() == atlasElem.attribute( "composerMap" ).toInt() )
{
mComposerMap = const_cast<QgsComposerMap*>( *it );
break;
}
}
mMargin = atlasElem.attribute( "margin", "0.0" ).toDouble();
mHideCoverage = atlasElem.attribute( "hideCoverage", "false" ) == "true" ? true : false;
mFixedScale = atlasElem.attribute( "fixedScale", "false" ) == "true" ? true : false;
mSingleFile = atlasElem.attribute( "singleFile", "false" ) == "true" ? true : false;
mFilenamePattern = atlasElem.attribute( "filenamePattern", "" );

std::cout << "emit parameter changed this = " << this << std::endl;
emit parameterChanged();
}
116 changes: 116 additions & 0 deletions src/core/composer/qgsatlascomposition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/***************************************************************************
qgsatlascomposermap.h
---------------------
begin : October 2012
copyright : (C) 2005 by Hugo Mercier
email : hugo dot mercier at oslandia 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 QGSATLASCOMPOSITION_H
#define QGSATLASCOMPOSITION_H

#include "qgscoordinatetransform.h"
#include "qgsfeature.h"

#include <memory>
#include <QString>
#include <QDomElement>
#include <QDomDocument>

class QgsComposerMap;
class QgsComposition;
class QgsVectorLayer;
class QgsExpression;

/** \ingroup MapComposer
* Class used to render an Atlas, iterating over geometry features.
* prepareForFeature() modifies the atlas map's extent to zoom on the given feature.
* This class is used for printing, exporting to PDF and images.
* */
class CORE_EXPORT QgsAtlasComposition : public QObject
{
Q_OBJECT
public:
QgsAtlasComposition( QgsComposition* composition );
~QgsAtlasComposition();

/** Is the atlas generation enabled ? */
bool enabled() const { return mEnabled; }
void setEnabled( bool e ) { mEnabled = e; }

QgsComposerMap* composerMap() const { return mComposerMap; }
void setComposerMap( QgsComposerMap* map ) { mComposerMap = map; }

bool hideCoverage() const { return mHideCoverage; }
void setHideCoverage( bool hide ) { mHideCoverage = hide; }

bool fixedScale() const { return mFixedScale; }
void setFixedScale( bool fixed ) { mFixedScale = fixed; }

float margin() const { return mMargin; }
void setMargin( float margin ) { mMargin = margin; }

QString filenamePattern() const { return mFilenamePattern; }
void setFilenamePattern( const QString& pattern ) { mFilenamePattern = pattern; }

QgsVectorLayer* coverageLayer() const { return mCoverageLayer; }
void setCoverageLayer( QgsVectorLayer* lmap );

bool singleFile() const { return mSingleFile; }
void setSingleFile( bool single ) { mSingleFile = single; }

/** Begins the rendering. */
void beginRender();
/** Ends the rendering. Restores original extent */
void endRender();

/** Returns the number of features in the coverage layer */
size_t numFeatures() const;

/** Prepare the atlas map for the given feature. Sets the extent and context variables */
void prepareForFeature( size_t i );

/** Returns the current filename. Must be called after prepareForFeature( i ) */
const QString& currentFilename() const;

void writeXML( QDomElement& elem, QDomDocument& doc ) const;
void readXML( const QDomElement& elem, const QDomDocument& doc );

QgsComposition* composition() { return mComposition; }

signals:
/** emitted when one of the parameters changes */
void parameterChanged();

private:
QgsComposition* mComposition;

bool mEnabled;
QgsComposerMap* mComposerMap;
bool mHideCoverage;
bool mFixedScale;
double mMargin;
QString mFilenamePattern;
QgsVectorLayer* mCoverageLayer;
bool mSingleFile;

QgsCoordinateTransform mTransform;
QString mCurrentFilename;
std::vector<QgsFeatureId> mFeatureIds;
QgsFeature mCurrentFeature;
QgsRectangle mOrigExtent;
bool mRestoreLayer;
std::auto_ptr<QgsExpression> mFilenameExpr;
};

#endif



1 change: 1 addition & 0 deletions src/core/composer/qgscomposeritem.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
virtual void removeItems() {}

const QgsComposition* composition() const {return mComposition;}
QgsComposition* composition() {return mComposition;}

virtual void beginItemCommand( const QString& text ) { beginCommand( text ); }

Expand Down
26 changes: 21 additions & 5 deletions src/core/composer/qgscomposerlabel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down Expand Up @@ -75,23 +78,36 @@ void QgsComposerLabel::setText( const QString& text )
emit itemChanged();
}

void QgsComposerLabel::setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer, QMap<QString, QVariant> substitutions )
{
mExpressionFeature = feature;
mExpressionLayer = layer;
mSubstitutions = substitutions;
}

QString QgsComposerLabel::displayText() const
{
QString displayText = mText;
replaceDateText( displayText );
return displayText;
QMap<QString, QVariant> subs = mSubstitutions;
subs[ "$page" ] = QVariant((int)mComposition->itemPageNumber( this ) + 1);
return QgsExpression::replaceExpressionText( displayText, mExpressionFeature, mExpressionLayer, &subs );
}

void QgsComposerLabel::replaceDateText( QString& text ) const
{
int currentDatePos = text.indexOf( "$CURRENT_DATE" );
QString constant = "$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 )
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 ) );
Expand Down
10 changes: 10 additions & 0 deletions src/core/composer/qgscomposerlabel.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

#include "qgscomposeritem.h"

class QgsVectorLayer;
class QgsFeature;

/** \ingroup MapComposer
* A label that can be placed onto a map composition.
*/
Expand All @@ -45,6 +48,9 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem
@note this function was added in version 1.2*/
QString displayText() const;

/** Sets the current feature, the current layer and a list of local variable substitutions for evaluating expressions */
void setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer, QMap<QString, QVariant> substitutions = QMap<QString, QVariant>() );

QFont font() const;
void setFont( const QFont& f );
/** Accessor for the vertical alignment of the label
Expand Down Expand Up @@ -120,6 +126,10 @@ 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;
QMap<QString, QVariant> mSubstitutions;
};

#endif
Expand Down
7 changes: 4 additions & 3 deletions src/core/composer/qgscomposermap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@
#include <cmath>

QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
: QgsComposerItem( x, y, width, height, composition ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ), mGridEnabled( false ), mGridStyle( Solid ),
: QgsComposerItem( x, y, width, height, composition ), mKeepLayerSet( false ),
mOverviewFrameMapId( -1 ), mGridEnabled( false ), mGridStyle( Solid ),
mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ),
mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ), mTopGridAnnotationPosition( OutsideMapFrame ),
mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ),
mTopGridAnnotationDirection( Horizontal ), mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ),
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true )
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true )
{
mComposition = composition;
mOverviewFrameMapSymbol = 0;
Expand Down Expand Up @@ -84,7 +85,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition )
mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ), mTopGridAnnotationPosition( OutsideMapFrame ),
mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ),
mTopGridAnnotationDirection( Horizontal ), mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mCrossLength( 3 ),
mMapCanvas( 0 ), mDrawCanvasItems( true )
mMapCanvas( 0 ), mDrawCanvasItems( true )
{
mOverviewFrameMapSymbol = 0;
createDefaultOverviewFrameSymbol();
Expand Down
3 changes: 2 additions & 1 deletion src/core/composer/qgscomposermap.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class QDomDocument;
class QGraphicsView;
class QPainter;
class QgsFillSymbolV2;
class QgsVectorLayer;

/** \ingroup MapComposer
* \class QgsComposerMap
Expand All @@ -45,7 +46,7 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height );
/** Constructor. Settings are read from project. */
QgsComposerMap( QgsComposition *composition );
~QgsComposerMap();
virtual ~QgsComposerMap();

/** return correct graphics item type. Added in v1.7 */
virtual int type() const { return ComposerMap; }
Expand Down
80 changes: 65 additions & 15 deletions src/core/composer/qgscomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* *
***************************************************************************/

#include <stdexcept>

#include "qgscomposition.h"
#include "qgscomposeritem.h"
#include "qgscomposerarrow.h"
Expand All @@ -26,20 +28,26 @@
#include "qgscomposerpicture.h"
#include "qgscomposerscalebar.h"
#include "qgscomposershape.h"
#include "qgscomposerlabel.h"
#include "qgscomposerattributetable.h"
#include "qgsaddremovemultiframecommand.h"
#include "qgscomposermultiframecommand.h"
#include "qgslogger.h"
#include "qgspaintenginehack.h"
#include "qgspaperitem.h"
#include "qgsgeometry.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsexpression.h"
#include <QDomDocument>
#include <QDomElement>
#include <QGraphicsRectItem>
#include <QPainter>
#include <QPrinter>
#include <QSettings>
#include <QDir>

QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ):
QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ) :
QGraphicsScene( 0 ), mMapRenderer( mapRenderer ), mPlotStyle( QgsComposition::Preview ), mPageWidth( 297 ), mPageHeight( 210 ), mSpaceBetweenPages( 10 ), mPrintAsRaster( false ), mSelectionTolerance( 0.0 ),
mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveItemCommand( 0 ), mActiveMultiFrameCommand( 0 )
{
Expand Down Expand Up @@ -112,6 +120,10 @@ void QgsComposition::setNumPages( int pages )
mPages.removeLast();
}
}

// update the corresponding variable
QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )numPages() ) );

emit nPagesChanged();
}

Expand Down Expand Up @@ -146,6 +158,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;
Expand Down Expand Up @@ -300,7 +322,6 @@ bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc )
{
( *multiFrameIt )->writeXML( compositionElem, doc );
}

composerElem.appendChild( compositionElem );

return true;
Expand Down Expand Up @@ -344,6 +365,7 @@ bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocu
mPrintAsRaster = compositionElem.attribute( "printAsRaster" ).toInt();

mPrintResolution = compositionElem.attribute( "printResolution", "300" ).toInt();

updatePaperItems();
return true;
}
Expand Down Expand Up @@ -1273,6 +1295,7 @@ void QgsComposition::addComposerHtmlFrame( QgsComposerHtml* html, QgsComposerFra
void QgsComposition::removeComposerItem( QgsComposerItem* item, bool createCommand )
{
QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item );

if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
{
removeItem( item );
Expand Down Expand Up @@ -1453,6 +1476,8 @@ void QgsComposition::addPaperItem()
addItem( paperItem );
paperItem->setZValue( 0 );
mPages.push_back( paperItem );

QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )mPages.size() ) );
}

void QgsComposition::removePaperItems()
Expand All @@ -1462,6 +1487,7 @@ void QgsComposition::removePaperItems()
delete mPages.at( i );
}
mPages.clear();
QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )0 ) );
}

void QgsComposition::deleteAndRemoveMultiFrames()
Expand All @@ -1474,29 +1500,25 @@ void QgsComposition::deleteAndRemoveMultiFrames()
mMultiFrames.clear();
}

void QgsComposition::exportAsPDF( const QString& file )
void QgsComposition::beginPrintAsPDF( QPrinter& printer, const QString& file )
{
QPrinter printer;
printer.setOutputFormat( QPrinter::PdfFormat );
printer.setOutputFileName( file );
printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );

QgsPaintEngineHack::fixEngineFlags( printer.paintEngine() );
print( printer );
}

void QgsComposition::print( QPrinter &printer )
void QgsComposition::exportAsPDF( const QString& file )
{
//set resolution based on composer setting
printer.setFullPage( true );
printer.setColorMode( QPrinter::Color );

//set user-defined resolution
printer.setResolution( printResolution() );

QPainter p( &printer );
QPrinter printer;
beginPrintAsPDF( printer, file );
print( printer );
}

//QgsComposition starts page numbering at 0
void QgsComposition::doPrint( QPrinter& printer, QPainter& p )
{
//QgsComposition starts page numbering at 0
int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1 ;
int toPage = ( printer.toPage() < 1 ) ? numPages() - 1 : printer.toPage() - 1;

Expand Down Expand Up @@ -1531,6 +1553,23 @@ void QgsComposition::print( QPrinter &printer )
}
}

void QgsComposition::beginPrint( QPrinter &printer )
{
//set resolution based on composer setting
printer.setFullPage( true );
printer.setColorMode( QPrinter::Color );

//set user-defined resolution
printer.setResolution( printResolution() );
}

void QgsComposition::print( QPrinter &printer )
{
beginPrint( printer );
QPainter p( &printer );
doPrint( printer, p );
}

QImage QgsComposition::printPageAsRaster( int page )
{
//print out via QImage, code copied from on_mActionExportAsImage_activated
Expand Down Expand Up @@ -1587,3 +1626,14 @@ QString QgsComposition::encodeStringForXML( const QString& str )
modifiedStr.replace( ">", "&gt;" );
return modifiedStr;
}

#if 0
void QgsComposition::setAtlasComposerMap( QgsAtlasComposerMap* map )
{
if ( mAtlasComposerMap != 0 )
{
delete mAtlasComposerMap;
}
mAtlasComposerMap = map;
}
#endif
26 changes: 23 additions & 3 deletions src/core/composer/qgscomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
#ifndef QGSCOMPOSITION_H
#define QGSCOMPOSITION_H

#include <memory>

#include <QDomDocument>
#include <QGraphicsScene>
#include <QLinkedList>
#include <QSet>
#include <QUndoStack>
#include <QPrinter>
#include <QPainter>

#include "qgsaddremoveitemcommand.h"
#include "qgscomposeritemcommand.h"
Expand All @@ -44,6 +48,7 @@ class QgsComposerShape;
class QgsComposerAttributeTable;
class QgsComposerMultiFrame;
class QgsComposerMultiFrameCommand;
class QgsVectorLayer;

/** \ingroup MapComposer
* Graphics scene for map printing. The class manages the paper item which always
Expand Down Expand Up @@ -115,11 +120,17 @@ 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
@note not available in python bindings
*/
@note available in python bindings only with PyQt >= 4.8.4
*/
QList<const QgsComposerMap*> composerMapItems() const;

/**Return composer items of a specific type
Expand Down Expand Up @@ -271,10 +282,19 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene

//printing

void exportAsPDF( const QString& file );
/** Prepare the printer for printing */
void beginPrint( QPrinter& printer );
/** Prepare the printer for printing in a PDF */
void beginPrintAsPDF( QPrinter& printer, const QString& file );
/** Print on a preconfigured printer */
void doPrint( QPrinter& printer, QPainter& painter );

/** Convenience function that prepares the printer and prints */
void print( QPrinter &printer );

/** Convenience function that prepares the printer for printing in PDF and prints */
void exportAsPDF( const QString& file );

//! print composer page to image
//! If the image does not fit into memory, a null image is returned
QImage printPageAsRaster( int page );
Expand Down
116 changes: 107 additions & 9 deletions src/core/qgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,19 @@ static QVariant fcnFormatNumber( const QVariantList& values, QgsFeature*, QgsExp
return QString( "%L1" ).arg( value, 0, 'f', places );
}

static QVariant fcnFormatDate( const QVariantList& values, QgsFeature*, QgsExpression* parent )
{
QDateTime dt = getDateTimeValue( values.at( 0 ), parent );
QString format = getStringValue( values.at( 1 ), parent );
return dt.toString( format );
}

static QVariant fcnSpecialColumn( const QVariantList& values, QgsFeature* /*f*/, QgsExpression* parent )
{
QString varName = getStringValue( values.at( 0 ), parent );
return QgsExpression::specialColumn( varName );
}

QList<QgsExpression::FunctionDef> QgsExpression::gmBuiltinFunctions;

const QList<QgsExpression::FunctionDef> &QgsExpression::BuiltinFunctions()
Expand Down Expand Up @@ -855,6 +868,7 @@ const QList<QgsExpression::FunctionDef> &QgsExpression::BuiltinFunctions()
<< FunctionDef( "rpad", 3, fcnRPad, QObject::tr( "String" ) )
<< FunctionDef( "lpad", 3, fcnLPad, QObject::tr( "String" ) )
<< FunctionDef( "format_number", 2, fcnFormatNumber, QObject::tr( "String" ) )
<< FunctionDef( "format_date", 2, fcnFormatDate, QObject::tr( "String" ) )

// geometry accessors
<< FunctionDef( "xat", 1, fcnXat, QObject::tr( "Geometry" ), "", true )
Expand All @@ -868,12 +882,61 @@ const QList<QgsExpression::FunctionDef> &QgsExpression::BuiltinFunctions()
<< FunctionDef( "$rownum", 0, fcnRowNumber, QObject::tr( "Record" ) )
<< FunctionDef( "$id", 0, fcnFeatureId, QObject::tr( "Record" ) )
<< FunctionDef( "$scale", 0, fcnScale, QObject::tr( "Record" ) )
// private functions
<< FunctionDef( "_specialcol_", 1, fcnSpecialColumn, QObject::tr( "Special" ) )
;
}

return gmBuiltinFunctions;
}

QMap<QString, QVariant> QgsExpression::gmSpecialColumns;

void QgsExpression::setSpecialColumn( const QString& name, QVariant variant )
{
int fnIdx = functionIndex( name );
if ( fnIdx != -1 )
{
// function of the same name already exists
return;
}
gmSpecialColumns[ name ] = variant;
}

void QgsExpression::unsetSpecialColumn( const QString& name )
{
QMap<QString, QVariant>::iterator fit = gmSpecialColumns.find( name );
if ( fit != gmSpecialColumns.end() )
{
gmSpecialColumns.erase( fit );
}
}

QVariant QgsExpression::specialColumn( const QString& name )
{
int fnIdx = functionIndex( name );
if ( fnIdx != -1 )
{
// function of the same name already exists
return QVariant();
}
QMap<QString, QVariant>::iterator it = gmSpecialColumns.find( name );
if ( it == gmSpecialColumns.end() )
{
return QVariant();
}
return it.value();
}

QList<QgsExpression::FunctionDef> QgsExpression::specialColumns()
{
QList<FunctionDef> defs;
for ( QMap<QString, QVariant>::const_iterator it = gmSpecialColumns.begin(); it != gmSpecialColumns.end(); ++it )
{
defs << FunctionDef( it.key(), 0, 0, QObject::tr( "Record" ));
}
return defs;
}

bool QgsExpression::isFunctionName( QString name )
{
Expand Down Expand Up @@ -1049,12 +1112,27 @@ void QgsExpression::acceptVisitor( QgsExpression::Visitor& v )
mRootNode->accept( v );
}

QString QgsExpression::replaceExpressionText( QString action, QgsFeature &feat,
QString QgsExpression::replaceExpressionText( QString action, QgsFeature* feat,
QgsVectorLayer* layer,
const QMap<QString, QVariant> *substitutionMap )
{
QString expr_action;

QMap<QString, QVariant> savedValues;
if ( substitutionMap )
{
// variables with a local scope (must be restored after evaluation)
for ( QMap<QString, QVariant>::const_iterator sit = substitutionMap->begin(); sit != substitutionMap->end(); ++sit )
{
QVariant oldValue = QgsExpression::specialColumn( sit.key() );
if ( !oldValue.isNull() )
savedValues.insert( sit.key(), oldValue );

// set the new value
QgsExpression::setSpecialColumn( sit.key(), sit.value() );
}
}

int index = 0;
while ( index < action.size() )
{
Expand All @@ -1070,12 +1148,6 @@ QString QgsExpression::replaceExpressionText( QString action, QgsFeature &feat,
QString to_replace = rx.cap( 1 ).trimmed();
QgsDebugMsg( "Found expression: " + to_replace );

if ( substitutionMap && substitutionMap->contains( to_replace ) )
{
expr_action += action.mid( start, pos - start ) + substitutionMap->value( to_replace ).toString();
continue;
}

QgsExpression exp( to_replace );
if ( exp.hasParserError() )
{
Expand All @@ -1084,7 +1156,15 @@ QString QgsExpression::replaceExpressionText( QString action, QgsFeature &feat,
continue;
}

QVariant result = exp.evaluate( &feat, layer->pendingFields() );
QVariant result;
if ( layer )
{
result = exp.evaluate( feat, layer->pendingFields() );
}
else
{
result = exp.evaluate( feat );
}
if ( exp.hasEvalError() )
{
QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
Expand All @@ -1097,10 +1177,24 @@ QString QgsExpression::replaceExpressionText( QString action, QgsFeature &feat,
}

expr_action += action.mid( index );

// restore overwritten local values
for ( QMap<QString, QVariant>::const_iterator sit = savedValues.begin(); sit != savedValues.end(); ++sit )
{
QgsExpression::setSpecialColumn( sit.key(), sit.value() );
}

return expr_action;
}


QString QgsExpression::replaceExpressionText( QString action, QgsFeature& feat,
QgsVectorLayer* layer,
const QMap<QString, QVariant> *substitutionMap )
{
return replaceExpressionText( action, &feat, layer, substitutionMap );
}

QgsExpression::Node* QgsExpression::Node::createFromOgcFilter( QDomElement &element, QString &errorMessage )
{
if ( element.isNull() )
Expand Down Expand Up @@ -2048,7 +2142,11 @@ QgsExpression::Node* QgsExpression::NodeLiteral::createFromOgcFilter( QDomElemen

QVariant QgsExpression::NodeColumnRef::eval( QgsExpression* /*parent*/, QgsFeature* f )
{
return f->attributeMap()[mIndex];
if ( f )
{
return f->attributeMap()[mIndex];
}
return QVariant("[" + mName + "]");
}

bool QgsExpression::NodeColumnRef::prepare( QgsExpression* parent, const QgsFieldMap& fields )
Expand Down
20 changes: 19 additions & 1 deletion src/core/qgsexpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@ class CORE_EXPORT QgsExpression
//! Return the number used for $rownum special column
int currentRowNumber() { return mRowNumber; }

//! Assign a special column
static void setSpecialColumn( const QString& name, QVariant value );
//! Unset a special column
static void unsetSpecialColumn( const QString& name );
//! Return the value of the given special column or a null QVariant if undefined
static QVariant specialColumn( const QString& name );

void setScale( double scale ) { mScale = scale; }

int scale() {return mScale; }
Expand All @@ -140,10 +147,14 @@ class CORE_EXPORT QgsExpression
Additional substitutions can be passed through the substitutionMap
parameter
*/
static QString replaceExpressionText( QString action, QgsFeature &feat,
static QString replaceExpressionText( QString action, QgsFeature* feat,
QgsVectorLayer* layer,
const QMap<QString, QVariant> *substitutionMap = 0 );


static QString replaceExpressionText( QString action, QgsFeature& feat,
QgsVectorLayer* layer,
const QMap<QString, QVariant> *substitutionMap = 0 );
//

enum UnaryOperator
Expand Down Expand Up @@ -226,6 +237,11 @@ class CORE_EXPORT QgsExpression
*/
static int functionCount();

/**
* Returns a list of special Column definitions
*/
static QList<FunctionDef> specialColumns();

//! return quoted column reference (in double quotes)
static QString quotedColumnRef( QString name ) { return QString( "\"%1\"" ).arg( name.replace( "\"", "\"\"" ) ); }
//! return quoted string (in single quotes)
Expand Down Expand Up @@ -532,6 +548,8 @@ class CORE_EXPORT QgsExpression
int mRowNumber;
double mScale;

static QMap<QString, QVariant> gmSpecialColumns;

QgsDistanceArea* mCalc;
};

Expand Down
20 changes: 16 additions & 4 deletions src/core/qgsexpressionparser.yy
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,23 @@ expression:
int fnIndex = QgsExpression::functionIndex(*$1);
if (fnIndex == -1)
{
exp_error("Special column is not known");
YYERROR;
QVariant userVar = QgsExpression::specialColumn( *$1 );
if ( userVar.isNull() )
{
exp_error("Special column is not known");
YYERROR;
}
// $var is equivalent to _specialcol_( "$var" )
QgsExpression::NodeList* args = new QgsExpression::NodeList();
QgsExpression::NodeLiteral* literal = new QgsExpression::NodeLiteral( *$1 );
args->append( literal );
$$ = new QgsExpression::NodeFunction( QgsExpression::functionIndex( "_specialcol_" ), args );
}
$$ = new QgsExpression::NodeFunction( fnIndex, NULL );
delete $1;
else
{
$$ = new QgsExpression::NodeFunction( fnIndex, NULL );
delete $1;
}
}

// literals
Expand Down
14 changes: 7 additions & 7 deletions src/gui/qgscomposerview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,13 +311,13 @@ void QgsComposerView::mouseReleaseEvent( QMouseEvent* e )
}
if ( composition() )
{
QgsComposerMap* composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
composition()->addComposerMap( composerMap );
scene()->removeItem( mRubberBandItem );
delete mRubberBandItem;
mRubberBandItem = 0;
emit actionFinished();
composition()->pushAddRemoveCommand( composerMap, tr( "Map added" ) );
QgsComposerMap* composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
composition()->addComposerMap( composerMap );
scene()->removeItem( mRubberBandItem );
delete mRubberBandItem;
mRubberBandItem = 0;
emit actionFinished();
composition()->pushAddRemoveCommand( composerMap, tr( "Map added" ) );
}
break;

Expand Down
20 changes: 18 additions & 2 deletions src/gui/qgsexpressionbuilderwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,20 @@ QgsExpressionBuilderWidget::QgsExpressionBuilderWidget( QWidget *parent )
{
QgsExpression::FunctionDef func = QgsExpression::BuiltinFunctions()[i];
QString name = func.mName;
if ( name.startsWith( "_" ) ) // do not display private functions
continue;
if ( func.mParams >= 1 )
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
txtSearchEdit->setPlaceholderText( tr( "Search" ) );
#endif
Expand Down Expand Up @@ -259,8 +268,6 @@ void QgsExpressionBuilderWidget::on_txtExpressionString_textChanged()

QgsExpression exp( text );

// TODO We could do this without a layer.
// Maybe just calling exp.evaluate()?
if ( mLayer )
{
if ( !mFeature.isValid() )
Expand All @@ -282,6 +289,15 @@ void QgsExpressionBuilderWidget::on_txtExpressionString_textChanged()
lblPreview->setText( "" );
}
}
else
{
// No layer defined
QVariant value = exp.evaluate();
if ( !exp.hasEvalError() )
{
lblPreview->setText( value.toString() );
}
}

if ( exp.hasParserError() || exp.hasEvalError() )
{
Expand Down
198 changes: 198 additions & 0 deletions src/ui/qgsatlascompositionwidgetbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsAtlasCompositionWidgetBase</class>
<widget class="QWidget" name="QgsAtlasCompositionWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>501</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Atlas generation</string>
</property>
<layout class="QGridLayout" name="gridLayout_8">
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="lineWidth">
<number>0</number>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_4">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>470</height>
</rect>
</property>
<attribute name="label">
<string>Atlas options</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_9">
<item row="2" column="0">
<widget class="QFrame" name="mAtlasFrame">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout_7" rowstretch="0,0,0,0,0,0,0,0,0" columnstretch="0,0,0">
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="mAtlasHideCoverageCheckBox">
<property name="toolTip">
<string>Hide the coverage layer when generating the output</string>
</property>
<property name="text">
<string>Hidden coverage layer</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Margin around coverage</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Output filename expression</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="mAtlasMarginSpinBox">
<property name="suffix">
<string> %</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QToolButton" name="mAtlasFilenameExpressionButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="mAtlasFilenamePatternEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Coverage layer</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mAtlasCoverageLayerComboBox">
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mAtlasFixedScaleCheckBox">
<property name="text">
<string>Fixed scale</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QCheckBox" name="mAtlasSingleFileCheckBox">
<property name="text">
<string>Single file export when possible</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mComposerMapComboBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Composer map to use</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="5" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>76</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="mUseAtlasCheckBox">
<property name="text">
<string>Generate an atlas</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
29 changes: 18 additions & 11 deletions src/ui/qgscomposerlabelwidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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">
Expand All @@ -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>
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand All @@ -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">
Expand All @@ -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">
Expand All @@ -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>
Expand Down
10 changes: 5 additions & 5 deletions src/ui/qgscomposerlegendwidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-109</y>
<width>370</width>
<height>523</height>
<y>0</y>
<width>374</width>
<height>549</height>
</rect>
</property>
<attribute name="label">
Expand Down Expand Up @@ -220,8 +220,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>367</width>
<height>170</height>
<width>393</width>
<height>162</height>
</rect>
</property>
<attribute name="label">
Expand Down
125 changes: 64 additions & 61 deletions src/ui/qgscomposermapwidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>265</width>
<height>483</height>
<width>450</width>
<height>501</height>
</rect>
</property>
<property name="sizePolicy">
Expand All @@ -25,6 +25,9 @@
</property>
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="lineWidth">
<number>0</number>
</property>
<property name="currentIndex">
<number>0</number>
</property>
Expand All @@ -33,15 +36,44 @@
<rect>
<x>0</x>
<y>0</y>
<width>255</width>
<height>392</height>
<width>450</width>
<height>408</height>
</rect>
</property>
<attribute name="label">
<string>Map</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="7" column="0" colspan="2">
<item row="7" column="1">
<widget class="QComboBox" name="mOverviewFrameMapComboBox"/>
</item>
<item row="4" column="0">
<widget class="QComboBox" name="mPreviewModeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="9" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
Expand All @@ -57,24 +89,35 @@
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QComboBox" name="mPreviewModeComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="4" column="1">
<widget class="QPushButton" name="mUpdatePreviewButton">
<property name="text">
<string>Update preview</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="mUpdatePreviewButton">
<item row="8" column="0">
<widget class="QLabel" name="mOverviewFrameStyleLabel">
<property name="text">
<string>Update preview</string>
<string>Overview style</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QPushButton" name="mOverviewFrameStyleButton">
<property name="text">
<string>Change...</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="mOverviewFrameMapLabel">
<property name="text">
<string>Overview frame</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
Expand Down Expand Up @@ -188,23 +231,7 @@
</item>
</layout>
</item>
<item row="0" column="0" colspan="2">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
Expand All @@ -220,39 +247,15 @@
</property>
</spacer>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="mOverviewFrameMapComboBox"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="mOverviewFrameMapLabel">
<property name="text">
<string>Overview frame</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="mOverviewFrameStyleLabel">
<property name="text">
<string>Overview style</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QPushButton" name="mOverviewFrameStyleButton">
<property name="text">
<string>Change...</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>255</width>
<height>392</height>
<width>199</width>
<height>177</height>
</rect>
</property>
<attribute name="label">
Expand Down Expand Up @@ -359,8 +362,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>238</width>
<height>770</height>
<width>277</width>
<height>921</height>
</rect>
</property>
<attribute name="label">
Expand Down
2 changes: 2 additions & 0 deletions tests/src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ ADD_QGIS_TEST(rulebasedrenderertest testqgsrulebasedrenderer.cpp)
ADD_QGIS_TEST(ziplayertest testziplayer.cpp)
ADD_QGIS_TEST(dataitemtest testqgsdataitem.cpp)
ADD_QGIS_TEST(composermaptest testqgscomposermap.cpp)
ADD_QGIS_TEST(atlascompositiontest testqgsatlascomposition.cpp)
ADD_QGIS_TEST(composerlabeltest testqgscomposerlabel.cpp)
ADD_QGIS_TEST(stylev2test testqgsstylev2.cpp)
#ADD_QGIS_TEST(composerhtmltest testqgscomposerhtml.cpp )
ADD_QGIS_TEST(rectangletest testqgsrectangle.cpp)
Expand Down
227 changes: 227 additions & 0 deletions tests/src/core/testqgsatlascomposition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/***************************************************************************
testqgsatlascomposition.cpp
---------------------------
begin : Sept 2012
copyright : (C) 2012 by Hugo Mercier
email : hugo dot mercier at oslandia 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 "qgscomposition.h"
#include "qgscompositionchecker.h"
#include "qgscomposermap.h"
#include "qgsatlascomposition.h"
#include "qgscomposerlabel.h"
#include "qgsmaplayerregistry.h"
#include "qgsmaprenderer.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgssymbolv2.h"
#include "qgssinglesymbolrendererv2.h"
#include <QObject>
#include <QtTest>

class TestQgsAtlasComposition: public QObject
{
Q_OBJECT;
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 filename pattern evaluation
void filename();
// test rendering with an autoscale atlas
void autoscale_render();
// test rendering with a fixed scale atlas
void fixedscale_render();
// test rendering with a hidden coverage
void hiding_render();
private:
QgsComposition* mComposition;
QgsComposerLabel* mLabel1;
QgsComposerLabel* mLabel2;
QgsComposerMap* mAtlasMap;
QgsComposerMap* mOverview;
QgsMapRenderer* mMapRenderer;
QgsVectorLayer* mVectorLayer;
QgsAtlasComposition* mAtlas;
};

void TestQgsAtlasComposition::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();

//create maplayers from testdata and add to layer registry
QFileInfo vectorFileInfo( QString( TEST_DATA_DIR ) + QDir::separator() + "france_parts.shp" );
mVectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
"ogr" );

QgsMapLayerRegistry::instance()->addMapLayers( QList<QgsMapLayer*>() << mVectorLayer );

//create composition with composer map
mMapRenderer = new QgsMapRenderer();
mMapRenderer->setLayerSet( QStringList() << mVectorLayer->id() );
mMapRenderer->setProjectionsEnabled( true );

// select epsg:2154
QgsCoordinateReferenceSystem crs;
crs.createFromSrid( 2154 );
mMapRenderer->setDestinationCrs( crs );
mComposition = new QgsComposition( mMapRenderer );
mComposition->setPaperSize( 297, 210 ); //A4 landscape

// fix the renderer, fill with green
QgsStringMap props;
props.insert( "color", "0,127,0" );
QgsFillSymbolV2* fillSymbol = QgsFillSymbolV2::createSimple( props );
QgsSingleSymbolRendererV2* renderer = new QgsSingleSymbolRendererV2( fillSymbol );
mVectorLayer->setRendererV2( renderer );

// the atlas map
mAtlasMap = new QgsComposerMap( mComposition, 20, 20, 130, 130 );
mAtlasMap->setFrameEnabled( true );
mComposition->addComposerMap( mAtlasMap );

mAtlas = new QgsAtlasComposition( mComposition );
mAtlas->setCoverageLayer( mVectorLayer );
mAtlas->setComposerMap( mAtlasMap );

// an overview
mOverview = new QgsComposerMap( mComposition, 180, 20, 50, 50 );
mOverview->setFrameEnabled( true );
mOverview->setOverviewFrameMap( mAtlasMap->id() );
mComposition->addComposerMap( mOverview );
mOverview->setNewExtent( QgsRectangle( 49670.718, 6415139.086, 699672.519, 7065140.887 ) );

// set the fill symbol of the overview map
QgsStringMap props2;
props2.insert( "color", "127,0,0,127" );
QgsFillSymbolV2* fillSymbol2 = QgsFillSymbolV2::createSimple( props2 );
mOverview->setOverviewFrameMapSymbol( fillSymbol2 );

// header label
mLabel1 = new QgsComposerLabel( mComposition );
mComposition->addComposerLabel( mLabel1 );
mLabel1->setText( "[% \"NAME_1\" %] area" );
mLabel1->adjustSizeToText();
mLabel1->setItemPosition( 150, 5 );

// feature number label
mLabel2 = new QgsComposerLabel( mComposition );
mComposition->addComposerLabel( mLabel2 );
mLabel2->setText( "# [%$feature || ' / ' || $numfeatures%]" );
mLabel2->adjustSizeToText();
mLabel2->setItemPosition( 150, 200 );
}

void TestQgsAtlasComposition::cleanupTestCase()
{
delete mComposition;
delete mMapRenderer;
delete mVectorLayer;
}

void TestQgsAtlasComposition::init()
{

}

void TestQgsAtlasComposition::cleanup()
{

}

void TestQgsAtlasComposition::filename()
{
mAtlas->setFilenamePattern( "'output_' || $feature" );
mAtlas->beginRender();
for ( size_t fi = 0; fi < mAtlas->numFeatures(); ++fi )
{
mAtlas->prepareForFeature( fi );
QString expected = QString( "output_%1" ).arg( (int)(fi+1) );
QCOMPARE( mAtlas->currentFilename(), expected );
}
mAtlas->endRender();
}


void TestQgsAtlasComposition::autoscale_render()
{
mAtlas->setFixedScale( false );
mAtlas->setMargin( 0.10 );

mAtlas->beginRender();

for ( size_t fit = 0; fit < 2; ++fit )
{
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();

QgsCompositionChecker checker( "Atlas autoscale test", mComposition,
QString( TEST_DATA_DIR ) + QDir::separator() + "control_images" + QDir::separator() +
"expected_composermapatlas" + QDir::separator() +
QString( "autoscale_%1.png" ).arg((int)fit) );
QVERIFY( checker.testComposition( 0 ) );
}
mAtlas->endRender();
}

void TestQgsAtlasComposition::fixedscale_render()
{
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setFixedScale( true );

mAtlas->beginRender();

for ( size_t fit = 0; fit < 2; ++fit )
{
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();

QgsCompositionChecker checker( "Atlas fixedscale test", mComposition,
QString( TEST_DATA_DIR ) + QDir::separator() + "control_images" + QDir::separator() +
"expected_composermapatlas" + QDir::separator() +
QString( "fixedscale_%1.png" ).arg((int)fit) );
QVERIFY( checker.testComposition( 0 ) );
}
mAtlas->endRender();

}

void TestQgsAtlasComposition::hiding_render()
{
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setFixedScale( true );
mAtlas->setHideCoverage( true );

mAtlas->beginRender();

for ( size_t fit = 0; fit < 2; ++fit )
{
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();

QgsCompositionChecker checker( "Atlas hidden test", mComposition,
QString( TEST_DATA_DIR ) + QDir::separator() + "control_images" + QDir::separator() +
"expected_composermapatlas" + QDir::separator() +
QString( "hiding_%1.png" ).arg((int)fit) );
QVERIFY( checker.testComposition( 0 ) );
}
mAtlas->endRender();
}

QTEST_MAIN( TestQgsAtlasComposition )
#include "moc_testqgsatlascomposition.cxx"
181 changes: 181 additions & 0 deletions tests/src/core/testqgscomposerlabel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/***************************************************************************
testqgscomposerlabel.cpp
----------------------
begin : Sept 2012
copyright : (C) 2012 by Hugo Mercier
email : hugo dot mercier at oslandia 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 "qgscomposition.h"
#include "qgscomposerlabel.h"
#include "qgsmaplayerregistry.h"
#include "qgsmaprenderer.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include <QObject>
#include <QtTest>

class TestQgsComposerLabel: public QObject
{
Q_OBJECT;
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();
private:
QgsComposition* mComposition;
QgsComposerLabel* mComposerLabel;
QgsMapRenderer* mMapRenderer;
QgsVectorLayer* mVectorLayer;
};

void TestQgsComposerLabel::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();

//create maplayers from testdata and add to layer registry
QFileInfo vectorFileInfo( QString( TEST_DATA_DIR ) + QDir::separator() + "france_parts.shp" );
mVectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
"ogr" );
QgsMapLayerRegistry::instance()->addMapLayers( QList<QgsMapLayer*>() << mVectorLayer );

//create composition with composer map
mMapRenderer = new QgsMapRenderer();
mMapRenderer->setLayerSet( QStringList() << mVectorLayer->id() );
mMapRenderer->setProjectionsEnabled( false );
mComposition = new QgsComposition( mMapRenderer );
mComposition->setPaperSize( 297, 210 ); //A4 landscape

mComposerLabel = new QgsComposerLabel( mComposition );
mComposition->addComposerLabel( mComposerLabel );
}

void TestQgsComposerLabel::cleanupTestCase()
{
delete mComposition;
delete mMapRenderer;
delete mVectorLayer;
}

void TestQgsComposerLabel::init()
{

}

void TestQgsComposerLabel::cleanup()
{

}

void TestQgsComposerLabel::evaluation()
{
{
// $CURRENT_DATE evaluation
QString expected = "__" + QDate::currentDate().toString() + "__";
mComposerLabel->setText( "__$CURRENT_DATE__" );
QString evaluated = mComposerLabel->displayText();
QCOMPARE( evaluated, expected );
}
{
// $CURRENT_DATE() evaluation
QDateTime now = QDateTime::currentDateTime();
QString expected = "__" + now.toString( "dd" ) + "(ok)__";
mComposerLabel->setText( "__$CURRENT_DATE(dd)(ok)__" );
QString evaluated = mComposerLabel->displayText();
QCOMPARE( evaluated, expected );
}
{
// $CURRENT_DATE() evaluation (inside an expression)
QDate now = QDate::currentDate();
int dd = now.day();

QString expected = "__" + QString("%1").arg(dd+1) + "(ok)__";
mComposerLabel->setText( "__[%$CURRENT_DATE(dd) + 1%](ok)__" );
QString evaluated = mComposerLabel->displayText();
QCOMPARE( evaluated, expected );
}
{
// expression evaluation (without feature)
QString expected = "__[NAME_1]42__";
mComposerLabel->setText( "__[%\"NAME_1\"%][%21*2%]__" );
QString evaluated = mComposerLabel->displayText();
QCOMPARE( evaluated, expected );
}
}

void TestQgsComposerLabel::feature_evaluation()
{
QgsVectorDataProvider* provider = mVectorLayer->dataProvider();

QgsAttributeList allAttrs = provider->attributeIndexes();
provider->select( allAttrs );
QgsFeature feat;

provider->nextFeature( feat );
{
// evaluation with a feature
mComposerLabel->setExpressionContext( &feat, mVectorLayer );
mComposerLabel->setText( "[%\"NAME_1\"||'_ok'%]" );
QString evaluated = mComposerLabel->displayText();
QString expected = "Basse-Normandie_ok";
QCOMPARE( evaluated, expected );
}
provider->nextFeature( feat );
{
// evaluation with a feature
mComposerLabel->setExpressionContext( &feat, mVectorLayer );
mComposerLabel->setText( "[%\"NAME_1\"||'_ok'%]" );
QString evaluated = mComposerLabel->displayText();
QString expected = "Bretagne_ok";
QCOMPARE( evaluated, expected );
}
{
// evaluation with a feature and local variables
QMap<QString, QVariant> locals;
locals.insert( "$test", "OK" );

mComposerLabel->setExpressionContext( &feat, mVectorLayer, locals );
mComposerLabel->setText( "[%\"NAME_1\"||$test%]" );
QString evaluated = mComposerLabel->displayText();
QString expected = "BretagneOK";
QCOMPARE( evaluated, expected );
}
}

void TestQgsComposerLabel::page_evaluation()
{
mComposition->setNumPages( 2 );
{
mComposerLabel->setText( "[%$page||'/'||$numpages%]" );
QString evaluated = mComposerLabel->displayText();
QString expected = "1/2";
QCOMPARE( evaluated, expected );

// move to the second page and re-evaluate
mComposerLabel->setItemPosition( 0, 320 );
QCOMPARE( mComposerLabel->displayText(), QString("2/2") );
}
}

QTEST_MAIN( TestQgsComposerLabel )
#include "moc_testqgscomposerlabel.cxx"
27 changes: 27 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,33 @@ class TestQgsExpression: public QObject
QVariant vPerimeter = exp3.evaluate( &fPolygon );
QCOMPARE( vPerimeter.toDouble(), 20. );
}

void eval_special_columns()
{
QTest::addColumn<QString>( "string" );
QTest::addColumn<QVariant>( "result" );

QgsExpression::setSpecialColumn( "$var1", QVariant((int)42) );

QgsExpression exp( "$var1 + 1" );
QVariant v1 = exp.evaluate();
QCOMPARE( v1.toInt(), 43 );

QgsExpression::setSpecialColumn( "$var1", QVariant((int)100) );
QVariant v2 = exp.evaluate();
QCOMPARE( v2.toInt(), 101 );

QgsExpression exp2( "_specialcol_('$var1')+1" );
QVariant v3 = exp2.evaluate();
QCOMPARE( v3.toInt(), 101 );

QgsExpression exp3( "_specialcol_('undefined')");
QVariant v4 = exp3.evaluate();
QCOMPARE( v4, QVariant() );

QgsExpression::unsetSpecialColumn( "$var1" );
}

};

QTEST_MAIN( TestQgsExpression )
Expand Down
2 changes: 2 additions & 0 deletions tests/src/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ ADD_PYTHON_TEST(PyQgsAnalysis test_qgsanalysis.py)
ADD_PYTHON_TEST(PyQgsComposerMap test_qgscomposermap.py)
ADD_PYTHON_TEST(PyQgsSymbolLayerV2 test_qgssymbollayerv2.py)
ADD_PYTHON_TEST(PyQgsPoint test_qgspoint.py)
ADD_PYTHON_TEST(PyQgsAtlasComposition test_qgsatlascomposition.py)
ADD_PYTHON_TEST(PyQgsComposerLabel test_qgscomposerlabel.py)
169 changes: 169 additions & 0 deletions tests/src/python/test_qgsatlascomposition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# -*- coding: utf-8 -*-
'''
test_qgsatlascomposition.py
--------------------------------------
Date : Oct 2012
Copyright : (C) 2012 by Dr. Hugo Mercier
email : hugo dot mercier at oslandia 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. *
* *
***************************************************************************/
'''
import unittest
from utilities import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtXml import *
from qgis.core import *
from qgscompositionchecker import QgsCompositionChecker

QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()

class TestQgsAtlasComposition(unittest.TestCase):

def testCase(self):
self.TEST_DATA_DIR = unitTestDataPath()
vectorFileInfo = QFileInfo( self.TEST_DATA_DIR + QDir().separator().toAscii() + "france_parts.shp")
mVectorLayer = QgsVectorLayer( vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" )

QgsMapLayerRegistry.instance().addMapLayer( mVectorLayer )

# create composition with composer map
mMapRenderer = QgsMapRenderer()
layerStringList = QStringList()
layerStringList.append( mVectorLayer.id() )
mMapRenderer.setLayerSet( layerStringList )
mMapRenderer.setProjectionsEnabled( True )

# select epsg:2154
crs = QgsCoordinateReferenceSystem()
crs.createFromSrid( 2154 )
mMapRenderer.setDestinationCrs( crs )

self.mComposition = QgsComposition( mMapRenderer )
self.mComposition.setPaperSize( 297, 210 )

# fix the renderer, fill with green
props = { "color": "0,127,0" }
fillSymbol = QgsFillSymbolV2.createSimple( props )
renderer = QgsSingleSymbolRendererV2( fillSymbol )
mVectorLayer.setRendererV2( renderer )

# the atlas map
self.mAtlasMap = QgsComposerMap( self.mComposition, 20, 20, 130, 130 )
self.mAtlasMap.setFrameEnabled( True )
self.mComposition.addComposerMap( self.mAtlasMap )

# the atlas
self.mAtlas = QgsAtlasComposition( self.mComposition )
self.mAtlas.setCoverageLayer( mVectorLayer )
self.mAtlas.setComposerMap( self.mAtlasMap )

# an overview
mOverview = QgsComposerMap( self.mComposition, 180, 20, 50, 50 )
mOverview.setFrameEnabled( True )
mOverview.setOverviewFrameMap( self.mAtlasMap.id() )
self.mComposition.addComposerMap( mOverview )
nextent = QgsRectangle( 49670.718, 6415139.086, 699672.519, 7065140.887 )
mOverview.setNewExtent( nextent )

# set the fill symbol of the overview map
props2 = { "color": "127,0,0,127" }
fillSymbol2 = QgsFillSymbolV2.createSimple( props2 )
mOverview.setOverviewFrameMapSymbol( fillSymbol2 );

# header label
self.mLabel1 = QgsComposerLabel( self.mComposition )
self.mComposition.addComposerLabel( self.mLabel1 )
self.mLabel1.setText( "[% \"NAME_1\" %] area" )
self.mLabel1.adjustSizeToText()
self.mLabel1.setItemPosition( 150, 5 )

# feature number label
self.mLabel2 = QgsComposerLabel( self.mComposition )
self.mComposition.addComposerLabel( self.mLabel2 )
self.mLabel2.setText( "# [%$feature || ' / ' || $numfeatures%]" )
self.mLabel2.adjustSizeToText()
self.mLabel2.setItemPosition( 150, 200 )

self.filename_test()
self.autoscale_render_test()
self.fixedscale_render_test()
self.hidden_render_test()

def filename_test( self ):

self.mAtlas.setFilenamePattern( "'output_' || $feature" )
self.mAtlas.beginRender()
for i in range(0, self.mAtlas.numFeatures()):
self.mAtlas.prepareForFeature( i )
expected = QString( "output_%1" ).arg(i+1)
assert self.mAtlas.currentFilename() == expected
self.mAtlas.endRender()

def autoscale_render_test( self ):
self.mAtlas.setFixedScale( False )
self.mAtlas.setMargin( 0.10 )

self.mAtlas.beginRender()

for i in range(0, 2):
self.mAtlas.prepareForFeature( i )
self.mLabel1.adjustSizeToText()

checker = QgsCompositionChecker()
res = checker.testComposition( "Atlas autoscale test", self.mComposition, \
QString( self.TEST_DATA_DIR ) + QDir.separator() + \
"control_images" + QDir.separator() + \
"expected_composermapatlas" + QDir.separator() + \
QString( "autoscale_%1.png" ).arg( i ) )
assert res[0] == True
self.mAtlas.endRender()

def fixedscale_render_test( self ):
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.setFixedScale( True )

self.mAtlas.beginRender()

for i in range(0, 2):
self.mAtlas.prepareForFeature( i )
self.mLabel1.adjustSizeToText()

checker = QgsCompositionChecker()
res = checker.testComposition( "Atlas fixed scale test", self.mComposition, \
QString( self.TEST_DATA_DIR ) + QDir.separator() + \
"control_images" + QDir.separator() + \
"expected_composermapatlas" + QDir.separator() + \
QString( "fixedscale_%1.png" ).arg( i ) )
assert res[0] == True
self.mAtlas.endRender()

def hidden_render_test( self ):
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.setFixedScale( True )
self.mAtlas.setHideCoverage( True )

self.mAtlas.beginRender()

for i in range(0, 2):
self.mAtlas.prepareForFeature( i )
self.mLabel1.adjustSizeToText()

checker = QgsCompositionChecker()
res = checker.testComposition( "Atlas hidden test", self.mComposition, \
QString( self.TEST_DATA_DIR ) + QDir.separator() + \
"control_images" + QDir.separator() + \
"expected_composermapatlas" + QDir.separator() + \
QString( "hiding_%1.png" ).arg( i ) )
assert res[0] == True
self.mAtlas.endRender()

if __name__ == '__main__':
unittest.main()

Loading