121 changes: 71 additions & 50 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 @@ -308,6 +309,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 @@ -338,6 +342,7 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
QDockWidget* mItemDock;
QDockWidget* mUndoDock;
QDockWidget* mGeneralDock;
QDockWidget* mAtlasDock;

QMenu* mPanelMenu;
QMenu* mToolbarMenu;
Expand Down
195 changes: 0 additions & 195 deletions src/app/composer/qgscomposermapwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,29 +416,6 @@ void QgsComposerMapWidget::updateGuiElements()
mLineWidthSpinBox->setValue( gridPen.widthF() );
mLineColorButton->setColor( gridPen.color() );

// special processing for atlas
QgsComposition* composition = mComposerMap->composition();
if ( composition->atlasMap() && composition->atlasMap() == mComposerMap )
{
mIsAtlasCheckBox->setCheckState( Qt::Checked );

int idx = mAtlasCoverageLayerComboBox->findData( qVariantFromValue( (void*)mComposerMap->atlasCoverageLayer() ));
if ( idx != -1 )
{
mAtlasCoverageLayerComboBox->setCurrentIndex( idx );
}

mAtlasMarginSpinBox->setValue( static_cast<int>(mComposerMap->atlasMargin() * 100) );
mAtlasFilenamePatternEdit->setText( mComposerMap->atlasFilenamePattern() );
mAtlasFixedScaleCheckBox->setCheckState( mComposerMap->atlasFixedScale() ? Qt::Checked : Qt::Unchecked );
mAtlasHideCoverageCheckBox->setCheckState( mComposerMap->atlasHideCoverage() ? Qt::Checked : Qt::Unchecked );
mAtlasSingleFileCheckBox->setCheckState( mComposerMap->atlasSingleFile() ? Qt::Checked : Qt::Unchecked );
}
else
{
mIsAtlasCheckBox->setCheckState( Qt::Unchecked );
}

blockAllSignals( false );
}
}
Expand Down Expand Up @@ -927,178 +904,6 @@ void QgsComposerMapWidget::on_mFrameWidthSpinBox_valueChanged( double d )
}
}

void QgsComposerMapWidget::on_mIsAtlasCheckBox_stateChanged( int state )
{
if ( !mComposerMap )
{
return;
}

QgsComposition* composition = mComposerMap->composition();
if ( state == Qt::Checked )
{
if ( composition->atlasMap() != 0 && composition->atlasMap() != mComposerMap )
{
QMessageBox msgBox;
msgBox.setText(tr("An atlas map already exists."));
msgBox.setInformativeText("Are you sure to define this map as the new atlas map ?");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No );
msgBox.setDefaultButton(QMessageBox::No);
if ( msgBox.exec() != QMessageBox::Yes )
{
mIsAtlasCheckBox->setCheckState( Qt::Unchecked );
return;
}
}
composition->setAtlasMap( mComposerMap );

// repopulate 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* ) ) );
}

mAtlasFrame->setEnabled( true );
updateGuiElements();
}
else
{
mAtlasFrame->setEnabled( false );

// If the current atlas map was this one and a uncheck is requested, set the atlas map to null
if ( composition->atlasMap() == mComposerMap )
{
composition->setAtlasMap( 0 );

QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance();
if ( layerRegistry )
{
disconnect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( onLayerRemoved( QString ) ) );
disconnect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerAdded( QgsMapLayer* ) ) );
}
}
}
}

void QgsComposerMapWidget::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;
}
}
}

void QgsComposerMapWidget::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 ) );
}
}

void QgsComposerMapWidget::on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index )
{
if ( !mComposerMap )
{
return;
}

QgsVectorLayer* layer = reinterpret_cast<QgsVectorLayer*>(mAtlasCoverageLayerComboBox->itemData( index ).value<void*>());
mComposerMap->setAtlasCoverageLayer( layer );
}

void QgsComposerMapWidget::on_mAtlasFilenamePatternEdit_textChanged( const QString& text )
{
if ( !mComposerMap )
{
return;
}

mComposerMap->setAtlasFilenamePattern( text );
}

