Skip to content

Commit

Permalink
GUI for configuration of size-based legend for diagrams
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Jun 19, 2017
1 parent ea8a2c2 commit 517fefe
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 133 deletions.
3 changes: 2 additions & 1 deletion doc/api_break.dox
Expand Up @@ -987,7 +987,8 @@ QgsDiagramRenderer {#qgis_api_break_3_0_QgsDiagramRenderer}
- renderDiagram() now takes an optional data defined overrides collection argument.
- readXml(), _readXml(), writeXml(), _writeXml() do not take QgsVectorLayer as an argument anymore.
- readXml(), _readXml(), writeXml(), _writeXml() require a new argument: a reference to QgsReadWriteContext

- sizeLegend() and setSizeLegend() have been replaced by dataDefinedSizeLegend() and setDataDefinedSizeLegend() methods.
- sizeLegendSymbol() and setSizeLegendSymbol() have been moved to QgsLinearlyInterpolatedDiagramRenderer subclass.


QgsDiagramLayerSettings {#qgis_api_break_3_0_QgsDiagramLayerSettings}
Expand Down
58 changes: 18 additions & 40 deletions python/core/qgsdiagramrenderer.sip
Expand Up @@ -545,44 +545,6 @@ Returns list with all diagram settings in the renderer
.. versionadded:: 2.16
.. seealso:: attributeLegend()
.. seealso:: setSizeLegend()
%End

bool sizeLegend() const;
%Docstring
Returns true if renderer will show legend items for diagram sizes.
.. versionadded:: 2.16
.. seealso:: setSizeLegend()
.. seealso:: attributeLegend()
.. seealso:: sizeLegendSymbol()
:rtype: bool
%End

void setSizeLegend( bool enabled );
%Docstring
Sets whether the renderer will show legend items for diagram sizes.
\param enabled set to true to show diagram size legend
.. versionadded:: 2.16
.. seealso:: sizeLegend()
.. seealso:: setAttributeLegend()
.. seealso:: setSizeLegendSymbol()
%End

QgsMarkerSymbol *sizeLegendSymbol() const;
%Docstring
Returns the marker symbol used for rendering the diagram size legend.
.. versionadded:: 2.16
.. seealso:: setSizeLegendSymbol()
.. seealso:: sizeLegend()
:rtype: QgsMarkerSymbol
%End

void setSizeLegendSymbol( QgsMarkerSymbol *symbol /Transfer/ );
%Docstring
Sets the marker symbol used for rendering the diagram size legend.
\param symbol marker symbol, ownership is transferred to the renderer.
.. versionadded:: 2.16
.. seealso:: sizeLegendSymbol()
.. seealso:: setSizeLegend()
%End

protected:
Expand Down Expand Up @@ -628,8 +590,6 @@ Returns the paint device dpi (or -1 in case of error
%End




};

class QgsSingleCategoryDiagramRenderer : QgsDiagramRenderer
Expand Down Expand Up @@ -760,6 +720,24 @@ Returns list with all diagram settings in the renderer
virtual QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const /Factory/;


QgsMarkerSymbol *sizeLegendSymbol() const;
%Docstring
Returns the marker symbol used for rendering the diagram size legend.
.. versionadded:: 2.16
.. seealso:: setSizeLegendSymbol()
.. seealso:: sizeLegend()
:rtype: QgsMarkerSymbol
%End

void setSizeLegendSymbol( QgsMarkerSymbol *symbol /Transfer/ );
%Docstring
Sets the marker symbol used for rendering the diagram size legend.
\param symbol marker symbol, ownership is transferred to the renderer.
.. versionadded:: 2.16
.. seealso:: sizeLegendSymbol()
.. seealso:: setSizeLegend()
%End

void setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings /Transfer/ );
%Docstring
Configures appearance of legend. Takes ownership of the passed settings objects.
Expand Down
54 changes: 39 additions & 15 deletions src/app/qgsdiagramproperties.cpp
Expand Up @@ -21,6 +21,8 @@

#include "qgsproject.h"
#include "qgsapplication.h"
#include "qgsdatadefinedsizelegend.h"
#include "qgsdatadefinedsizelegenddialog.h"
#include "qgsdiagramproperties.h"
#include "qgsdiagramrenderer.h"
#include "qgslabelengineconfigdialog.h"
Expand Down Expand Up @@ -188,6 +190,8 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
}

mSizeLegendSymbol.reset( QgsMarkerSymbol::createSimple( QgsStringMap() ) );

