Skip to content

Commit e4364f3

Browse files
author
Hugo Mercier
committedOct 4, 2012
Merge branch 'atlas' into atlas2
Conflicts: python/core/composer/qgscomposition.sip tests/src/python/CMakeLists.txt
2 parents b5f736a + 371efa0 commit e4364f3

File tree

8 files changed

+352
-1
lines changed

8 files changed

+352
-1
lines changed
 

‎python/core/composer/qgscomposerlabel.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class QgsComposerLabel : QgsComposerItem
2626
@note this function was added in version 1.2*/
2727
QString displayText() const;
2828

29+
/** Sets the current feature, the current layer and a list of local variable substitutions for evaluating expressions */
30+
void setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer, QMap<QString, QVariant> substitutions = QMap<QString, QVariant>() );
31+
2932
QFont font() const;
3033
void setFont( const QFont& f );
3134
/** Accessor for the vertical alignment of the label

‎python/core/composer/qgscomposermap.sip

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,29 @@ class QgsComposerMap : QgsComposerItem
285285
Usually, this function is called before adding the composer map to the composition*/
286286
void assignFreeId();
287287

288+
bool atlasHideCoverage() const;
289+
void setAtlasHideCoverage( bool hide );
290+
291+
bool atlasFixedScale() const;
292+
void setAtlasFixedScale( bool fixed );
293+
294+
float atlasMargin() const;
295+
void setAtlasMargin( float margin );
296+
297+
QString atlasFilenamePattern() const;
298+
void setAtlasFilenamePattern( const QString& pattern );
299+
300+
QgsVectorLayer* atlasCoverageLayer() const;
301+
void setAtlasCoverageLayer( QgsVectorLayer* lmap );
302+
303+
bool atlasSingleFile() const;
304+
void setAtlasSingleFile( bool single );
305+
288306
signals:
289307
void extentChanged();
290308

309+
void atlasCoverageLayerChanged( QgsVectorLayer* );
310+
291311
public slots:
292312

293313
/**Called if map canvas has changed*/

‎src/app/composer/qgscomposermapwidget.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,14 @@ void QgsComposerMapWidget::on_mIsAtlasCheckBox_stateChanged( int state )
965965
}
966966
}
967967

968+
// Connect to addition / removal of layers
969+
QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance();
970+
if ( layerRegistry )
971+
{
972+
connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( onLayerRemoved( QString ) ) );
973+
connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerAdded( QgsMapLayer* ) ) );
974+
}
975+
968976
mAtlasFrame->setEnabled( true );
969977
updateGuiElements();
970978
}
@@ -976,10 +984,40 @@ void QgsComposerMapWidget::on_mIsAtlasCheckBox_stateChanged( int state )
976984
if ( composition->atlasMap() == mComposerMap )
977985
{
978986
composition->setAtlasMap( 0 );
987+
988+
QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance();
989+
if ( layerRegistry )
990+
{
991+
disconnect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( onLayerRemoved( QString ) ) );
992+
disconnect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerAdded( QgsMapLayer* ) ) );
993+
}
994+
}
995+
}
996+
}
997+
998+
void QgsComposerMapWidget::onLayerRemoved( QString layerName )
999+
{
1000+
// update the atlas coverage layer combo box
1001+
for ( int i = 0; i < mAtlasCoverageLayerComboBox->count(); ++i )
1002+
{
1003+
if ( mAtlasCoverageLayerComboBox->itemText( i ) == layerName )
1004+
{
1005+
mAtlasCoverageLayerComboBox->removeItem( i );
1006+
break;
9791007
}
9801008
}
9811009
}
9821010