void QgsComposerMapWidget::on_mAtlasFilenameExpressionButton_clicked()
{
if ( !mComposerMap )
{
return;
}
if ( !mComposerMap->atlasCoverageLayer() )
{
return;
}
QgsExpressionBuilderDialog exprDlg( mComposerMap->atlasCoverageLayer(), 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 QgsComposerMapWidget::on_mAtlasHideCoverageCheckBox_stateChanged( int state )
{
if (!mComposerMap)
{
return;
}
mComposerMap->setAtlasHideCoverage( state == Qt::Checked );
}

void QgsComposerMapWidget::on_mAtlasFixedScaleCheckBox_stateChanged( int state )
{
if (!mComposerMap)
{
return;
}
mComposerMap->setAtlasFixedScale( state == Qt::Checked );

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

void QgsComposerMapWidget::on_mAtlasSingleFileCheckBox_stateChanged( int state )
{
if (!mComposerMap)
{
return;
}
mComposerMap->setAtlasSingleFile( state == Qt::Checked );
}

void QgsComposerMapWidget::showEvent( QShowEvent * event )
{
refreshMapComboBox();
Expand Down
12 changes: 0 additions & 12 deletions src/app/composer/qgscomposermapwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,6 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
void on_mFrameStyleComboBox_currentIndexChanged( const QString& text );
void on_mFrameWidthSpinBox_valueChanged( double d );

void on_mIsAtlasCheckBox_stateChanged( int state );
void on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index );
void on_mAtlasFilenamePatternEdit_textChanged( const QString& );
void on_mAtlasFilenameExpressionButton_clicked();
void on_mAtlasHideCoverageCheckBox_stateChanged( int state );
void on_mAtlasFixedScaleCheckBox_stateChanged( int state );
void on_mAtlasSingleFileCheckBox_stateChanged( int state );

protected:
void showEvent( QShowEvent * event );

Expand All @@ -105,10 +97,6 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
/**Sets the GUI elements to the values of mPicture*/
void setGuiElementValues();

/** Updates atlas' coverage layer combobox on layer addition / removal */
void onLayerRemoved( QString );
void onLayerAdded( QgsMapLayer* );

private:
QgsComposerMap* mComposerMap;

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
328 changes: 328 additions & 0 deletions src/core/composer/qgsatlascomposition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,328 @@
/***************************************************************************
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;

// 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() );

// features must be stored in a list, since modifying the layer's extent rewinds nextFeature()
mFeatures.clear();
QgsFeature feature;
while ( provider->nextFeature( feature ) )
{
mFeatures.push_back( feature );
}

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 )mFeatures.size() ) );
}

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
{
return mFeatures.size();
}

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

QgsFeature* fit = &mFeatures[featureI];

if ( mFilenamePattern.size() > 0 )
{
QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) );
QVariant filenameRes = mFilenameExpr->evaluate( &*fit );
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( *fit->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( fit, 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();
}
115 changes: 115 additions & 0 deletions src/core/composer/qgsatlascomposition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/***************************************************************************
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<QgsFeature> mFeatures;
QgsRectangle mOrigExtent;
bool mRestoreLayer;
std::auto_ptr<QgsExpression> mFilenameExpr;
};

#endif



69 changes: 2 additions & 67 deletions src/core/composer/qgscomposermap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w
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 ),
mAtlasHideCoverage( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 ), mAtlasFilenamePattern("'output_'||$feature"), mAtlasCoverageLayer(0), mAtlasSingleFile( false )
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true )
{
mComposition = composition;
mOverviewFrameMapSymbol = 0;
Expand Down Expand Up @@ -86,8 +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 ),
mAtlasHideCoverage( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 ), mAtlasFilenamePattern("'output_'||$feature"), mAtlasCoverageLayer(0), mAtlasSingleFile( false )
mMapCanvas( 0 ), mDrawCanvasItems( true )
{
mOverviewFrameMapSymbol = 0;
createDefaultOverviewFrameSymbol();
Expand Down Expand Up @@ -620,26 +618,10 @@ void QgsComposerMap::connectUpdateSlot()
if ( layerRegistry )
{
connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( updateCachedImage() ) );
connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( syncAtlasCoverageLayer( QString ) ) );
connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( updateCachedImage() ) );
}
}

void QgsComposerMap::syncAtlasCoverageLayer( QString lname )
{
if ( mAtlasCoverageLayer && mAtlasCoverageLayer->id() == lname )
{
mAtlasCoverageLayer = 0;
}
}

void QgsComposerMap::setAtlasCoverageLayer( QgsVectorLayer* map )
{
mAtlasCoverageLayer = map;

emit atlasCoverageLayerChanged( map );
}

bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
{
if ( elem.isNull() )
Expand Down Expand Up @@ -747,27 +729,6 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
gridElem.appendChild( annotationElem );
composerMapElem.appendChild( gridElem );

// atlas
if ( mComposition->atlasMap() == this )
{
QDomElement atlasElem = doc.createElement( "Atlas" );
if ( mAtlasCoverageLayer )
{
atlasElem.setAttribute( "coverageLayer", mAtlasCoverageLayer->id() );
}
else
{
atlasElem.setAttribute( "coverageLayer", "" );
}
atlasElem.setAttribute( "hideCoverage", mAtlasHideCoverage ? "true" : "false" );
atlasElem.setAttribute( "fixedScale", mAtlasFixedScale ? "true" : "false" );
atlasElem.setAttribute( "singleFile", mAtlasSingleFile ? "true" : "false" );
atlasElem.setAttribute( "margin", QString::number(mAtlasMargin) );
atlasElem.setAttribute( "filenamePattern", mAtlasFilenamePattern );

composerMapElem.appendChild( atlasElem );
}

elem.appendChild( composerMapElem );
return _writeXML( composerMapElem, doc );
}
Expand Down Expand Up @@ -905,32 +866,6 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d
}
}

// atlas
QDomNodeList atlasNodeList = itemElem.elementsByTagName( "Atlas" );
if ( atlasNodeList.size() > 0 )
{
mComposition->setAtlasMap( this );

QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();

// look for stored layer name
mAtlasCoverageLayer = 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") )
{
mAtlasCoverageLayer = dynamic_cast<QgsVectorLayer*>(it.value());
break;
}
}
mAtlasMargin = atlasElem.attribute( "margin", "0.0" ).toDouble();
mAtlasHideCoverage = atlasElem.attribute( "hideCoverage", "false" ) == "true" ? true : false;
mAtlasFixedScale = atlasElem.attribute( "fixedScale", "false" ) == "true" ? true : false;
mAtlasSingleFile = atlasElem.attribute( "singleFile", "false" ) == "true" ? true : false;
mAtlasFilenamePattern = atlasElem.attribute( "filenamePattern", "" );
}

//restore general composer item properties
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( composerItemList.size() > 0 )
Expand Down
28 changes: 0 additions & 28 deletions src/core/composer/qgscomposermap.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,24 +317,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
Usually, this function is called before adding the composer map to the composition*/
void assignFreeId();

bool atlasHideCoverage() const { return mAtlasHideCoverage; }
void setAtlasHideCoverage( bool hide ) { mAtlasHideCoverage = hide; }

bool atlasFixedScale() const { return mAtlasFixedScale; }
void setAtlasFixedScale( bool fixed ) { mAtlasFixedScale = fixed; }

float atlasMargin() const { return mAtlasMargin; }
void setAtlasMargin( float margin ) { mAtlasMargin = margin; }

QString atlasFilenamePattern() const { return mAtlasFilenamePattern; }
void setAtlasFilenamePattern( const QString& pattern ) { mAtlasFilenamePattern = pattern; }

QgsVectorLayer* atlasCoverageLayer() const { return mAtlasCoverageLayer; }
void setAtlasCoverageLayer( QgsVectorLayer* lmap );

bool atlasSingleFile() const { return mAtlasSingleFile; }
void setAtlasSingleFile( bool single ) { mAtlasSingleFile = single; }

signals:
void extentChanged();

Expand All @@ -347,9 +329,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/**Call updateCachedImage if item is in render mode*/
void renderModeUpdateCachedImage();

private slots:
void syncAtlasCoverageLayer( QString );

private:

enum AnnotationCoordinate
Expand Down Expand Up @@ -462,13 +441,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/**True if annotation items, rubber band, etc. from the main canvas should be displayed*/
bool mDrawCanvasItems;

bool mAtlasHideCoverage;
bool mAtlasFixedScale;
double mAtlasMargin;
QString mAtlasFilenamePattern;
QgsVectorLayer* mAtlasCoverageLayer;
bool mAtlasSingleFile;

/**Draws the map grid*/
void drawGrid( QPainter* p );
void drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines );
Expand Down
289 changes: 14 additions & 275 deletions src/core/composer/qgscomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,261 +47,22 @@
#include <QSettings>
#include <QDir>

/**
* Private members of the QgsAtlasRendering class
*/
struct QgsAtlasRendering::QgsAtlasRenderingImpl
{
QgsComposition* composition;
QgsCoordinateTransform transform;
QString filenamePattern;
QString currentFilename;
int nFeatures;
std::vector<QgsFeature> features;
QgsRectangle origExtent;
bool restoreLayer;
std::auto_ptr<QgsExpression> filenameExpr;
size_t pageNumber;
size_t numberOfPages;
};

QgsAtlasRendering::QgsAtlasRendering( QgsComposition* composition )
{
impl = new QgsAtlasRendering::QgsAtlasRenderingImpl();
impl->composition = composition;
impl->nFeatures = 0;
}

QgsAtlasRendering::~QgsAtlasRendering()
{
delete impl;
}

void QgsAtlasRendering::begin( const QString& filenamePattern )
{
if ( !impl->composition || !impl->composition->atlasMap() || !impl->composition->atlasMap()->atlasCoverageLayer() )
return;

impl->filenamePattern = filenamePattern;

QgsVectorLayer* coverage = impl->composition->atlasMap()->atlasCoverageLayer();
const QgsCoordinateReferenceSystem& coverage_crs = coverage->crs();
const QgsCoordinateReferenceSystem& destination_crs = impl->composition->atlasMap()->mapRenderer()->destinationCrs();
// transformation needed for feature geometries
impl->transform.setSourceCrs( coverage_crs );
impl->transform.setDestCRS( destination_crs );

QgsVectorDataProvider* provider = coverage->dataProvider();
impl->nFeatures = provider->featureCount();

QgsFieldMap fieldmap = provider->fields();

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

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

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

// features must be stored in a list, since modifying the layer's extent rewinds nextFeature()
QgsFeature feature;
while ( provider->nextFeature( feature ) )
{
impl->features.push_back( feature );
}

impl->origExtent = impl->composition->atlasMap()->extent();

impl->restoreLayer = false;
QStringList& layerSet = impl->composition->mapRenderer()->layerSet();
if ( impl->composition->atlasMap()->atlasHideCoverage() )
{
// look for the layer in the renderer's set
int removeAt = layerSet.indexOf( coverage->id() );
if ( removeAt != -1 )
{
impl->restoreLayer = true;
layerSet.removeAt( removeAt );
}
}

// special columns for expressions
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )impl->nFeatures ) );
}

