114 changes: 103 additions & 11 deletions src/core/composer/qgsatlascomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ QgsAtlasComposition::QgsAtlasComposition( QgsComposition* composition ) :
mComposerMap( 0 ),
mHideCoverage( false ), mFixedScale( false ), mMargin( 0.10 ), mFilenamePattern( "'output_'||$feature" ),
mCoverageLayer( 0 ), mSingleFile( false ),
mSortFeatures( false ), mSortAscending( true ),
mSortFeatures( false ), mSortAscending( true ), mCurrentFeatureNo( 0 ),
mFilterFeatures( false ), mFeatureFilter( "" )
{

Expand All @@ -49,6 +49,12 @@ QgsAtlasComposition::~QgsAtlasComposition()
{
}

void QgsAtlasComposition::setEnabled( bool e )
{
mEnabled = e;
emit toggled( e );
}

void QgsAtlasComposition::setCoverageLayer( QgsVectorLayer* layer )
{
mCoverageLayer = layer;
Expand Down Expand Up @@ -94,8 +100,10 @@ class FieldSorter
bool mAscending;
};

void QgsAtlasComposition::beginRender()
void QgsAtlasComposition::updateFeatures()
{
//needs to be called when layer, filter, sort changes

if ( !mComposerMap || !mCoverageLayer )
{
return;
Expand Down Expand Up @@ -172,7 +180,25 @@ void QgsAtlasComposition::beginRender()
qSort( mFeatureIds.begin(), mFeatureIds.end(), sorter );
}

mOrigExtent = mComposerMap->extent();
QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )mFeatureIds.size() ) );

//jump to first feature if currently using an atlas preview
//need to do this in case filtering/layer change has altered matching features
if ( mComposition->atlasPreviewEnabled() )
{
firstFeature();
}
}


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

updateFeatures();

mRestoreLayer = false;
QStringList& layerSet = mComposition->mapRenderer()->layerSet();
Expand Down Expand Up @@ -213,17 +239,50 @@ void QgsAtlasComposition::endRender()
QStringList& layerSet = mComposition->mapRenderer()->layerSet();

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

mComposerMap->cache();
}

int QgsAtlasComposition::numFeatures() const
{
return mFeatureIds.size();
}

void QgsAtlasComposition::nextFeature()
{
mCurrentFeatureNo++;
if ( mCurrentFeatureNo >= mFeatureIds.size() )
{
mCurrentFeatureNo = mFeatureIds.size() - 1;
}

prepareForFeature( mCurrentFeatureNo );
}

void QgsAtlasComposition::prevFeature()
{
mCurrentFeatureNo--;
if ( mCurrentFeatureNo < 0 )
{
mCurrentFeatureNo = 0;
}

prepareForFeature( mCurrentFeatureNo );
}

void QgsAtlasComposition::firstFeature()
{
mCurrentFeatureNo = 0;
prepareForFeature( mCurrentFeatureNo );
}

void QgsAtlasComposition::lastFeature()
{
mCurrentFeatureNo = mFeatureIds.size() - 1;
prepareForFeature( mCurrentFeatureNo );
}

void QgsAtlasComposition::prepareForFeature( int featureI )
{
if ( !mComposerMap || !mCoverageLayer )
Expand All @@ -233,6 +292,7 @@ void QgsAtlasComposition::prepareForFeature( int featureI )

// retrieve the next feature, based on its id
mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ] ) ).nextFeature( mCurrentFeature );

QgsExpression::setSpecialColumn( "$atlasfeatureid", mCurrentFeature.id() );
QgsExpression::setSpecialColumn( "$atlasgeometry", QVariant::fromValue( *mCurrentFeature.geometry() ) );

Expand Down Expand Up @@ -266,10 +326,7 @@ void QgsAtlasComposition::prepareForFeature( int featureI )
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 );
QgsRectangle mOrigExtent = mComposerMap->extent();

if ( mFixedScale )
{
Expand Down Expand Up @@ -326,7 +383,7 @@ void QgsAtlasComposition::prepareForFeature( int featureI )
}

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

