Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE][composer] Data defined style preset for composer maps
Sponsored by City of Uster
  • Loading branch information
nyalldawson committed Aug 19, 2015
1 parent bcaee65 commit b87e5f7
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 8 deletions.
1 change: 1 addition & 0 deletions python/core/composer/qgscomposerobject.sip
Expand Up @@ -41,6 +41,7 @@ class QgsComposerObject : QObject
MapYMax, /*!< map extent y maximum */
MapAtlasMargin, /*!< map atlas margin*/
MapLayers, /*!< map layer set*/
MapStylePreset, /*!< layer and style visibility preset */
//composer picture
PictureSource, /*!< picture source url */
//html item
Expand Down
11 changes: 11 additions & 0 deletions src/app/composer/qgscomposermapwidget.cpp
Expand Up @@ -175,6 +175,9 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap )
connect( mLayersDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedProperty() ) );
connect( mLayersDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedProperty() ) );

connect( mStylePresetsDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedProperty() ) );
connect( mStylePresetsDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedProperty() ) );

updateGuiElements();
loadGridEntries();
loadOverviewEntries();
Expand All @@ -197,6 +200,7 @@ void QgsComposerMapWidget::populateDataDefinedButtons()
mXMaxDDBtn->blockSignals( true );
mYMaxDDBtn->blockSignals( true );
mAtlasMarginDDBtn->blockSignals( true );
mStylePresetsDDBtn->blockSignals( true );
mLayersDDBtn->blockSignals( true );

//initialise buttons to use atlas coverage layer
Expand All @@ -214,6 +218,8 @@ void QgsComposerMapWidget::populateDataDefinedButtons()
QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() );
mAtlasMarginDDBtn->init( vl, mComposerMap->dataDefinedProperty( QgsComposerObject::MapAtlasMargin ),
QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() );
mStylePresetsDDBtn->init( vl, mComposerMap->dataDefinedProperty( QgsComposerObject::MapStylePreset ),
QgsDataDefinedButton::String, tr( "string matching a style preset name" ) );
mLayersDDBtn->init( vl, mComposerMap->dataDefinedProperty( QgsComposerObject::MapLayers ),
QgsDataDefinedButton::String, tr( "list of map layer names separated by | characters" ) );

Expand All @@ -225,6 +231,7 @@ void QgsComposerMapWidget::populateDataDefinedButtons()
mXMaxDDBtn->blockSignals( false );
mYMaxDDBtn->blockSignals( false );
mAtlasMarginDDBtn->blockSignals( false );
mStylePresetsDDBtn->blockSignals( false );
mLayersDDBtn->blockSignals( false );
}

Expand Down Expand Up @@ -258,6 +265,10 @@ QgsComposerObject::DataDefinedProperty QgsComposerMapWidget::ddPropertyForWidget
{
return QgsComposerObject::MapAtlasMargin;
}
else if ( widget == mStylePresetsDDBtn )
{
return QgsComposerObject::MapStylePreset;
}
else if ( widget == mLayersDDBtn )
{
return QgsComposerObject::MapLayers;
Expand Down
42 changes: 35 additions & 7 deletions src/core/composer/qgscomposermap.cpp
Expand Up @@ -33,6 +33,7 @@
#include "qgsvectorlayer.h"
#include "qgspallabeling.h"
#include "qgsexpression.h"
#include "qgsvisibilitypresetcollection.h"

#include "qgslabel.h"
#include "qgslabelattributes.h"
Expand Down Expand Up @@ -132,6 +133,7 @@ void QgsComposerMap::init()
mDataDefinedNames.insert( QgsComposerObject::MapYMax, QString( "dataDefinedMapYMax" ) );
mDataDefinedNames.insert( QgsComposerObject::MapAtlasMargin, QString( "dataDefinedMapAtlasMargin" ) );
mDataDefinedNames.insert( QgsComposerObject::MapLayers, QString( "dataDefinedMapLayers" ) );
mDataDefinedNames.insert( QgsComposerObject::MapStylePreset, QString( "dataDefinedMapStylePreset" ) );
}

