Navigation Menu

Skip to content

Commit

Permalink
Read/write also legend symbol in DDS legend, update DDS legend dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Jun 19, 2017
1 parent 517fefe commit e3270ed
Show file tree
Hide file tree
Showing 18 changed files with 218 additions and 207 deletions.
3 changes: 1 addition & 2 deletions doc/api_break.dox
Expand Up @@ -987,8 +987,7 @@ 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.
- sizeLegend(), setSizeLegend(), sizeLegendSymbol() and setSizeLegendSymbol() have been replaced by dataDefinedSizeLegend() and setDataDefinedSizeLegend() methods in QgsLinearlyInterpolatedDiagramRenderer.


QgsDiagramLayerSettings {#qgis_api_break_3_0_QgsDiagramLayerSettings}
Expand Down
12 changes: 4 additions & 8 deletions python/core/qgsdatadefinedsizelegend.sip
Expand Up @@ -152,19 +152,15 @@ Returns output image that would be shown in the legend. Returns invalid image if
:rtype: QImage
%End

static QgsDataDefinedSizeLegend *readTypeAndAlignmentFromXml( const QDomElement &elem ) /Factory/;
static QgsDataDefinedSizeLegend *readXml( const QDomElement &elem, const QgsReadWriteContext &context ) /Factory/;
%Docstring
.. note::

This is a temporary method and may be removed in the future
Creates instance from given element and returns it (caller takes ownership). Returns null on error.
:rtype: QgsDataDefinedSizeLegend
%End

static void writeTypeAndAlignmentToXml( const QgsDataDefinedSizeLegend &ddsLegend, QDomElement &elem );
void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const;
%Docstring
.. note::

This is a temporary method and may be removed in the future
Writes configuration to the given XML element.
%End

};
Expand Down
18 changes: 0 additions & 18 deletions python/core/qgsdiagramrenderer.sip
Expand Up @@ -720,24 +720,6 @@ 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
15 changes: 3 additions & 12 deletions python/gui/symbology-ng/qgsdatadefinedsizelegenddialog.sip
Expand Up @@ -10,6 +10,7 @@




class QgsDataDefinedSizeLegendDialog : QDialog
{
%Docstring
Expand All @@ -22,22 +23,12 @@ class QgsDataDefinedSizeLegendDialog : QDialog
#include "qgsdatadefinedsizelegenddialog.h"
%End
public:
explicit QgsDataDefinedSizeLegendDialog( const QgsDataDefinedSizeLegend *ddsLegend, QWidget *parent /TransferThis/ = 0 );
explicit QgsDataDefinedSizeLegendDialog( const QgsDataDefinedSizeLegend *ddsLegend, const QgsProperty &ddSize, QgsMarkerSymbol *overrideSymbol /Transfer/, QgsMapCanvas *canvas = 0, QWidget *parent /TransferThis/ = 0 );
%Docstring
Creates the dialog and initializes the content to what is passed in the legend configuration (may be null)
when the symbol is given from outside rather than being set inside QgsDataDefinedSizeLegend.
%End
~QgsDataDefinedSizeLegendDialog();

void setSourceSymbol( QgsMarkerSymbol *symbol /Transfer/ );
%Docstring
Use given symbol for preview. Takes ownership of the symbol. It should have data-defined size enabled + size scale transformer attached.
%End

void setLegendMapViewData( double mapUnitsPerPixel, int dpi, double scale );
%Docstring
Setup map view details to make preview match the expected output
%End

QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const /Factory/;
%Docstring
Returns configuration as set up in the dialog (may be null). Ownership is passed to the caller.
Expand Down
43 changes: 2 additions & 41 deletions src/app/qgsdiagramproperties.cpp
Expand Up @@ -190,8 +190,6 @@ 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 Down Expand Up @@ -360,7 +358,6 @@ 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 @@ -402,9 +399,6 @@ 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 Down Expand Up @@ -818,7 +812,6 @@ void QgsDiagramProperties::apply()
}
dr->setDiagramSettings( ds );

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

renderer = dr;
Expand Down Expand Up @@ -941,52 +934,20 @@ void QgsDiagramProperties::on_mPlacementComboBox_currentIndexChanged( int index
chkLineOrientationDependent->setEnabled( linePlacementEnabled );
}

void QgsDiagramProperties::on_mButtonSizeLegendSymbol_clicked()
{
QgsMarkerSymbol *newSymbol = mSizeLegendSymbol->clone();
QgsSymbolWidgetContext context;
context.setMapCanvas( mMapCanvas );
QgsExpressionContext ec = createExpressionContext();
context.setExpressionContext( &ec );

QgsSymbolSelectorDialog d( newSymbol, QgsStyle::defaultStyle(), mLayer, this );
d.setContext( context );

if ( d.exec() == QDialog::Accepted )
{
mSizeLegendSymbol.reset( newSymbol );
QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mSizeLegendSymbol.get(), mButtonSizeLegendSymbol->iconSize() );
mButtonSizeLegendSymbol->setIcon( icon );
}
else
{
delete newSymbol;
}
}