const QString& QgsAtlasComposition::currentFilename() const
Expand Down Expand Up @@ -383,6 +440,7 @@ void QgsAtlasComposition::writeXML( QDomElement& elem, QDomDocument& doc ) const
void QgsAtlasComposition::readXML( const QDomElement& atlasElem, const QDomDocument& )
{
mEnabled = atlasElem.attribute( "enabled", "false" ) == "true" ? true : false;
emit toggled( mEnabled );
if ( !mEnabled )
{
emit parameterChanged();
Expand Down Expand Up @@ -431,3 +489,37 @@ void QgsAtlasComposition::readXML( const QDomElement& atlasElem, const QDomDocum

emit parameterChanged();
}

void QgsAtlasComposition::setHideCoverage( bool hide )
{
mHideCoverage = hide;

if ( mComposition->atlasPreviewEnabled() )
{
//an atlas preview is enabled, so reflect changes in coverage layer visibility immediately
QStringList& layerSet = mComposition->mapRenderer()->layerSet();
if ( hide )
{
// look for the layer in the renderer's set
int removeAt = layerSet.indexOf( mCoverageLayer->id() );
if ( removeAt != -1 )
{
mRestoreLayer = true;
layerSet.removeAt( removeAt );
}
}
else
{
if ( mRestoreLayer )
{
layerSet.push_back( mCoverageLayer->id() );
mRestoreLayer = false;
}
}
mComposerMap->cache();
mComposition->update();
}

}


19 changes: 16 additions & 3 deletions src/core/composer/qgsatlascomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ class CORE_EXPORT QgsAtlasComposition : public QObject

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

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

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

bool fixedScale() const { return mFixedScale; }
void setFixedScale( bool fixed ) { mFixedScale = fixed; }
Expand Down Expand Up @@ -100,10 +100,20 @@ class CORE_EXPORT QgsAtlasComposition : public QObject

QgsComposition* composition() { return mComposition; }

void updateFeatures();

void nextFeature();
void prevFeature();
void lastFeature();
void firstFeature();

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

/** emitted when atlas is enabled or disabled */
void toggled( bool );

private:
QgsComposition* mComposition;

Expand All @@ -122,6 +132,10 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
bool mSortFeatures;
// sort direction
bool mSortAscending;

// current atlas feature number
int mCurrentFeatureNo;

public:
typedef QMap< QgsFeatureId, QVariant > SorterKeys;
private:
Expand All @@ -139,7 +153,6 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
QVector<QgsFeatureId> mFeatureIds;

QgsFeature mCurrentFeature;
QgsRectangle mOrigExtent;
bool mRestoreLayer;
std::auto_ptr<QgsExpression> mFilenameExpr;
};
Expand Down
16 changes: 14 additions & 2 deletions src/core/composer/qgscomposerlabel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
double penWidth = pen().widthF();
QRectF painterRect( penWidth + mMargin, penWidth + mMargin, rect().width() - 2 * penWidth - 2 * mMargin, rect().height() - 2 * penWidth - 2 * mMargin );

QString textToDraw;
if ( mComposition->plotStyle() != QgsComposition::Preview || mComposition->atlasPreviewEnabled() )
{
//render text with expressions evaluated
textToDraw = displayText();
}
else
{
//not outputing or using an atlas preview, so render text without expressions evaluated
textToDraw = mText;
}

if ( mHtmlState )
{
painter->scale( 1.0 / mHtmlUnitsToMM / 10.0, 1.0 / mHtmlUnitsToMM / 10.0 );
Expand Down Expand Up @@ -107,7 +119,7 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
mHtmlLoaded = false;
connect( webPage, SIGNAL( loadFinished( bool ) ), SLOT( loadingHtmlFinished( bool ) ) );

webPage->mainFrame()->setHtml( displayText() );
webPage->mainFrame()->setHtml( textToDraw );

//For very basic html labels with no external assets, the html load will already be
//complete before we even get a chance to start the QEventLoop. Make sure we check
Expand All @@ -132,7 +144,7 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem*
//debug
//painter->setPen( QColor( Qt::red ) );
//painter->drawRect( painterRect );
drawText( painter, painterRect, displayText(), mFont, mHAlignment, mVAlignment );
drawText( painter, painterRect, textToDraw, mFont, mHAlignment, mVAlignment );
}

painter->restore();
Expand Down
201 changes: 138 additions & 63 deletions src/core/composer/qgscomposermap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w
//calculate mExtent based on width/height ratio and map canvas extent
if ( mMapRenderer )
{
QgsRectangle mapExtent = mMapRenderer->extent();
//make extent make item shape while keeping centre unchanged
adjustExtentToItemShape( width, height, mapExtent );
mExtent = mapExtent;
mExtent = mMapRenderer->extent();
}
setSceneRect( QRectF( x, y, width, height ) );
setToolTip( tr( "Map %1" ).arg( mId ) );
Expand Down Expand Up @@ -154,28 +151,6 @@ void QgsComposerMap::adjustExtentToItemShape( double itemWidth, double itemHeigh
}
}