void QgsAtlasRendering::prepareForFeature( size_t featureI )
{
if ( !impl->composition || !impl->composition->atlasMap() || !impl->composition->atlasMap()->atlasCoverageLayer() )
return;

QgsFeature* fit = &impl->features[featureI];

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

impl->currentFilename = 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( *fit->geometry() );
tgeom.transform( impl->transform );
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)
impl->composition->atlasMap()->setNewExtent( impl->origExtent );

if ( impl->composition->atlasMap()->atlasFixedScale() )
{
// 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 - impl->origExtent.width() / 2.0;
double yy = geom_center_y - impl->origExtent.height() / 2.0;
new_extent = QgsRectangle( xx,
yy,
xx + impl->origExtent.width(),
yy + impl->origExtent.height() );
}
else
{
// auto scale

double geom_ratio = geom_rect.width() / geom_rect.height();
double map_ratio = impl->origExtent.width() / impl->origExtent.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 ( impl->composition->atlasMap()->atlasMargin() > 0.0 )
{
new_extent.scale( 1 + impl->composition->atlasMap()->atlasMargin() );
}
}

// 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 )
{
( *lit )->setExpressionContext( fit, impl->composition->atlasMap()->atlasCoverageLayer() );
}

// set the new extent (and render)
impl->composition->atlasMap()->setNewExtent( new_extent );
}

