Skip to content

Commit

Permalink
Merge pull request #3064 from wonder-sk/composer-map-follow-preset
Browse files Browse the repository at this point in the history
Composer map to follow a visibility preset
  • Loading branch information
wonder-sk committed May 18, 2016
2 parents 5dd88c9 + 292a8a4 commit a9c1996
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 102 deletions.
21 changes: 21 additions & 0 deletions python/core/composer/qgscomposermap.sip
Expand Up @@ -223,6 +223,27 @@ class QgsComposerMap : QgsComposerItem
/** Stores the current layer styles into style overrides. @note added in 2.8 */
void storeCurrentLayerStyles();

/** Whether the map should follow a visibility preset. If true, the layers and layer styles
* will be used from given preset name (configured with setFollowVisibilityPresetName() method).
* This means when preset's settings are changed, the new settings are automatically
* picked up next time when rendering, without having to explicitly update them.
* At most one of the flags keepLayerSet() and followVisibilityPreset() should be enabled
* at any time since they are alternative approaches - if both are enabled,
* following visibility preset has higher priority. If neither is enabled (or if preset name is not set),
* map will use the same configuration as the map canvas uses.
* @note added in 2.16 */
bool followVisibilityPreset() const;
/** Sets whether the map should follow a visibility preset. See followVisibilityPreset() for more details.
* @note added in 2.16 */
void setFollowVisibilityPreset( bool follow );
/** Preset name that decides which layers and layer styles are used for map rendering. It is only
* used when followVisibilityPreset() returns true.
* @note added in 2.16 */
QString followVisibilityPresetName() const;
/** Sets preset name for map rendering. See followVisibilityPresetName() for more details.
* @note added in 2.16 */
void setFollowVisibilityPresetName( const QString& name );

// Set cache outdated
void setCacheUpdated( bool u = false );

Expand Down
105 changes: 93 additions & 12 deletions src/app/composer/qgscomposermapwidget.cpp
Expand Up @@ -125,12 +125,19 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap )
//set initial state of frame style controls
toggleFrameControls( false, false, false );

QMenu* m = new QMenu( this );
mLayerListFromPresetButton->setMenu( m );
// follow preset combo
mFollowVisibilityPresetCombo->setModel( new QStringListModel( mFollowVisibilityPresetCombo ) );
connect( mFollowVisibilityPresetCombo, SIGNAL( currentIndexChanged( int ) ), this, SLOT( followVisibilityPresetSelected( int ) ) );
connect( QgsProject::instance()->visibilityPresetCollection(), SIGNAL( presetsChanged() ),
this, SLOT( onPresetsChanged() ) );
onPresetsChanged();

// keep layers from preset button
QMenu* menuKeepLayers = new QMenu( this );
mLayerListFromPresetButton->setMenu( menuKeepLayers );
mLayerListFromPresetButton->setIcon( QgsApplication::getThemeIcon( "/mActionShowAllLayers.png" ) );
mLayerListFromPresetButton->setToolTip( tr( "Set layer list from a visibility preset" ) );

connect( m, SIGNAL( aboutToShow() ), this, SLOT( aboutToShowVisibilityPresetsMenu() ) );
connect( menuKeepLayers, SIGNAL( aboutToShow() ), this, SLOT( aboutToShowKeepLayersVisibilityPresetsMenu() ) );

if ( composerMap )
{
Expand Down Expand Up @@ -301,28 +308,50 @@ void QgsComposerMapWidget::compositionAtlasToggled( bool atlasEnabled )
}
}