void QgsComposerMap::extentCenteredOnOverview( QgsRectangle& extent ) const
{
extent = mExtent;
if ( ! mOverviewCentered )
{
return;
}

if ( mOverviewFrameMapId != -1 )
{
const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
QgsRectangle otherExtent = overviewFrameMap->extent();

QgsPoint center = otherExtent.center();
QgsRectangle movedExtent( center.x() - mExtent.width() / 2,
center.y() - mExtent.height() / 2,
center.x() - mExtent.width() / 2 + mExtent.width(),
center.y() - mExtent.height() / 2 + mExtent.height() );
extent = movedExtent;
}
}

QgsComposerMap::~QgsComposerMap()
{
delete mOverviewFrameMapSymbol;
Expand Down Expand Up @@ -312,7 +287,7 @@ void QgsComposerMap::cache( void )
mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
}

double mapUnitsPerPixel = mExtent.width() / w;
double mapUnitsPerPixel = currentMapExtent()->width() / w;

// WARNING: ymax in QgsMapToPixel is device height!!!
QgsMapToPixel transform( mapUnitsPerPixel, h, requestExtent.yMinimum(), requestExtent.xMinimum() );
Expand Down Expand Up @@ -360,16 +335,15 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i
QgsRectangle requestRectangle;
requestedExtent( requestRectangle );

QgsRectangle cExtent;
extentCenteredOnOverview( cExtent );
QgsRectangle cExtent = *currentMapExtent();

double horizontalVScaleFactor = horizontalViewScaleFactor();
if ( horizontalVScaleFactor < 0 )
{
horizontalVScaleFactor = mLastValidViewScaleFactor;
}

double imagePixelWidth = mExtent.width() / requestRectangle.width() * mCacheImage.width() ; //how many pixels of the image are for the map extent?
double imagePixelWidth = cExtent.width() / requestRectangle.width() * mCacheImage.width() ; //how many pixels of the image are for the map extent?
double scale = rect().width() / imagePixelWidth;
QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );

Expand Down Expand Up @@ -417,8 +391,7 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i
QgsRectangle requestRectangle;
requestedExtent( requestRectangle );

QgsRectangle cExtent;
extentCenteredOnOverview( cExtent );
QgsRectangle cExtent = *currentMapExtent();

QSizeF theSize( requestRectangle.width() * mapUnitsToMM(), requestRectangle.height() * mapUnitsToMM() );

Expand Down Expand Up @@ -492,7 +465,7 @@ double QgsComposerMap::scale() const
QgsScaleCalculator calculator;
calculator.setMapUnits( mMapRenderer->mapUnits() );
calculator.setDpi( 25.4 ); //QGraphicsView units are mm
return calculator.calculate( mExtent, rect().width() );
return calculator.calculate( *currentMapExtent(), rect().width() );
}