size_t QgsAtlasRendering::numFeatures() const
{
return impl->nFeatures;
}

const QString& QgsAtlasRendering::currentFilename() const
{
return impl->currentFilename;
}

void QgsAtlasRendering::end()
{
if ( !impl->composition || !impl->composition->atlasMap() || !impl->composition->atlasMap()->atlasCoverageLayer() )
return;

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

// restore the coverage visibility
if ( impl->restoreLayer )
{
QStringList& layerSet = impl->composition->mapRenderer()->layerSet();
QgsVectorLayer* coverage = impl->composition->atlasMap()->atlasCoverageLayer();

layerSet.push_back( coverage->id() );
impl->composition->atlasMap()->cache();
impl->composition->atlasMap()->update();
}
impl->composition->atlasMap()->setNewExtent( impl->origExtent );
}

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 ),
mAtlasMap( 0 )
mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveItemCommand( 0 ), mActiveMultiFrameCommand( 0 )
{
setBackgroundBrush( Qt::gray );
addPaperItem();

mPrintResolution = 300; //hardcoded default
loadSettings();

// declare special columns with a default value
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():
QGraphicsScene( 0 ), mMapRenderer( 0 ), 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 ),
mAtlasMap( 0 )
mSelectionTolerance( 0.0 ), mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveItemCommand( 0 ), mActiveMultiFrameCommand( 0 )
{
loadSettings();

QgsExpression::setSpecialColumn( "$page", QVariant(( int )0 ) );
QgsExpression::setSpecialColumn( "$feature", QVariant(( int )0 ) );
QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )0 ) );
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )0 ) );
}