void QgsComposerMap::updateToolTip()
Expand Down Expand Up @@ -217,7 +219,7 @@ QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle& extent, const QS
: QStringList(); //exporting decorations such as map frame/grid/overview, so no map layers required
}
jobMapSettings.setLayers( theLayerSet );
jobMapSettings.setLayerStyleOverrides( mLayerStyleOverrides );
jobMapSettings.setLayerStyleOverrides( layerStyleOverridesToRender() );
jobMapSettings.setDestinationCrs( ms.destinationCrs() );
jobMapSettings.setCrsTransformEnabled( ms.hasCrsTransformEnabled() );
jobMapSettings.setFlags( ms.flags() );
Expand Down Expand Up @@ -522,18 +524,30 @@ const QgsMapRenderer *QgsComposerMap::mapRenderer() const

QStringList QgsComposerMap::layersToRender() const
{
//use stored layer set or read current set from main canvas
QStringList renderLayerSet;
if ( mKeepLayerSet )

QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal ) )
{
renderLayerSet = mLayerSet;
QString presetName = exprVal.toString();

if ( QgsProject::instance()->visibilityPresetCollection()->hasPreset( presetName ) )
renderLayerSet = QgsProject::instance()->visibilityPresetCollection()->presetVisibleLayers( presetName );
}
else

//use stored layer set or read current set from main canvas
if ( renderLayerSet.isEmpty() )
{
renderLayerSet = mComposition->mapSettings().layers();
if ( mKeepLayerSet )
{
renderLayerSet = mLayerSet;
}
else
{
renderLayerSet = mComposition->mapSettings().layers();
}
}

QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapLayers, exprVal ) )
{
renderLayerSet.clear();
Expand Down Expand Up @@ -568,6 +582,20 @@ QStringList QgsComposerMap::layersToRender() const
return renderLayerSet;
}

QMap<QString, QString> QgsComposerMap::layerStyleOverridesToRender() const
{
QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal ) )
{
QString presetName = exprVal.toString();

if ( QgsProject::instance()->visibilityPresetCollection()->hasPreset( presetName ) )
return QgsProject::instance()->visibilityPresetCollection()->presetStyleOverrides( presetName );

}
return mLayerStyleOverrides;
}

double QgsComposerMap::scale() const
{
QgsScaleCalculator calculator;
Expand Down
3 changes: 3 additions & 0 deletions src/core/composer/qgscomposermap.h
Expand Up @@ -921,6 +921,9 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/** Returns a list of the layers to render for this map item*/
QStringList layersToRender() const;

/** Returns current layer style overrides for this map item*/
QMap<QString, QString> layerStyleOverridesToRender() const;

/** Returns extent that considers mOffsetX / mOffsetY (during content move)*/
QgsRectangle transformedExtent() const;

Expand Down
1 change: 1 addition & 0 deletions src/core/composer/qgscomposerobject.h
Expand Up @@ -66,6 +66,7 @@ class CORE_EXPORT QgsComposerObject: public QObject
MapYMax, /*!< map extent y maximum */
MapAtlasMargin, /*!< map atlas margin*/
MapLayers, /*!< map layer set*/
MapStylePreset, /*!< layer and style visibility preset */
//composer picture
PictureSource, /*!< picture source url */
//html item
Expand Down
10 changes: 9 additions & 1 deletion src/ui/qgscomposermapwidgetbase.ui
Expand Up @@ -65,7 +65,7 @@
<x>0</x>
<y>0</y>
<width>446</width>
<height>2490</height>
<height>2493</height>
</rect>
</property>
<property name="sizePolicy">
Expand Down Expand Up @@ -230,6 +230,13 @@
</property>
</widget>
</item>
<item>
<widget class="QgsDataDefinedButton" name="mStylePresetsDDBtn">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
Expand Down Expand Up @@ -1438,6 +1445,7 @@
<tabstop>mLayerListFromPresetButton</tabstop>
<tabstop>mLayersDDBtn</tabstop>
<tabstop>mKeepLayerStylesCheckBox</tabstop>
<tabstop>mStylePresetsDDBtn</tabstop>
<tabstop>mExtentsCheckBox</tabstop>
<tabstop>mXMinLineEdit</tabstop>
<tabstop>mXMinDDBtn</tabstop>
Expand Down
58 changes: 58 additions & 0 deletions tests/src/core/testqgscomposermap.cpp
Expand Up @@ -24,6 +24,8 @@
#include "qgsmultibandcolorrenderer.h"
#include "qgsrasterlayer.h"
#include "qgsvectorlayer.h"
#include "qgsproject.h"
#include "qgsvisibilitypresetcollection.h"
#include <QObject>
#include <QtTest/QtTest>

Expand All @@ -49,6 +51,7 @@ class TestQgsComposerMap : public QObject
void worldFileGeneration(); // test world file generation
void mapPolygonVertices(); // test mapPolygon function with no map rotation
void dataDefinedLayers(); //test data defined layer string
void dataDefinedStyles(); //test data defined styles

private:
QgsComposition *mComposition;
Expand Down Expand Up @@ -279,5 +282,60 @@ void TestQgsComposerMap::dataDefinedLayers()
QVERIFY( checker.testComposition( mReport, 0, 0 ) );
}