void QgsComposerMap::resize( double dx, double dy )
Expand All @@ -509,10 +482,10 @@ void QgsComposerMap::moveContent( double dx, double dy )
if ( !mDrawing )
{
transformShift( dx, dy );
mExtent.setXMinimum( mExtent.xMinimum() + dx );
mExtent.setXMaximum( mExtent.xMaximum() + dx );
mExtent.setYMinimum( mExtent.yMinimum() + dy );
mExtent.setYMaximum( mExtent.yMaximum() + dy );
currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
cache();
update();
emit itemChanged();
Expand Down Expand Up @@ -540,14 +513,14 @@ void QgsComposerMap::zoomContent( int delta, double x, double y )
double zoomFactor = settings.value( "/qgis/zoom_factor", 2.0 ).toDouble();

//find out new center point
double centerX = ( mExtent.xMaximum() + mExtent.xMinimum() ) / 2;
double centerY = ( mExtent.yMaximum() + mExtent.yMinimum() ) / 2;
double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;

if ( zoomMode != 0 )
{
//find out map coordinates of mouse position
double mapMouseX = mExtent.xMinimum() + ( x / rect().width() ) * ( mExtent.xMaximum() - mExtent.xMinimum() );
double mapMouseY = mExtent.yMinimum() + ( 1 - ( y / rect().height() ) ) * ( mExtent.yMaximum() - mExtent.yMinimum() );
double mapMouseX = currentMapExtent()->xMinimum() + ( x / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
double mapMouseY = currentMapExtent()->yMinimum() + ( 1 - ( y / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
if ( zoomMode == 1 ) //zoom and recenter
{
centerX = mapMouseX;
Expand All @@ -564,23 +537,23 @@ void QgsComposerMap::zoomContent( int delta, double x, double y )

if ( delta > 0 )
{
newIntervalX = ( mExtent.xMaximum() - mExtent.xMinimum() ) / zoomFactor;
newIntervalY = ( mExtent.yMaximum() - mExtent.yMinimum() ) / zoomFactor;
newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / zoomFactor;
newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / zoomFactor;
}
else if ( delta < 0 )
{
newIntervalX = ( mExtent.xMaximum() - mExtent.xMinimum() ) * zoomFactor;
newIntervalY = ( mExtent.yMaximum() - mExtent.yMinimum() ) * zoomFactor;
newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) * zoomFactor;
newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) * zoomFactor;
}
else //no need to zoom
{
return;
}

mExtent.setXMaximum( centerX + newIntervalX / 2 );
mExtent.setXMinimum( centerX - newIntervalX / 2 );
mExtent.setYMaximum( centerY + newIntervalY / 2 );
mExtent.setYMinimum( centerY - newIntervalY / 2 );
currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );

cache();
update();
Expand Down Expand Up @@ -624,6 +597,83 @@ void QgsComposerMap::setNewExtent( const QgsRectangle& extent )
updateItem();
}

void QgsComposerMap::setNewAtlasFeatureExtent( const QgsRectangle& extent )
{
if ( mAtlasFeatureExtent == extent )
{
return;
}

//don't adjust size of item, instead adjust size of bounds to fit
QgsRectangle newExtent = extent;

//Make sure the width/height ratio is the same as the map item size
double currentWidthHeightRatio = rect().width() / rect().height();
double newWidthHeightRatio = newExtent.width() / newExtent.height();

if ( currentWidthHeightRatio < newWidthHeightRatio )
{
//enlarge height of new extent, ensuring the map center stays the same
double newHeight = newExtent.width() / currentWidthHeightRatio;
double deltaHeight = newHeight - newExtent.height();
newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
}
else if ( currentWidthHeightRatio >= newWidthHeightRatio )
{
//enlarge width of new extent, ensuring the map center stays the same
double newWidth = currentWidthHeightRatio * newExtent.height();
double deltaWidth = newWidth - newExtent.width();
newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
}

mAtlasFeatureExtent = newExtent;
mCacheUpdated = false;
updateItem();
emit itemChanged();
emit extentChanged();
}

QgsRectangle* QgsComposerMap::currentMapExtent()
{
//non-const version

QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();

if ( atlasMap->enabled() && atlasMap->composerMap() == this &&
( mComposition->atlasPreviewEnabled() || mComposition->plotStyle() != QgsComposition::Preview ) )
{
//if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
//return the current temporary atlas feature extent
return &mAtlasFeatureExtent;
}
else
{
//otherwise return permenant user set extent
return &mExtent;
}
}

const QgsRectangle* QgsComposerMap::currentMapExtent() const
{
//const version

QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
if ( atlasMap->enabled() && atlasMap->composerMap() == this &&
( mComposition->atlasPreviewEnabled() || mComposition->plotStyle() != QgsComposition::Preview ) )
{
//if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
//return the current temporary atlas feature extent
return &mAtlasFeatureExtent;
}
else
{
//otherwise return permenant user set extent
return &mExtent;
}
}

void QgsComposerMap::setNewScale( double scaleDenominator )
{
double currentScaleDenominator = scale();
Expand All @@ -634,7 +684,7 @@ void QgsComposerMap::setNewScale( double scaleDenominator )
}

double scaleRatio = scaleDenominator / currentScaleDenominator;
mExtent.scale( scaleRatio );
currentMapExtent()->scale( scaleRatio );
mCacheUpdated = false;
cache();
update();
Expand Down Expand Up @@ -1844,7 +1894,7 @@ QgsRectangle QgsComposerMap::transformedExtent() const
double dx = mXOffset;
double dy = mYOffset;
transformShift( dx, dy );
return QgsRectangle( mExtent.xMinimum() - dx, mExtent.yMinimum() - dy, mExtent.xMaximum() - dx, mExtent.yMaximum() - dy );
return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
}

QPolygonF QgsComposerMap::transformedMapPolygon() const
Expand Down Expand Up @@ -1951,13 +2001,12 @@ void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) c