const QgsDiagramRenderer *dr = layer->diagramRenderer();
if ( !dr ) //no diagram renderer yet, insert reasonable default
{
Expand All @@ -208,8 +212,6 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
mScaleRangeWidget->setScaleRange( layer->minimumScale(), layer->maximumScale() );
mShowAllCheckBox->setChecked( true );
mCheckBoxAttributeLegend->setChecked( true );
mCheckBoxSizeLegend->setChecked( false );
mSizeLegendSymbol.reset( QgsMarkerSymbol::createSimple( QgsStringMap() ) );

switch ( layerType )
{
Expand Down Expand Up @@ -248,10 +250,6 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
mLinearScaleFrame->setEnabled( mAttributeBasedScalingRadio->isChecked() );
mCheckBoxAttributeLegend->setChecked( dr->attributeLegend() );
mCheckBoxSizeLegend->setChecked( dr->sizeLegend() );
mSizeLegendSymbol.reset( dr->sizeLegendSymbol() ? dr->sizeLegendSymbol()->clone() : QgsMarkerSymbol::createSimple( QgsStringMap() ) );
QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mSizeLegendSymbol.get(), mButtonSizeLegendSymbol->iconSize() );
mButtonSizeLegendSymbol->setIcon( icon );

//assume single category or linearly interpolated diagram renderer for now
QList<QgsDiagramSettings> settingList = dr->diagramSettings();
Expand Down Expand Up @@ -361,6 +359,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
{
mSizeFieldExpressionWidget->setField( lidr->classificationField() );
}

mSizeLegendSymbol.reset( lidr->sizeLegendSymbol() ? lidr->sizeLegendSymbol()->clone() : QgsMarkerSymbol::createSimple( QgsStringMap() ) );
mSizeLegend.reset( lidr->dataDefinedSizeLegend() ? new QgsDataDefinedSizeLegend( *lidr->dataDefinedSizeLegend() ) : nullptr );
}
}

Expand Down Expand Up @@ -401,6 +402,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
}
}

QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mSizeLegendSymbol.get(), mButtonSizeLegendSymbol->iconSize() );
mButtonSizeLegendSymbol->setIcon( icon );

connect( mAddAttributeExpression, &QPushButton::clicked, this, &QgsDiagramProperties::showAddAttributeExpressionDialog );
registerDataDefinedButton( mBackgroundColorDDBtn, QgsDiagramLayerSettings::BackgroundColor );
registerDataDefinedButton( mLineColorDDBtn, QgsDiagramLayerSettings::StrokeColor );
Expand All @@ -414,6 +418,8 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare
registerDataDefinedButton( mAlwaysShowDDBtn, QgsDiagramLayerSettings::AlwaysShow );
registerDataDefinedButton( mIsObstacleDDBtn, QgsDiagramLayerSettings::IsObstacle );
registerDataDefinedButton( mStartAngleDDBtn, QgsDiagramLayerSettings::StartAngle );

connect( mButtonSizeLegendSettings, &QPushButton::clicked, this, &QgsDiagramProperties::showSizeLegendDialog );
}

QgsDiagramProperties::~QgsDiagramProperties()
Expand Down Expand Up @@ -811,12 +817,14 @@ void QgsDiagramProperties::apply()
dr->setClassificationField( sizeFieldNameOrExp );
}
dr->setDiagramSettings( ds );

dr->setSizeLegendSymbol( mSizeLegendSymbol->clone() );
dr->setDataDefinedSizeLegend( mSizeLegend ? new QgsDataDefinedSizeLegend( *mSizeLegend ) : nullptr );

renderer = dr;
}
renderer->setDiagram( diagram );
renderer->setAttributeLegend( mCheckBoxAttributeLegend->isChecked() );
renderer->setSizeLegend( mCheckBoxSizeLegend->isChecked() );
renderer->setSizeLegendSymbol( mSizeLegendSymbol->clone() );
mLayer->setDiagramRenderer( renderer );

QgsDiagramLayerSettings dls;
Expand Down Expand Up @@ -958,13 +966,29 @@ void QgsDiagramProperties::on_mButtonSizeLegendSymbol_clicked()

void QgsDiagramProperties::scalingTypeChanged()
{
if ( !mAttributeBasedScalingRadio->isChecked() )
{
mCheckBoxSizeLegend->setChecked( false );
mCheckBoxSizeLegend->setEnabled( false );
}
else
mSizeLegendGroupBox->setEnabled( mAttributeBasedScalingRadio->isChecked() );
}