QgsComposition::~QgsComposition()
Expand Down Expand Up @@ -561,7 +322,6 @@ bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc )
{
( *multiFrameIt )->writeXML( compositionElem, doc );
}

composerElem.appendChild( compositionElem );

return true;
Expand Down Expand Up @@ -605,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 @@ -1534,10 +1295,6 @@ void QgsComposition::addComposerHtmlFrame( QgsComposerHtml* html, QgsComposerFra
void QgsComposition::removeComposerItem( QgsComposerItem* item, bool createCommand )
{
QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item );
if ( map && mAtlasMap == map )
{
mAtlasMap = 0;
}

if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
{
Expand Down Expand Up @@ -1859,35 +1616,6 @@ void QgsComposition::renderPage( QPainter* p, int page )
mPlotStyle = savedPlotStyle;
}

void QgsComposition::setAtlasMap( QgsComposerMap* map )
{
mAtlasMap = map;
if ( map != 0 )
{
QObject::connect( map, SIGNAL( atlasCoverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( onAtlasCoverageChanged( QgsVectorLayer* ) ) );
}
else
{
QObject::disconnect( map, SIGNAL( atlasCoverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( onAtlasCoverageChanged( QgsVectorLayer* ) ) );
}
}

void QgsComposition::onAtlasCoverageChanged( QgsVectorLayer* )
{
// update variables
if ( mAtlasMap != 0 && mAtlasMap->atlasCoverageLayer() != 0 )
{
QgsVectorDataProvider* provider = mAtlasMap->atlasCoverageLayer()->dataProvider();
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )provider->featureCount() ) );
}
else
{
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )0 ) );
}
//
QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )numPages() ) );
}