void QgsComposerMap::mapPolygon( QPolygonF& poly ) const
{
return mapPolygon( mExtent, poly );
return mapPolygon( *currentMapExtent(), poly );
}

void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const
{
QgsRectangle newExtent;
extentCenteredOnOverview( newExtent );
QgsRectangle newExtent = *currentMapExtent();
if ( mMapRotation == 0 )
{
extent = newExtent;
Expand All @@ -1976,7 +2025,7 @@ void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const

double QgsComposerMap::mapUnitsToMM() const
{
double extentWidth = mExtent.width();
double extentWidth = currentMapExtent()->width();
if ( extentWidth <= 0 )
{
return 1;
Expand All @@ -1991,7 +2040,7 @@ void QgsComposerMap::setOverviewFrameMap( int mapId )
const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
if ( map )
{
QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
}
}
mOverviewFrameMapId = mapId;
Expand All @@ -2000,12 +2049,39 @@ void QgsComposerMap::setOverviewFrameMap( int mapId )
const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
if ( map )
{
QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( repaint() ) );
QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
}
}
update();
}

void QgsComposerMap::overviewExtentChanged()
{
//if using overview centering, update the map's extent
if ( mOverviewCentered && mOverviewFrameMapId != -1 )
{
QgsRectangle extent = *currentMapExtent();

const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();

QgsPoint center = otherExtent.center();
QgsRectangle movedExtent( center.x() - currentMapExtent()->width() / 2,
center.y() - currentMapExtent()->height() / 2,
center.x() - currentMapExtent()->width() / 2 + currentMapExtent()->width(),
center.y() - currentMapExtent()->height() / 2 + currentMapExtent()->height() );
*currentMapExtent() = movedExtent;

emit itemChanged();
emit extentChanged();
}

//redraw so that overview gets updated
cache();
update();
}