void QgsDiagramProperties::scalingTypeChanged()
{
mSizeLegendGroupBox->setEnabled( mAttributeBasedScalingRadio->isChecked() );
mButtonSizeLegendSettings->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 )
{
dlg.setLegendMapViewData( mMapCanvas->mapUnitsPerPixel(), mMapCanvas->mapSettings().outputDpi(), mMapCanvas->scale() );
}

QgsDataDefinedSizeLegendDialog dlg( mSizeLegend.get(), ddSize, nullptr, mMapCanvas );
if ( !dlg.exec() )
return;

Expand Down
2 changes: 0 additions & 2 deletions src/app/qgsdiagramproperties.h
Expand Up @@ -52,7 +52,6 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
void showAddAttributeExpressionDialog();
void on_mDiagramStackedWidget_currentChanged( int index );
void on_mPlacementComboBox_currentIndexChanged( int index );
void on_mButtonSizeLegendSymbol_clicked();
void scalingTypeChanged();
void showSizeLegendDialog();

Expand Down Expand Up @@ -81,7 +80,6 @@ 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 );
Expand Down
75 changes: 71 additions & 4 deletions src/core/qgsdatadefinedsizelegend.cpp
Expand Up @@ -290,18 +290,85 @@ QImage QgsDataDefinedSizeLegend::collapsedLegendImage( QgsRenderContext &context
return img;
}

QgsDataDefinedSizeLegend *QgsDataDefinedSizeLegend::readTypeAndAlignmentFromXml( const QDomElement &elem )
QgsDataDefinedSizeLegend *QgsDataDefinedSizeLegend::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
if ( elem.isNull() )
return nullptr;
QgsDataDefinedSizeLegend *ddsLegend = new QgsDataDefinedSizeLegend;
ddsLegend->setLegendType( elem.attribute( "type" ) == "collapsed" ? LegendCollapsed : LegendSeparated );
ddsLegend->setVerticalAlignment( elem.attribute( "valign" ) == "center" ? AlignCenter : AlignBottom );
ddsLegend->setTitle( elem.attribute( "title" ) );

QDomElement elemSymbol = elem.firstChildElement( "symbol" );
if ( !elemSymbol.isNull() )
{
ddsLegend->setSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( elemSymbol, context ) );
}

QDomElement elemTextStyle = elem.firstChildElement( "text-style" );
if ( !elemTextStyle.isNull() )
{
QDomElement elemFont = elemTextStyle.firstChildElement( "font" );
if ( !elemFont.isNull() )
{
ddsLegend->setFont( QFont( elemFont.attribute( "family" ), elemFont.attribute( "size" ).toInt(),
elemFont.attribute( "weight" ).toInt(), elemFont.attribute( "italic" ).toInt() ) );
}
ddsLegend->setTextColor( QgsSymbolLayerUtils::decodeColor( elemTextStyle.attribute( "color" ) ) );
ddsLegend->setTextAlignment( static_cast<Qt::AlignmentFlag>( elemTextStyle.attribute( "align" ).toInt() ) );
}

QDomElement elemClasses = elem.firstChildElement( "classes" );
if ( !elemClasses.isNull() )
{
QList<SizeClass> classes;
QDomElement elemClass = elemClasses.firstChildElement( "class" );
while ( !elemClass.isNull() )
{
classes << SizeClass( elemClass.attribute( "size" ).toDouble(), elemClass.attribute( "label" ) );
elemClass = elemClass.nextSiblingElement();
}
ddsLegend->setClasses( classes );
}

return ddsLegend;
}

void QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( const QgsDataDefinedSizeLegend &ddsLegend, QDomElement &elem )
void QgsDataDefinedSizeLegend::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
{
elem.setAttribute( "type", ddsLegend.legendType() == LegendCollapsed ? "collapsed" : "separated" );
elem.setAttribute( "valign", ddsLegend.verticalAlignment() == AlignCenter ? "center" : "bottom" );
QDomDocument doc = elem.ownerDocument();

elem.setAttribute( "type", mType == LegendCollapsed ? "collapsed" : "separated" );
elem.setAttribute( "valign", mVAlign == AlignCenter ? "center" : "bottom" );
elem.setAttribute( "title", mTitleLabel );

if ( mSymbol )
{
QgsSymbolLayerUtils::saveSymbol( "source", mSymbol.get(), doc, context );
}

QDomElement elemFont = doc.createElement( "font" );
elemFont.setAttribute( "family", mFont.family() );
elemFont.setAttribute( "size", mFont.pointSize() );
elemFont.setAttribute( "weight", mFont.weight() );
elemFont.setAttribute( "italic", mFont.italic() );

QDomElement elemTextStyle = doc.createElement( "text-style" );
elemTextStyle.setAttribute( "color", QgsSymbolLayerUtils::encodeColor( mTextColor ) );
elemTextStyle.setAttribute( "align", static_cast<int>( mTextAlignment ) );
elemTextStyle.appendChild( elemFont );
elem.appendChild( elemTextStyle );

if ( !mSizeClasses.isEmpty() )
{
QDomElement elemClasses = doc.createElement( "classes" );
Q_FOREACH ( const SizeClass &sc, mSizeClasses )
{
QDomElement elemClass = doc.createElement( "class" );
elemClass.setAttribute( "size", sc.size );
elemClass.setAttribute( "label", sc.label );
elemClasses.appendChild( elemClass );
}
elem.appendChild( elemClasses );
}
}
9 changes: 3 additions & 6 deletions src/core/qgsdatadefinedsizelegend.h
Expand Up @@ -24,6 +24,7 @@
class QDomElement;
class QgsMarkerSymbol;
class QgsProperty;
class QgsReadWriteContext;
class QgsRenderContext;