QString QgsComposition::encodeStringForXML( const QString& str )
{
QString modifiedStr( str );
Expand All @@ -1898,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
39 changes: 0 additions & 39 deletions src/core/composer/qgscomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,37 +50,6 @@ class QgsComposerMultiFrame;
class QgsComposerMultiFrameCommand;
class QgsVectorLayer;

/** \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 QgsAtlasRendering
{
public:
QgsAtlasRendering( QgsComposition* composition );
~QgsAtlasRendering();

/** Begins the rendering. Sets an optional output filename pattern */
void begin( const QString& filenamePattern = "" );
/** Ends the rendering. Restores original extent*/
void end();

/** 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;

private:
struct QgsAtlasRenderingImpl;
// Use the PImpl idiom for private members.
QgsAtlasRenderingImpl *impl;
};

/** \ingroup MapComposer
* Graphics scene for map printing. The class manages the paper item which always
* is the item in the back (z-value 0). It maintains the z-Values of the items and stores
Expand Down Expand Up @@ -201,9 +170,6 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Returns pointer to map renderer of qgis map canvas*/
QgsMapRenderer* mapRenderer() {return mMapRenderer;}

QgsComposerMap* atlasMap() { return mAtlasMap; }
void setAtlasMap( QgsComposerMap* map );

QgsComposition::PlotStyle plotStyle() const {return mPlotStyle;}
void setPlotStyle( QgsComposition::PlotStyle style ) {mPlotStyle = style;}

Expand Down Expand Up @@ -341,9 +307,6 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Casts object to the proper subclass type and calls corresponding itemAdded signal*/
void sendItemAddedSignal( QgsComposerItem* item );

private slots:
void onAtlasCoverageChanged( QgsVectorLayer* );

private:
/**Pointer to map renderer of QGIS main map*/
QgsMapRenderer* mMapRenderer;
Expand Down Expand Up @@ -381,8 +344,6 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
QgsComposerItemCommand* mActiveItemCommand;
QgsComposerMultiFrameCommand* mActiveMultiFrameCommand;

QgsComposerMap* mAtlasMap;

QgsComposition(); //default constructor is forbidden

/**Reset z-values of items based on position in z list*/
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>
159 changes: 6 additions & 153 deletions src/ui/qgscomposermapwidgetbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
<number>0</number>
</property>
<property name="currentIndex">
<number>3</number>
<number>0</number>
</property>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>437</width>
<width>450</width>
<height>408</height>
</rect>
</property>
Expand Down Expand Up @@ -254,8 +254,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>377</height>
<width>199</width>
<height>177</height>
</rect>
</property>
<attribute name="label">
Expand Down Expand Up @@ -362,8 +362,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>437</width>
<height>893</height>
<width>277</width>
<height>921</height>
</rect>
</property>
<attribute name="label">
Expand Down Expand Up @@ -790,153 +790,6 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page_4">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>377</height>
</rect>
</property>
<attribute name="label">
<string>Atlas</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_9">
<item row="4" 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="mIsAtlasCheckBox">
<property name="text">
<string>Make it the atlas map</string>
</property>
</widget>
</item>
<item row="1" 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="1" 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="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Margin around coverage</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Output filename expression</string>
</property>
</widget>
</item>
<item row="3" 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="6" column="2">
<widget class="QToolButton" name="mAtlasFilenameExpressionButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="mAtlasFilenamePatternEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Coverage layer</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="mAtlasCoverageLayerComboBox">
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="mAtlasFixedScaleCheckBox">
<property name="text">
<string>Fixed scale</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<widget class="QCheckBox" name="mAtlasSingleFileCheckBox">
<property name="text">
<string>Single file export when possible</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ 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(composermapatlastest testqgscomposermapatlas.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 )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
testqgscomposermapatlas.cpp
testqgsatlascomposition.cpp
---------------------------
begin : Sept 2012
copyright : (C) 2012 by Hugo Mercier
Expand All @@ -19,6 +19,7 @@
#include "qgscomposition.h"
#include "qgscompositionchecker.h"
#include "qgscomposermap.h"
#include "qgsatlascomposition.h"
#include "qgscomposerlabel.h"
#include "qgsmaplayerregistry.h"
#include "qgsmaprenderer.h"
Expand All @@ -29,7 +30,7 @@
#include <QObject>
#include <QtTest>

class TestQgsComposerMapAtlas: public QObject
class TestQgsAtlasComposition: public QObject
{
Q_OBJECT;
private slots:
Expand All @@ -54,9 +55,10 @@ private slots:
QgsComposerMap* mOverview;
QgsMapRenderer* mMapRenderer;
QgsVectorLayer* mVectorLayer;
QgsAtlasComposition* mAtlas;
};

void TestQgsComposerMapAtlas::initTestCase()
void TestQgsAtlasComposition::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();
Expand Down Expand Up @@ -91,9 +93,11 @@ void TestQgsComposerMapAtlas::initTestCase()
// the atlas map
mAtlasMap = new QgsComposerMap( mComposition, 20, 20, 130, 130 );
mAtlasMap->setFrameEnabled( true );
mAtlasMap->setAtlasCoverageLayer( mVectorLayer );
mComposition->addComposerMap( mAtlasMap );
mComposition->setAtlasMap( mAtlasMap );

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

// an overview
mOverview = new QgsComposerMap( mComposition, 180, 20, 50, 50 );
Expand Down Expand Up @@ -123,49 +127,47 @@ void TestQgsComposerMapAtlas::initTestCase()
mLabel2->setItemPosition( 150, 200 );
}

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