void QgsDiagramProperties::showSizeLegendDialog()
{
QgsDataDefinedSizeLegendDialog dlg( mSizeLegend.get() );
QgsMarkerSymbol *symbol = mSizeLegendSymbol->clone();

// prepare size transformer
bool isExpression;
QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
QgsProperty ddSize = isExpression ? QgsProperty::fromExpression( sizeFieldNameOrExp ) : QgsProperty::fromField( sizeFieldNameOrExp );
ddSize.setTransformer( new QgsSizeScaleTransformer( QgsSizeScaleTransformer::Linear, 0.0, mMaxValueSpinBox->value(), 0.0, mSizeSpinBox->value() ) );
symbol->setDataDefinedSize( ddSize );
dlg.setSourceSymbol( symbol );

if ( mMapCanvas )
{
mCheckBoxSizeLegend->setEnabled( true );
dlg.setLegendMapViewData( mMapCanvas->mapUnitsPerPixel(), mMapCanvas->mapSettings().outputDpi(), mMapCanvas->scale() );
}

if ( !dlg.exec() )
return;

mSizeLegend.reset( dlg.dataDefinedSizeLegend() );
}
2 changes: 2 additions & 0 deletions src/app/qgsdiagramproperties.h
Expand Up @@ -54,6 +54,7 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
void on_mPlacementComboBox_currentIndexChanged( int index );
void on_mButtonSizeLegendSymbol_clicked();
void scalingTypeChanged();
void showSizeLegendDialog();

protected:
QFont mDiagramFont;
Expand Down Expand Up @@ -81,6 +82,7 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
// Keeps track of the diagram type to properly save / restore settings when the diagram type combo box is set to no diagram.
QString mDiagramType;
std::unique_ptr< QgsMarkerSymbol > mSizeLegendSymbol;
std::unique_ptr< QgsDataDefinedSizeLegend > mSizeLegend;