void TestQgsComposerMap::dataDefinedStyles()
{
delete mComposition;
QgsMapSettings ms;
ms.setLayers( QStringList() << mRasterLayer->id() << mPolysLayer->id() << mPointsLayer->id() << mLinesLayer->id() );
ms.setCrsTransformEnabled( true );

mComposition = new QgsComposition( ms );
mComposition->setPaperSize( 297, 210 ); //A4 landscape
mComposerMap = new QgsComposerMap( mComposition, 20, 20, 200, 100 );
mComposerMap->setFrameEnabled( true );
mComposition->addComposerMap( mComposerMap );

QgsVisibilityPresetCollection::PresetRecord rec;
rec.mVisibleLayerIDs.insert( mPointsLayer->id() );
rec.mVisibleLayerIDs.insert( mLinesLayer->id() );

QgsProject::instance()->visibilityPresetCollection()->insert( "test preset", rec );

//test malformed style string
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapStylePreset, true, true, "5", QString() );
QSet<QString> result = mComposerMap->layersToRender().toSet();
QCOMPARE( result, ms.layers().toSet() );

//test valid preset
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapStylePreset, true, true, QString( "'test preset'" ), QString() );
result = mComposerMap->layersToRender().toSet();
QCOMPARE( result.count(), 2 );
QVERIFY( result.contains( mLinesLayer->id() ) );
QVERIFY( result.contains( mPointsLayer->id() ) );

//test non-existant preset
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapStylePreset, true, true,
QString( "'bad preset'" ), QString() );
result = mComposerMap->layersToRender().toSet();
QCOMPARE( result, ms.layers().toSet() );

//test that dd layer set overrides style layers
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapStylePreset, true, true, QString( "'test preset'" ), QString() );
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapLayers, true, true,
QString( "'%1'" ).arg( mPolysLayer->name() ), QString() );
result = mComposerMap->layersToRender().toSet();
QCOMPARE( result.count(), 1 );
QVERIFY( result.contains( mPolysLayer->id() ) );
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapLayers, false, true, QString(), QString() );

//render test
mComposerMap->setDataDefinedProperty( QgsComposerObject::MapStylePreset, true, true,
QString( "'test preset'" ), QString() );
mComposerMap->setNewExtent( QgsRectangle( -110.0, 25.0, -90, 40.0 ) );

QgsCompositionChecker checker( "composermap_ddstyles", mComposition );
QVERIFY( checker.testComposition( mReport, 0, 0 ) );
}

QTEST_MAIN( TestQgsComposerMap )
#include "testqgscomposermap.moc"
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b87e5f7

Please sign in to comment.