void QgsComposerMapWidget::aboutToShowVisibilityPresetsMenu()
void QgsComposerMapWidget::aboutToShowKeepLayersVisibilityPresetsMenu()
{
// this menu is for the case when setting "keep layers" and "keep layer styles"
// and the preset configuration is copied. The preset is not followed further.

QMenu* menu = qobject_cast<QMenu*>( sender() );
if ( !menu )
return;

menu->clear();
Q_FOREACH ( const QString& presetName, QgsProject::instance()->visibilityPresetCollection()->presets() )
{
QAction* a = menu->addAction( presetName, this, SLOT( visibilityPresetSelected() ) );
a->setCheckable( true );
QStringList layers = QgsVisibilityPresets::instance()->orderedPresetVisibleLayers( presetName );
QMap<QString, QString> styles = QgsProject::instance()->visibilityPresetCollection()->presetStyleOverrides( presetName );
if ( layers == mComposerMap->layerSet() && styles == mComposerMap->layerStyleOverrides() )
a->setChecked( true );
menu->addAction( presetName, this, SLOT( keepLayersVisibilityPresetSelected() ) );
}

if ( menu->actions().isEmpty() )
menu->addAction( tr( "No presets defined" ) )->setEnabled( false );
}

void QgsComposerMapWidget::visibilityPresetSelected()
void QgsComposerMapWidget::followVisibilityPresetSelected( int currentIndex )
{
if ( !mComposerMap )
return;

if ( currentIndex == -1 )
return; // doing combo box model reset

QString presetName;
if ( currentIndex != 0 )
{
presetName = mFollowVisibilityPresetCombo->currentText();
}

if ( presetName == mComposerMap->followVisibilityPresetName() )
return;

mFollowVisibilityPresetCheckBox->setChecked( true );
mComposerMap->setFollowVisibilityPresetName( presetName );

mComposerMap->cache();
mComposerMap->update();
}

void QgsComposerMapWidget::keepLayersVisibilityPresetSelected()
{
QAction* action = qobject_cast<QAction*>( sender() );
if ( !action )
Expand All @@ -344,6 +373,23 @@ void QgsComposerMapWidget::visibilityPresetSelected()
}
}

void QgsComposerMapWidget::onPresetsChanged()
{
if ( QStringListModel* model = qobject_cast<QStringListModel*>( mFollowVisibilityPresetCombo->model() ) )
{
QStringList lst;
lst.append( tr( "(none)" ) );
lst += QgsProject::instance()->visibilityPresetCollection()->presets();
model->setStringList( lst );

// select the previously selected item again
int presetModelIndex = mFollowVisibilityPresetCombo->findText( mComposerMap->followVisibilityPresetName() );
mFollowVisibilityPresetCombo->blockSignals( true );
mFollowVisibilityPresetCombo->setCurrentIndex( presetModelIndex != -1 ? presetModelIndex : 0 ); // 0 == none
mFollowVisibilityPresetCombo->blockSignals( false );
}
}

void QgsComposerMapWidget::on_mAtlasCheckBox_toggled( bool checked )
{
if ( !mComposerMap )
Expand Down Expand Up @@ -668,6 +714,12 @@ void QgsComposerMapWidget::updateGuiElements()

mMapRotationSpinBox->setValue( mComposerMap->mapRotation( QgsComposerObject::OriginalValue ) );

// follow preset check box
mFollowVisibilityPresetCheckBox->setCheckState(
mComposerMap->followVisibilityPreset() ? Qt::Checked : Qt::Unchecked );
int presetModelIndex = mFollowVisibilityPresetCombo->findText( mComposerMap->followVisibilityPresetName() );
mFollowVisibilityPresetCombo->setCurrentIndex( presetModelIndex != -1 ? presetModelIndex : 0 ); // 0 == none

//keep layer list check box
if ( mComposerMap->keepLayerSet() )
{
Expand Down Expand Up @@ -797,6 +849,8 @@ void QgsComposerMapWidget::blockAllSignals( bool b )
mAtlasMarginSpinBox->blockSignals( b );
mAtlasFixedScaleRadio->blockSignals( b );
mAtlasMarginRadio->blockSignals( b );
mFollowVisibilityPresetCheckBox->blockSignals( b );
mFollowVisibilityPresetCombo->blockSignals( b );
mKeepLayerListCheckBox->blockSignals( b );
mKeepLayerStylesCheckBox->blockSignals( b );
mSetToMapCanvasExtentButton->blockSignals( b );
Expand Down Expand Up @@ -897,6 +951,30 @@ void QgsComposerMapWidget::on_mUpdatePreviewButton_clicked()
mUpdatePreviewButton->setEnabled( true );
}

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

if ( state == Qt::Checked )
{
mComposerMap->setFollowVisibilityPreset( true );

// mutually exclusive with keeping custom layer list
mKeepLayerListCheckBox->setCheckState( Qt::Unchecked );
mKeepLayerStylesCheckBox->setCheckState( Qt::Unchecked );

mComposerMap->cache();
mComposerMap->update();
}
else
{
mComposerMap->setFollowVisibilityPreset( false );
}
}