void QgsComposerMap::setOverviewFrameMapSymbol( QgsFillSymbolV2* symbol )
{
delete mOverviewFrameMapSymbol;
Expand All @@ -2027,7 +2103,7 @@ void QgsComposerMap::setOverviewInverted( bool inverted )
void QgsComposerMap::setOverviewCentered( bool centered )
{
mOverviewCentered = centered;
update();
overviewExtentChanged();
}

void QgsComposerMap::setGridLineSymbol( QgsLineSymbolV2* symbol )
Expand Down Expand Up @@ -2125,7 +2201,7 @@ void QgsComposerMap::drawCanvasItem( QGraphicsItem* item, QPainter* painter, con
painter->save();

QgsRectangle rendererExtent = mMapRenderer->extent();
QgsRectangle composerMapExtent = mExtent;
QgsRectangle composerMapExtent = *currentMapExtent();

//determine scale factor according to graphics view dpi
double scaleFactor = 1.0 / mMapCanvas->logicalDpiX() * 25.4;
Expand Down Expand Up @@ -2167,7 +2243,7 @@ QPointF QgsComposerMap::composerMapPosForItem( const QGraphicsItem* item ) const
return QPointF( 0, 0 );
}

if ( mExtent.height() <= 0 || mExtent.width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
if ( currentMapExtent()->height() <= 0 || currentMapExtent()->width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
{
return QPointF( 0, 0 );
}
Expand Down Expand Up @@ -2328,9 +2404,8 @@ void QgsComposerMap::drawOverviewMapExtent( QPainter* p )
return;
}

QgsRectangle otherExtent = overviewFrameMap->extent();
QgsRectangle thisExtent;
extentCenteredOnOverview( thisExtent );
QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
QgsRectangle thisExtent = *currentMapExtent();
QgsRectangle intersectRect = thisExtent.intersect( &otherExtent );

QgsRenderContext context;
Expand Down
22 changes: 18 additions & 4 deletions src/core/composer/qgscomposermap.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/**Sets new Extent and changes width, height (and implicitely also scale)*/
void setNewExtent( const QgsRectangle& extent );

/**Sets new Extent for the current atlas preview and changes width, height (and implicitely also scale).
Atlas preview extents are only temporary, and are regenerated whenever the atlas feature changes
*/
void setNewAtlasFeatureExtent( const QgsRectangle& extent );

/**Returns a pointer to the current map extent, which is either the original user specified
extent or the temporary atlas-driven feature extent depending on the current atlas state of the composition.
Both a const and non-const version are included.*/
QgsRectangle* currentMapExtent();
const QgsRectangle* currentMapExtent() const;

PreviewMode previewMode() const {return mPreviewMode;}
void setPreviewMode( PreviewMode m );

Expand Down Expand Up @@ -419,6 +430,8 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/**Call updateCachedImage if item is in render mode*/
void renderModeUpdateCachedImage();

void overviewExtentChanged();

private:

enum AnnotationCoordinate
Expand All @@ -439,6 +452,11 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
// so that full rectangle in paper is used.
QgsRectangle mExtent;

// Current temporary map region in map units. This is overwritten when atlas feature changes. It's also
// used when the user changes the map extent and an atlas preview is enabled. This allows the user
// to manually tweak each atlas preview page without affecting the actual original map extent.
QgsRectangle mAtlasFeatureExtent;

// Cache used in composer preview
QImage mCacheImage;

Expand Down Expand Up @@ -607,10 +625,6 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
void createDefaultGridLineSymbol();
void initGridAnnotationFormatFromProject();

/**
* Returns the extent, centered on the overview frame
*/
void extentCenteredOnOverview( QgsRectangle& extent ) const;
};

#endif
18 changes: 18 additions & 0 deletions src/core/composer/qgscomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer )
, mActiveItemCommand( 0 )
, mActiveMultiFrameCommand( 0 )
, mAtlasComposition( this )
, mAtlasPreviewEnabled( false )
, mPreventCursorChange( false )
{
setBackgroundBrush( Qt::gray );
Expand Down Expand Up @@ -120,6 +121,7 @@ QgsComposition::QgsComposition()
mActiveItemCommand( 0 ),
mActiveMultiFrameCommand( 0 ),
mAtlasComposition( this ),
mAtlasPreviewEnabled( false ),
mPreventCursorChange( false )
{
//load default composition settings
Expand Down Expand Up @@ -2310,6 +2312,22 @@ void QgsComposition::computeWorldFileParameters( double& a, double& b, double& c
f = r[3] * s[2] + r[4] * s[5] + r[5];
}

void QgsComposition::setAtlasPreviewEnabled( bool e )
{
mAtlasPreviewEnabled = e;

if ( !mAtlasPreviewEnabled )
{
mAtlasComposition.endRender();
}
else
{
mAtlasComposition.beginRender();
}

update();
}

void QgsComposition::relativeResizeRect( QRectF& rectToResize, const QRectF& boundsBefore, const QRectF& boundsAfter )
{
//linearly scale rectToResize relative to the scaling from boundsBefore to boundsAfter
Expand Down
7 changes: 7 additions & 0 deletions src/core/composer/qgscomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,11 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
/**Returns a scaled position given a before and after range*/
static double relativePosition( double position, double beforeMin, double beforeMax, double afterMin, double afterMax );

/** Is the atlas preview enabled ? */
bool atlasPreviewEnabled() const { return mAtlasPreviewEnabled; }
void setAtlasPreviewEnabled( bool e );


public slots:
/**Casts object to the proper subclass type and calls corresponding itemAdded signal*/
void sendItemAddedSignal( QgsComposerItem* item );
Expand Down Expand Up @@ -491,6 +496,8 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
/** The atlas composition object. It is held by the QgsComposition */
QgsAtlasComposition mAtlasComposition;

bool mAtlasPreviewEnabled;

QgsComposition(); //default constructor is forbidden

/**Reset z-values of items based on position in z list*/
Expand Down
61 changes: 61 additions & 0 deletions src/ui/qgscomposerbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,22 @@
<addaction name="mActionAddTable"/>
<addaction name="mActionAddHtml"/>
</widget>
<widget class="QToolBar" name="mAtlasToolbar">
<property name="windowTitle">
<string>Atlas</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>true</bool>
</attribute>
<addaction name="mActionAtlasPreview"/>
<addaction name="mActionAtlasFirst"/>
<addaction name="mActionAtlasPrev"/>
<addaction name="mActionAtlasNext"/>
<addaction name="mActionAtlasLast"/>
</widget>
<action name="mActionPrint">
<property name="checkable">
<bool>false</bool>
Expand Down Expand Up @@ -829,6 +845,51 @@
<string>Ctrl+R</string>
</property>
</action>
<action name="mActionAtlasFirst">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowUp.png</normaloff>:/images/themes/default/mActionArrowUp.png</iconset>
</property>
<property name="text">
<string>First Feature</string>
</property>
</action>
<action name="mActionAtlasPrev">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowLeft.png</normaloff>:/images/themes/default/mActionArrowLeft.png</iconset>
</property>
<property name="text">
<string>Previous Feature</string>
</property>
</action>
<action name="mActionAtlasNext">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowRight.png</normaloff>:/images/themes/default/mActionArrowRight.png</iconset>
</property>
<property name="text">
<string>Next Feature</string>
</property>
</action>
<action name="mActionAtlasLast">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionArrowDown.png</normaloff>:/images/themes/default/mActionArrowDown.png</iconset>
</property>
<property name="text">
<string>Last Feature</string>
</property>
</action>
<action name="mActionAtlasPreview">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mIconWmsLayer.png</normaloff>:/images/themes/default/mIconWmsLayer.png</iconset>
</property>
<property name="text">
<string>Preview Atlas</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>
Expand Down
3 changes: 2 additions & 1 deletion tests/src/core/testqgsatlascomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ void TestQgsAtlasComposition::initTestCase()
mAtlasMap->setFrameEnabled( true );
mComposition->addComposerMap( mAtlasMap );

mAtlas = new QgsAtlasComposition( mComposition );
mAtlas = &mComposition->atlasComposition();
mAtlas->setCoverageLayer( mVectorLayer );
mAtlas->setComposerMap( mAtlasMap );
mAtlas->setEnabled( true );

// an overview
mOverview = new QgsComposerMap( mComposition, 180, 20, 50, 50 );
Expand Down
3 changes: 2 additions & 1 deletion tests/src/python/test_qgsatlascomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ def testCase(self):
self.mComposition.addComposerMap( self.mAtlasMap )

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

# an overview
mOverview = QgsComposerMap( self.mComposition, 180, 20, 50, 50 )
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.