QString guessLegendText( const QString &expression );
QgsMapCanvas *mMapCanvas = nullptr;
Expand Down
40 changes: 21 additions & 19 deletions src/core/qgsdiagramrenderer.cpp
Expand Up @@ -398,8 +398,6 @@ void QgsDiagramSettings::writeXml( QDomElement &rendererElem, QDomDocument &doc
QgsDiagramRenderer::QgsDiagramRenderer()
: mDiagram( nullptr )
, mShowAttributeLegend( true )
, mShowSizeLegend( false )
, mSizeLegendSymbol( QgsMarkerSymbol::createSimple( QgsStringMap() ) )
{
}

Expand All @@ -417,17 +415,13 @@ void QgsDiagramRenderer::setDiagram( QgsDiagram *d )
QgsDiagramRenderer::QgsDiagramRenderer( const QgsDiagramRenderer &other )
: mDiagram( other.mDiagram ? other.mDiagram->clone() : nullptr )
, mShowAttributeLegend( other.mShowAttributeLegend )
, mShowSizeLegend( other.mShowSizeLegend )
, mSizeLegendSymbol( other.mSizeLegendSymbol ? other.mSizeLegendSymbol->clone() : nullptr )
{
}

QgsDiagramRenderer &QgsDiagramRenderer::operator=( const QgsDiagramRenderer &other )
{
mDiagram = other.mDiagram ? other.mDiagram->clone() : nullptr;
mShowAttributeLegend = other.mShowAttributeLegend;
mShowSizeLegend = other.mShowSizeLegend;
mSizeLegendSymbol.reset( other.mSizeLegendSymbol ? other.mSizeLegendSymbol->clone() : nullptr );
return *this;
}

Expand Down Expand Up @@ -522,6 +516,7 @@ int QgsDiagramRenderer::dpiPaintDevice( const QPainter *painter )

void QgsDiagramRenderer::_readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
Q_UNUSED( context );
delete mDiagram;
QString diagramType = elem.attribute( QStringLiteral( "diagramType" ) );
if ( diagramType == QLatin1String( "Pie" ) )
Expand All @@ -541,26 +536,18 @@ void QgsDiagramRenderer::_readXml( const QDomElement &elem, const QgsReadWriteCo
mDiagram = nullptr;
}
mShowAttributeLegend = ( elem.attribute( QStringLiteral( "attributeLegend" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
mShowSizeLegend = ( elem.attribute( QStringLiteral( "sizeLegend" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
QDomElement sizeLegendSymbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
if ( !sizeLegendSymbolElem.isNull() && sizeLegendSymbolElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "sizeSymbol" ) )
{
mSizeLegendSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( sizeLegendSymbolElem, context ) );
}
}

void QgsDiagramRenderer::_writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
{
Q_UNUSED( doc );
Q_UNUSED( context );

if ( mDiagram )
{
rendererElem.setAttribute( QStringLiteral( "diagramType" ), mDiagram->diagramName() );
}
rendererElem.setAttribute( QStringLiteral( "attributeLegend" ), mShowAttributeLegend );
rendererElem.setAttribute( QStringLiteral( "sizeLegend" ), mShowSizeLegend );
QDomElement sizeLegendSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "sizeSymbol" ), mSizeLegendSymbol.get(), doc, context );
rendererElem.appendChild( sizeLegendSymbolElem );
}

QgsSingleCategoryDiagramRenderer::QgsSingleCategoryDiagramRenderer(): QgsDiagramRenderer()
Expand Down Expand Up @@ -614,6 +601,7 @@ void QgsSingleCategoryDiagramRenderer::writeXml( QDomElement &layerElem, QDomDoc

QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer()
: QgsDiagramRenderer()
, mSizeLegendSymbol( QgsMarkerSymbol::createSimple( QgsStringMap() ) )
{
mInterpolationSettings.classificationAttributeIsExpression = false;
}
Expand All @@ -622,6 +610,7 @@ QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer(
: QgsDiagramRenderer( other )
, mSettings( other.mSettings )
, mInterpolationSettings( other.mInterpolationSettings )
, mSizeLegendSymbol( other.mSizeLegendSymbol ? other.mSizeLegendSymbol->clone() : nullptr )
, mDataDefinedSizeLegend( other.mDataDefinedSizeLegend ? new QgsDataDefinedSizeLegend( *other.mDataDefinedSizeLegend ) : nullptr )
{
}
Expand Down Expand Up @@ -696,11 +685,23 @@ void QgsLinearlyInterpolatedDiagramRenderer::readXml( const QDomElement &elem, c
mSettings.readXml( settingsElem );
}

QDomElement sizeLegendSymbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
if ( !sizeLegendSymbolElem.isNull() && sizeLegendSymbolElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "sizeSymbol" ) )
{
mSizeLegendSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( sizeLegendSymbolElem, context ) );
}

QDomElement ddsLegendSizeElem = elem.firstChildElement( "data-defined-size-legend" );
if ( !ddsLegendSizeElem.isNull() )
{
mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( ddsLegendSizeElem ) );
}
else
{
// pre-3.0 projects
bool enabled = elem.attribute( QStringLiteral( "sizeLegend" ), QStringLiteral( "0" ) ) != QLatin1String( "0" );
mDataDefinedSizeLegend.reset( enabled ? new QgsDataDefinedSizeLegend() : nullptr );
}

_readXml( elem, context );
}
Expand All @@ -724,6 +725,9 @@ void QgsLinearlyInterpolatedDiagramRenderer::writeXml( QDomElement &layerElem, Q
}
mSettings.writeXml( rendererElem, doc );

QDomElement sizeLegendSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "sizeSymbol" ), mSizeLegendSymbol.get(), doc, context );
rendererElem.appendChild( sizeLegendSymbolElem );

if ( mDataDefinedSizeLegend )
{
QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) );
Expand Down Expand Up @@ -768,7 +772,7 @@ QList< QgsLayerTreeModelLegendNode * > QgsLinearlyInterpolatedDiagramRenderer::l
if ( mShowAttributeLegend )
nodes = mSettings.legendItems( nodeLayer );

if ( mShowSizeLegend && mDiagram && mSizeLegendSymbol )
if ( mDataDefinedSizeLegend && mDiagram && mSizeLegendSymbol )
{
// add size legend

Expand All @@ -783,9 +787,7 @@ QList< QgsLayerTreeModelLegendNode * > QgsLinearlyInterpolatedDiagramRenderer::l
sizeClasses << QgsDataDefinedSizeLegend::SizeClass( size, QString::number( v ) );
}

QgsDataDefinedSizeLegend ddSizeLegend;
if ( mDataDefinedSizeLegend ) // copy legend configuration if any...
ddSizeLegend = *mDataDefinedSizeLegend;
QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend );
ddSizeLegend.setSymbol( legendSymbol ); // transfers ownership
ddSizeLegend.setClasses( sizeClasses );

Expand Down

0 comments on commit 517fefe

Please sign in to comment.