void QgsComposerMapWidget::on_mKeepLayerListCheckBox_stateChanged( int state )
{
if ( !mComposerMap )
Expand All @@ -908,6 +986,9 @@ void QgsComposerMapWidget::on_mKeepLayerListCheckBox_stateChanged( int state )
{
mComposerMap->storeCurrentLayerSet();
mComposerMap->setKeepLayerSet( true );

// mutually exclusive with following a preset
mFollowVisibilityPresetCheckBox->setCheckState( Qt::Unchecked );
}
else
{
Expand Down
8 changes: 6 additions & 2 deletions src/app/composer/qgscomposermapwidget.h
Expand Up @@ -43,6 +43,7 @@ class QgsComposerMapWidget: public QgsComposerItemBaseWidget, private Ui::QgsCom
void on_mSetToMapCanvasExtentButton_clicked();
void on_mViewExtentInCanvasButton_clicked();
void on_mUpdatePreviewButton_clicked();
void on_mFollowVisibilityPresetCheckBox_stateChanged( int state );
void on_mKeepLayerListCheckBox_stateChanged( int state );
void on_mKeepLayerStylesCheckBox_stateChanged( int state );
void on_mDrawCanvasItemsCheckBox_stateChanged( int state );
Expand Down Expand Up @@ -168,9 +169,12 @@ class QgsComposerMapWidget: public QgsComposerItemBaseWidget, private Ui::QgsCom
/** Enables or disables the atlas controls when composer atlas is toggled on/off*/
void compositionAtlasToggled( bool atlasEnabled );

void aboutToShowVisibilityPresetsMenu();
void aboutToShowKeepLayersVisibilityPresetsMenu();

void visibilityPresetSelected();
void followVisibilityPresetSelected( int currentIndex );
void keepLayersVisibilityPresetSelected();

void onPresetsChanged();

private:
QgsComposerMap* mComposerMap;
Expand Down
65 changes: 46 additions & 19 deletions src/core/composer/qgscomposermap.cpp
Expand Up @@ -53,6 +53,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w
, mEvaluatedMapRotation( 0 )
, mKeepLayerSet( false )
, mKeepLayerStyles( false )
, mFollowVisibilityPreset( false )
, mUpdatesEnabled( true )
, mMapCanvas( nullptr )
, mDrawCanvasItems( true )
Expand Down Expand Up @@ -98,6 +99,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition )
, mEvaluatedMapRotation( 0 )
, mKeepLayerSet( false )
, mKeepLayerStyles( false )
, mFollowVisibilityPreset( false )
, mUpdatesEnabled( true )
, mMapCanvas( nullptr )
, mDrawCanvasItems( true )
Expand Down Expand Up @@ -537,28 +539,32 @@ QStringList QgsComposerMap::layersToRender( const QgsExpressionContext* context

QStringList renderLayerSet;

QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal, *evalContext ) )
if ( mFollowVisibilityPreset )
{
QString presetName = exprVal.toString();
QString presetName = mFollowVisibilityPresetName;

// preset name can be overridden by data-defined one
QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal, *evalContext ) )
{
presetName = exprVal.toString();
}