1011+
void QgsComposerMapWidget::onLayerAdded( QgsMapLayer* map )
1012+
{
1013+
// update the atlas coverage layer combo box
1014+
QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( map );
1015+
if ( vectorLayer )
1016+
{
1017+
mAtlasCoverageLayerComboBox->addItem( map->id(), qVariantFromValue( (void*)map ) );
1018+
}
1019+
}
1020+
9831021
void QgsComposerMapWidget::on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index )
9841022
{
9851023
if ( !mComposerMap )

‎src/app/composer/qgscomposermapwidget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "ui_qgscomposermapwidgetbase.h"
2222
#include "qgscomposermap.h"
23+
class QgsMapLayer;
2324

2425
/** \ingroup MapComposer
2526
* Input widget for the configuration of QgsComposerMap
@@ -104,6 +105,10 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
104105
/**Sets the GUI elements to the values of mPicture*/
105106
void setGuiElementValues();
106107

108+
/** Updates atlas' coverage layer combobox on layer addition / removal */
109+
void onLayerRemoved( QString );
110+
void onLayerAdded( QgsMapLayer* );
111+
107112
private:
108113
QgsComposerMap* mComposerMap;
109114

‎tests/src/core/testqgscomposerlabel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void TestQgsComposerLabel::evaluation()
109109
QDate now = QDate::currentDate();
110110
int dd = now.day();
111111

112-
QString expected = "__" + QString("%1").arg(dd+1, 2, 10, QChar('0')) + "(ok)__";
112+
QString expected = "__" + QString("%1").arg(dd+1) + "(ok)__";
113113
mComposerLabel->setText( "__[%$CURRENT_DATE(dd) + 1%](ok)__" );
114114
QString evaluated = mComposerLabel->displayText();
115115
QCOMPARE( evaluated, expected );

‎tests/src/python/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ ADD_PYTHON_TEST(PyQgsComposition test_qgscomposition.py)
1414
ADD_PYTHON_TEST(PyQgsAnalysis test_qgsanalysis.py)
1515
#ADD_PYTHON_TEST(PyQgsComposerMap test_qgscomposermap.py)
1616
ADD_PYTHON_TEST(PyQgsSymbolLayerV2 test_qgssymbollayerv2.py)
17+
ADD_PYTHON_TEST(PyQgsComposerMapAtlas test_qgscomposermapatlas.py)
18+
ADD_PYTHON_TEST(PyQgsComposerLabel test_qgscomposerlabel.py)
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
test_qgscomposerlabel.py
4+
--------------------------------------
5+
Date : Oct 2012
6+
Copyright : (C) 2012 by Dr. Hugo Mercier
7+
email : hugo dot mercier at oslandia dot com
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
'''
17+
import unittest
18+
from utilities import *
19+
from PyQt4.QtCore import *
20+
from PyQt4.QtGui import *
21+
from PyQt4.QtXml import *
22+
from qgis.core import *
23+
24+
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()
25+
26+
class TestQgsComposerLabel(unittest.TestCase):
27+
28+
def testCase(self):
29+
TEST_DATA_DIR = unitTestDataPath()
30+
vectorFileInfo = QFileInfo( TEST_DATA_DIR + QDir().separator().toAscii() + "france_parts.shp")
31+
mVectorLayer = QgsVectorLayer( vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" )
32+
33+
QgsMapLayerRegistry.instance().addMapLayer( mVectorLayer )
34+
35+
# create composition with composer map
36+
mMapRenderer = QgsMapRenderer()
37+
layerStringList = QStringList()
38+
layerStringList.append( mVectorLayer.id() )
39+
mMapRenderer.setLayerSet( layerStringList )
40+
mMapRenderer.setProjectionsEnabled( False )
41+
42+
mComposition = QgsComposition( mMapRenderer )
43+
mComposition.setPaperSize( 297, 210 )
44+
45+
mLabel = QgsComposerLabel( mComposition )
46+
mComposition.addComposerLabel( mLabel )
47+
48+
self.evaluation_test( mComposition, mLabel )
49+
self.feature_evaluation_test( mComposition, mLabel, mVectorLayer )
50+
self.page_evaluation_test( mComposition, mLabel, mVectorLayer )
51+
52+
def evaluation_test( self, mComposition, mLabel ):
53+
# $CURRENT_DATE evaluation
54+
mLabel.setText( "__$CURRENT_DATE__" )
55+
assert mLabel.displayText() == ( "__" + QDate.currentDate().toString() + "__" )
56+
57+
# $CURRENT_DATE() evaluation
58+
mLabel.setText( "__$CURRENT_DATE(dd)(ok)__" )
59+
expected = "__" + QDateTime.currentDateTime().toString( "dd" ) + "(ok)__"
60+
assert mLabel.displayText() == expected
61+
62+
# $CURRENT_DATE() evaluation (inside an expression)
63+
mLabel.setText( "__[%$CURRENT_DATE(dd) + 1%](ok)__" )
64+
dd = QDate.currentDate().day()
65+
expected = "__" + QString( "%1" ).arg(dd+1) + "(ok)__"
66+
assert mLabel.displayText() == expected
67+
68+
# expression evaluation (without associated feature)
69+
mLabel.setText( "__[%\"NAME_1\"%][%21*2%]__" )
70+
assert mLabel.displayText() == "__[NAME_1]42__"
71+
72+
def feature_evaluation_test( self, mComposition, mLabel, mVectorLayer ):
73+
provider = mVectorLayer.dataProvider()
74+
75+
provider.select( provider.attributeIndexes() )
76+
feat = QgsFeature()
77+
78+
provider.nextFeature( feat )
79+
mLabel.setExpressionContext( feat, mVectorLayer )
80+
mLabel.setText( "[%\"NAME_1\"||'_ok'%]")
81+
assert mLabel.displayText() == "Basse-Normandie_ok"
82+
83+
provider.nextFeature( feat )
84+
mLabel.setExpressionContext( feat, mVectorLayer )
85+
assert mLabel.displayText() == "Bretagne_ok"
86+
87+
# evaluation with local variables
88+
locs = { "$test" : "OK" }
89+
mLabel.setExpressionContext( feat, mVectorLayer, locs )
90+
mLabel.setText( "[%\"NAME_1\"||$test%]" )
91+
assert mLabel.displayText() == "BretagneOK"
92+
93+
def page_evaluation_test( self, mComposition, mLabel, mVectorLayer ):
94+
mComposition.setNumPages( 2 )
95+
mLabel.setText( "[%$page||'/'||$numpages%]" )
96+
assert mLabel.displayText() == "1/2"
97+
98+
# move the the second page and re-evaluate
99+
mLabel.setItemPosition( 0, 320 )
100+
assert mLabel.displayText() == "2/2"
101+
102+
# use setSpecialColumn
103+
mLabel.setText( "[%$var1 + 1%]" )
104+
QgsExpression.setSpecialColumn( "$var1", QVariant(41) )
105+
assert mLabel.displayText() == "42"
106+
QgsExpression.setSpecialColumn( "$var1", QVariant(99) )
107+
assert mLabel.displayText() == "100"
108+
QgsExpression.unsetSpecialColumn( "$var1" )
109+
assert mLabel.displayText() == "[%$var1 + 1%]"
110+
111+
if __name__ == '__main__':
112+
unittest.main()
113+
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# -*- coding: utf-8 -*-
2+
'''
3+
test_qgscomposermapatlas.py
4+
--------------------------------------
5+
Date : Oct 2012
6+
Copyright : (C) 2012 by Dr. Hugo Mercier
7+
email : hugo dot mercier at oslandia dot com
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
'''
17+
import unittest
18+
from utilities import *
19+
from PyQt4.QtCore import *
20+
from PyQt4.QtGui import *
21+
from PyQt4.QtXml import *
22+
from qgis.core import *
23+
from qgscompositionchecker import QgsCompositionChecker
24+
25+
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()
26+
27+
class TestQgsComposerMapAtlas(unittest.TestCase):
28+
29+
def testCase(self):
30+
TEST_DATA_DIR = unitTestDataPath()
31+
vectorFileInfo = QFileInfo( TEST_DATA_DIR + QDir().separator().toAscii() + "france_parts.shp")
32+
mVectorLayer = QgsVectorLayer( vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr" )
33+
34+
QgsMapLayerRegistry.instance().addMapLayer( mVectorLayer )
35+
36+
# create composition with composer map
37+
mMapRenderer = QgsMapRenderer()
38+
layerStringList = QStringList()
39+
layerStringList.append( mVectorLayer.id() )
40+
mMapRenderer.setLayerSet( layerStringList )
41+
mMapRenderer.setProjectionsEnabled( True )
42+
43+
# select epsg:2154
44+
crs = QgsCoordinateReferenceSystem()
45+
crs.createFromSrid( 2154 )
46+
mMapRenderer.setDestinationCrs( crs )
47+
48+
mComposition = QgsComposition( mMapRenderer )
49+
mComposition.setPaperSize( 297, 210 )
50+
51+
# fix the renderer, fill with green
52+
props = { "color": "0,127,0" }
53+
fillSymbol = QgsFillSymbolV2.createSimple( props )
54+
renderer = QgsSingleSymbolRendererV2( fillSymbol )
55+
mVectorLayer.setRendererV2( renderer )
56+
57+
# the atlas map
58+
mAtlasMap = QgsComposerMap( mComposition, 20, 20, 130, 130 )
59+
mAtlasMap.setFrameEnabled( True )
60+
mAtlasMap.setAtlasCoverageLayer( mVectorLayer )
61+
mComposition.addComposerMap( mAtlasMap )
62+
mComposition.setAtlasMap( mAtlasMap )
63+
64+
# an overview
65+
mOverview = QgsComposerMap( mComposition, 180, 20, 50, 50 )
66+
mOverview.setFrameEnabled( True )
67+
mOverview.setOverviewFrameMap( mAtlasMap.id() )
68+
mComposition.addComposerMap( mOverview )
69+
nextent = QgsRectangle( 49670.718, 6415139.086, 699672.519, 7065140.887 )
70+
mOverview.setNewExtent( nextent )
71+
72+
# header label
73+
mLabel1 = QgsComposerLabel( mComposition )
74+
mComposition.addComposerLabel( mLabel1 )
75+
mLabel1.setText( "[% \"NAME_1\" %] area" )
76+
mLabel1.adjustSizeToText()
77+
mLabel1.setItemPosition( 150, 5 )
78+
79+
# feature number label
80+
mLabel2 = QgsComposerLabel( mComposition )
81+
mComposition.addComposerLabel( mLabel2 )
82+
mLabel2.setText( "# [%$feature || ' / ' || $numfeatures%]" )
83+
mLabel2.adjustSizeToText()
84+
mLabel2.setItemPosition( 150, 200 )
85+
86+
self.filename_test( mComposition )
87+
self.autoscale_render_test( mComposition, mLabel1, TEST_DATA_DIR )
88+
self.fixedscale_render_test( mComposition, mLabel1, TEST_DATA_DIR )
89+
self.hidden_render_test( mComposition, mLabel1, TEST_DATA_DIR )
90+
91+
def filename_test( self, mComposition ):
92+
atlasRender = QgsAtlasRendering( mComposition )
93+
atlasRender.begin( "'output_' || $feature" )
94+
for i in range(0, atlasRender.numFeatures()):
95+
atlasRender.prepareForFeature( i )
96+
expected = QString( "output_%1" ).arg(i+1)
97+
print atlasRender.currentFilename()
98+
assert atlasRender.currentFilename() == expected
99+
atlasRender.end()
100+
101+
def autoscale_render_test( self, mComposition, mLabel1, TEST_DATA_DIR ):
102+
atlasMap = mComposition.atlasMap()
103+
atlasMap.setAtlasFixedScale( False )
104+
atlasMap.setAtlasMargin( 0.10 )
105+
106+
atlasRender = QgsAtlasRendering( mComposition )
107+
108+
atlasRender.begin()
109+
110+
for i in range(0, 2):
111+
atlasRender.prepareForFeature( i )
112+
mLabel1.adjustSizeToText()
113+
114+
checker = QgsCompositionChecker()
115+
res = checker.testComposition( "Atlas autoscale test", mComposition, \
116+
QString( TEST_DATA_DIR ) + QDir.separator() + \
117+
"control_images" + QDir.separator() + \
118+
"expected_composermapatlas" + QDir.separator() + \
119+
QString( "autoscale_%1.png" ).arg( i ) )
120+
assert res[0] == True
121+
atlasRender.end()
122+
123+
def fixedscale_render_test( self, mComposition, mLabel1, TEST_DATA_DIR ):
124+
atlasMap = mComposition.atlasMap()
125+
atlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
126+
atlasMap.setAtlasFixedScale( True )
127+
128+
atlasRender = QgsAtlasRendering( mComposition )
129+
130+
atlasRender.begin()
131+
132+
for i in range(0, 2):
133+
atlasRender.prepareForFeature( i )
134+
mLabel1.adjustSizeToText()
135+
136+
checker = QgsCompositionChecker()
137+
res = checker.testComposition( "Atlas fixed scale test", mComposition, \
138+
QString( TEST_DATA_DIR ) + QDir.separator() + \
139+
"control_images" + QDir.separator() + \
140+
"expected_composermapatlas" + QDir.separator() + \
141+
QString( "fixedscale_%1.png" ).arg( i ) )
142+
assert res[0] == True
143+
atlasRender.end()
144+
145+
def hidden_render_test( self, mComposition, mLabel1, TEST_DATA_DIR ):
146+
atlasMap = mComposition.atlasMap()
147+
atlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
148+
atlasMap.setAtlasFixedScale( True )
149+
atlasMap.setAtlasHideCoverage( True )
150+
151+
atlasRender = QgsAtlasRendering( mComposition )
152+
153+
atlasRender.begin()
154+
155+
for i in range(0, 2):
156+
atlasRender.prepareForFeature( i )
157+
mLabel1.adjustSizeToText()
158+
159+
checker = QgsCompositionChecker()
160+
res = checker.testComposition( "Atlas hidden test", mComposition, \
161+
QString( TEST_DATA_DIR ) + QDir.separator() + \
162+
"control_images" + QDir.separator() + \
163+
"expected_composermapatlas" + QDir.separator() + \
164+
QString( "hiding_%1.png" ).arg( i ) )
165+
assert res[0] == True
166+
atlasRender.end()
167+
168+
if __name__ == '__main__':
169+
unittest.main()
170+

0 commit comments

Comments
 (0)
Please sign in to comment.