Expand Down Expand Up @@ -122,14 +123,10 @@ class CORE_EXPORT QgsDataDefinedSizeLegend
QImage collapsedLegendImage( QgsRenderContext &context, double paddingMM = 1 ) const;

//! Creates instance from given element and returns it (caller takes ownership). Returns null on error.
//! \note only reads legend type and vertical alignment of symbols
//! \note This is a temporary method and may be removed in the future
static QgsDataDefinedSizeLegend *readTypeAndAlignmentFromXml( const QDomElement &elem ) SIP_FACTORY;
static QgsDataDefinedSizeLegend *readXml( const QDomElement &elem, const QgsReadWriteContext &context ) SIP_FACTORY;

//! Writes configuration to the given XML element.
//! \note only writes legend type and vertical alignment of symbols
//! \note This is a temporary method and may be removed in the future
static void writeTypeAndAlignmentToXml( const QgsDataDefinedSizeLegend &ddsLegend, QDomElement &elem );
void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const;

private:
LegendType mType = LegendSeparated;
Expand Down
35 changes: 17 additions & 18 deletions src/core/qgsdiagramrenderer.cpp
Expand Up @@ -601,7 +601,6 @@ void QgsSingleCategoryDiagramRenderer::writeXml( QDomElement &layerElem, QDomDoc

QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer()
: QgsDiagramRenderer()
, mSizeLegendSymbol( QgsMarkerSymbol::createSimple( QgsStringMap() ) )
{
mInterpolationSettings.classificationAttributeIsExpression = false;
}
Expand All @@ -610,7 +609,6 @@ 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 @@ -685,22 +683,27 @@ 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 ) );
mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) );
}
else
{
// pre-3.0 projects
bool enabled = elem.attribute( QStringLiteral( "sizeLegend" ), QStringLiteral( "0" ) ) != QLatin1String( "0" );
mDataDefinedSizeLegend.reset( enabled ? new QgsDataDefinedSizeLegend() : nullptr );
if ( elem.attribute( QStringLiteral( "sizeLegend" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) )
{
mDataDefinedSizeLegend.reset( new QgsDataDefinedSizeLegend() );
QDomElement sizeLegendSymbolElem = elem.firstChildElement( QStringLiteral( "symbol" ) );
if ( !sizeLegendSymbolElem.isNull() && sizeLegendSymbolElem.attribute( QStringLiteral( "name" ) ) == QLatin1String( "sizeSymbol" ) )
{
mDataDefinedSizeLegend->setSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( sizeLegendSymbolElem, context ) );
}
}
else
{
mDataDefinedSizeLegend.reset( nullptr );
}
}

_readXml( elem, context );
Expand All @@ -725,13 +728,10 @@ 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" ) );
QgsDataDefinedSizeLegend::writeTypeAndAlignmentToXml( *mDataDefinedSizeLegend, ddsLegendElem );
mDataDefinedSizeLegend->writeXml( ddsLegendElem, context );
rendererElem.appendChild( ddsLegendElem );
}

Expand Down Expand Up @@ -772,11 +772,10 @@ QList< QgsLayerTreeModelLegendNode * > QgsLinearlyInterpolatedDiagramRenderer::l
if ( mShowAttributeLegend )
nodes = mSettings.legendItems( nodeLayer );

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

QgsMarkerSymbol *legendSymbol = mSizeLegendSymbol.get()->clone();
QgsMarkerSymbol *legendSymbol = mDataDefinedSizeLegend->symbol() ? mDataDefinedSizeLegend->symbol()->clone() : QgsMarkerSymbol::createSimple( QgsStringMap() );
legendSymbol->setSizeUnit( mSettings.sizeType );
legendSymbol->setSizeMapUnitScale( mSettings.sizeScale );

Expand Down

0 comments on commit e3270ed

Please sign in to comment.