if ( QgsProject::instance()->visibilityPresetCollection()->hasPreset( presetName ) )
renderLayerSet = QgsProject::instance()->visibilityPresetCollection()->presetVisibleLayers( presetName );
else // fallback to using map canvas layers
renderLayerSet = mComposition->mapSettings().layers();
}

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

QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapLayers, exprVal, *evalContext ) )
{
renderLayerSet.clear();
Expand Down Expand Up @@ -595,16 +601,29 @@ QStringList QgsComposerMap::layersToRender( const QgsExpressionContext* context

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

QVariant exprVal;
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal, context ) )
{
presetName = exprVal.toString();
}

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

else
return QMap<QString, QString>();
}
else if ( mKeepLayerStyles )
{
return mLayerStyleOverrides;
}
else
{
return QMap<QString, QString>();
}
return mLayerStyleOverrides;
}

double QgsComposerMap::scale() const
Expand Down Expand Up @@ -1294,6 +1313,10 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) );
composerMapElem.appendChild( extentElem );

// follow visibility preset
composerMapElem.setAttribute( "followPreset", mFollowVisibilityPreset ? "true" : "false" );
composerMapElem.setAttribute( "followPresetName", mFollowVisibilityPresetName );

//map rotation
composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) );

Expand Down Expand Up @@ -1395,6 +1418,10 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d
mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble();
}

// follow visibility preset
mFollowVisibilityPreset = itemElem.attribute( "followPreset" ).compare( "true" ) == 0;
mFollowVisibilityPresetName = itemElem.attribute( "followPresetName" );

//mKeepLayerSet flag
QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
Expand Down
29 changes: 29 additions & 0 deletions src/core/composer/qgscomposermap.h
Expand Up @@ -262,6 +262,27 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/** Stores the current layer styles into style overrides. @note added in 2.8 */
void storeCurrentLayerStyles();

/** Whether the map should follow a visibility preset. If true, the layers and layer styles
* will be used from given preset name (configured with setFollowVisibilityPresetName() method).
* This means when preset's settings are changed, the new settings are automatically
* picked up next time when rendering, without having to explicitly update them.
* At most one of the flags keepLayerSet() and followVisibilityPreset() should be enabled
* at any time since they are alternative approaches - if both are enabled,
* following visibility preset has higher priority. If neither is enabled (or if preset name is not set),
* map will use the same configuration as the map canvas uses.
* @note added in 2.16 */
bool followVisibilityPreset() const { return mFollowVisibilityPreset; }
/** Sets whether the map should follow a visibility preset. See followVisibilityPreset() for more details.
* @note added in 2.16 */
void setFollowVisibilityPreset( bool follow ) { mFollowVisibilityPreset = follow; }
/** Preset name that decides which layers and layer styles are used for map rendering. It is only
* used when followVisibilityPreset() returns true.
* @note added in 2.16 */
QString followVisibilityPresetName() const { return mFollowVisibilityPresetName; }
/** Sets preset name for map rendering. See followVisibilityPresetName() for more details.
* @note added in 2.16 */
void setFollowVisibilityPresetName( const QString& name ) { mFollowVisibilityPresetName = name; }

// Set cache outdated
void setCacheUpdated( bool u = false );

Expand Down Expand Up @@ -888,6 +909,14 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
/** Stored style names (value) to be used with particular layer IDs (key) instead of default style */
QMap<QString, QString> mLayerStyleOverrides;

/** Whether layers and styles should be used from a preset (preset name is stored
* in mVisibilityPresetName and may be overridden by data-defined expression).
* This flag has higher priority than mKeepLayerSet. */
bool mFollowVisibilityPreset;
/** Visibility preset name to be used for map's layers and styles in case mFollowVisibilityPreset
* is true. May be overridden by data-defined expression. */
QString mFollowVisibilityPresetName;

/** Whether updates to the map are enabled */
bool mUpdatesEnabled;

Expand Down

0 comments on commit a9c1996

Please sign in to comment.