void TestQgsComposerMapAtlas::init()
void TestQgsAtlasComposition::init()
{

}

void TestQgsComposerMapAtlas::cleanup()
void TestQgsAtlasComposition::cleanup()
{

}

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


void TestQgsComposerMapAtlas::autoscale_render()
void TestQgsAtlasComposition::autoscale_render()
{
mAtlasMap->setAtlasFixedScale( false );
mAtlasMap->setAtlasMargin( 0.10 );

QgsAtlasRendering atlasRender( mComposition );
mAtlas->setFixedScale( false );
mAtlas->setMargin( 0.10 );

atlasRender.begin();
mAtlas->beginRender();

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

QgsCompositionChecker checker( "Atlas autoscale test", mComposition,
Expand All @@ -174,21 +176,19 @@ void TestQgsComposerMapAtlas::autoscale_render()
QString( "autoscale_%1.png" ).arg((int)fit) );
QVERIFY( checker.testComposition( 0 ) );
}
atlasRender.end();
mAtlas->endRender();
}

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

QgsAtlasRendering atlasRender( mComposition );
mAtlas->setFixedScale( true );

atlasRender.begin();
mAtlas->beginRender();

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

QgsCompositionChecker checker( "Atlas fixedscale test", mComposition,
Expand All @@ -197,23 +197,21 @@ void TestQgsComposerMapAtlas::fixedscale_render()
QString( "fixedscale_%1.png" ).arg((int)fit) );
QVERIFY( checker.testComposition( 0 ) );
}
atlasRender.end();
mAtlas->endRender();

}

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

QgsAtlasRendering atlasRender( mComposition );

atlasRender.begin();
mAtlas->beginRender();

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

QgsCompositionChecker checker( "Atlas hidden test", mComposition,
Expand All @@ -222,9 +220,8 @@ void TestQgsComposerMapAtlas::hiding_render()
QString( "hiding_%1.png" ).arg((int)fit) );
QVERIFY( checker.testComposition( 0 ) );
}
atlasRender.end();

mAtlas->endRender();
}

QTEST_MAIN( TestQgsComposerMapAtlas )
#include "moc_testqgscomposermapatlas.cxx"
QTEST_MAIN( TestQgsAtlasComposition )
#include "moc_testqgsatlascomposition.cxx"