[FEATURE][composer] Data defined legend titles and column count

(fix #11913)
This commit is contained in:
Nyall Dawson 2017-01-17 14:32:30 +10:00
parent a67c84b9a9
commit ec9ba9c2a2
9 changed files with 187 additions and 56 deletions

View File

@ -242,9 +242,13 @@ class QgsComposerLegend : QgsComposerItem
//Overridden to show legend title
virtual QString displayName() const;
const QgsLegendSettings& legendSettings() const;
public slots:
/** Data changed*/
void synchronizeWithModel();
/** Sets mCompositionMap to 0 if the map is deleted*/
void invalidateCurrentMap();
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = nullptr );
};

View File

@ -51,6 +51,9 @@ class QgsComposerObject : QObject, QgsExpressionContextGenerator
PictureSvgOutlineWidth, //!< SVG outline width
//html item
SourceUrl /*!< html source url */
//legend item
LegendTitle, //!< Legend title
LegendColumnCount, //!< Legend column count
};
/** Specifies whether the value returned by a function should be the original, user

View File

@ -100,6 +100,11 @@ QgsComposerLegendWidget::QgsComposerLegendWidget( QgsComposerLegend* legend )
connect( &legend->composition()->atlasComposition(), SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( updateFilterLegendByAtlasButton() ) );
}
registerDataDefinedButton( mLegendTitleDDBtn, QgsComposerObject::LegendTitle,
QgsDataDefinedButtonV2::AnyType, QgsDataDefinedButtonV2::anyStringDesc() );
registerDataDefinedButton( mColumnsDDBtn, QgsComposerObject::LegendColumnCount,
QgsDataDefinedButtonV2::AnyType, QgsDataDefinedButtonV2::intPosOneDesc() );
setGuiElements();
connect( mItemTreeView->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ),
@ -160,6 +165,8 @@ void QgsComposerLegendWidget::setGuiElements()
blockAllSignals( false );
on_mCheckBoxAutoUpdate_stateChanged( mLegend->autoUpdateModel() ? Qt::Checked : Qt::Unchecked );
updateDataDefinedButton( mLegendTitleDDBtn );
updateDataDefinedButton( mColumnsDDBtn );
}
void QgsComposerLegendWidget::on_mWrapCharLineEdit_textChanged( const QString &text )

View File

@ -265,6 +265,7 @@ void QgsComposerLegend::setLegendFilterByMapEnabled( bool enabled )
void QgsComposerLegend::setTitle( const QString& t )
{
mTitle = t;
mSettings.setTitle( t );
if ( mComposition && id().isEmpty() )
@ -273,7 +274,7 @@ void QgsComposerLegend::setTitle( const QString& t )
mComposition->itemsModel()->updateItemDisplayName( this );
}
}
QString QgsComposerLegend::title() const { return mSettings.title(); }
QString QgsComposerLegend::title() const { return mTitle; }
Qt::AlignmentFlag QgsComposerLegend::titleAlignment() const { return mSettings.titleAlignment(); }
void QgsComposerLegend::setTitleAlignment( Qt::AlignmentFlag alignment ) { mSettings.setTitleAlignment( alignment ); }
@ -315,8 +316,8 @@ void QgsComposerLegend::setWmsLegendHeight( double h ) { mSettings.setWmsLegendS
void QgsComposerLegend::setWrapChar( const QString& t ) { mSettings.setWrapChar( t ); }
QString QgsComposerLegend::wrapChar() const {return mSettings.wrapChar(); }
int QgsComposerLegend::columnCount() const { return mSettings.columnCount(); }
void QgsComposerLegend::setColumnCount( int c ) { mSettings.setColumnCount( c ); }
int QgsComposerLegend::columnCount() const { return mColumnCount; }
void QgsComposerLegend::setColumnCount( int c ) { mColumnCount = c; mSettings.setColumnCount( c ); }
bool QgsComposerLegend::splitLayer() const { return mSettings.splitLayer(); }
void QgsComposerLegend::setSplitLayer( bool s ) { mSettings.setSplitLayer( s ); }
@ -362,9 +363,9 @@ bool QgsComposerLegend::writeXml( QDomElement& elem, QDomDocument & doc ) const
elem.appendChild( composerLegendElem );
//write general properties
composerLegendElem.setAttribute( QStringLiteral( "title" ), mSettings.title() );
composerLegendElem.setAttribute( QStringLiteral( "title" ), mTitle );
composerLegendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
composerLegendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mSettings.columnCount() ) );
composerLegendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mColumnCount ) );
composerLegendElem.setAttribute( QStringLiteral( "splitLayer" ), QString::number( mSettings.splitLayer() ) );
composerLegendElem.setAttribute( QStringLiteral( "equalColumnWidth" ), QString::number( mSettings.equalColumnWidth() ) );
@ -462,14 +463,16 @@ bool QgsComposerLegend::readXml( const QDomElement& itemElem, const QDomDocument
}
//read general properties
mSettings.setTitle( itemElem.attribute( QStringLiteral( "title" ) ) );
mTitle = itemElem.attribute( QStringLiteral( "title" ) );
mSettings.setTitle( mTitle );
if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
{
mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
}
int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
if ( colCount < 1 ) colCount = 1;
mSettings.setColumnCount( colCount );
mColumnCount = colCount;
mSettings.setColumnCount( mColumnCount );
mSettings.setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
mSettings.setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
@ -642,6 +645,42 @@ void QgsComposerLegend::invalidateCurrentMap()
setComposerMap( nullptr );
}
void QgsComposerLegend::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, const QgsExpressionContext* context )
{
QgsExpressionContext scopedContext = createExpressionContext();
const QgsExpressionContext* evalContext = context ? context : &scopedContext;
bool forceUpdate = false;
//updates data defined properties and redraws item to match
if ( property == QgsComposerObject::LegendTitle || property == QgsComposerObject::AllProperties )
{
bool ok = false;
QString t = mProperties.valueAsString( QgsComposerObject::LegendTitle, *evalContext, mTitle, &ok );
if ( ok )
{
mSettings.setTitle( t );
forceUpdate = true;
}
}
if ( property == QgsComposerObject::LegendColumnCount || property == QgsComposerObject::AllProperties )
{
bool ok = false;
int cols = mProperties.valueAsInt( QgsComposerObject::LegendColumnCount, *evalContext, mColumnCount, &ok );
if ( ok && cols >= 0 )
{
mSettings.setColumnCount( cols );
forceUpdate = true;
}
}
if ( forceUpdate )
{
adjustBoxSize();
update();
}
QgsComposerObject::refreshDataDefinedProperty( property, context );
}
void QgsComposerLegend::mapLayerStyleOverridesChanged()
{
if ( !mComposerMap )

View File

@ -272,12 +272,21 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
//Overridden to show legend title
virtual QString displayName() const override;
/**
* Returns the legend's renderer settings object.
* @note added in QGIS 3.0
*/
const QgsLegendSettings& legendSettings() const { return mSettings; }
public slots:
//! Data changed
void synchronizeWithModel();
//! Sets mCompositionMap to 0 if the map is deleted
void invalidateCurrentMap();
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = nullptr ) override;
private slots:
void updateFilterByMap( bool redraw = true );
@ -301,6 +310,9 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
QgsLegendSettings mSettings;
QString mTitle;
int mColumnCount = 1;
const QgsComposerMap* mComposerMap;
bool mLegendFilterByMap;

View File

@ -61,6 +61,8 @@ const QgsPropertyDefinition QgsComposerObject::sPropertyNameMap
{ QgsComposerObject::PictureSvgBackgroundColor, "dataDefinedSvgBackgroundColor" },
{ QgsComposerObject::PictureSvgOutlineColor, "dataDefinedSvgOutlineColor" },
{ QgsComposerObject::PictureSvgOutlineWidth, "dataDefinedSvgOutlineWidth" },
{ QgsComposerObject::LegendTitle, "dataDefinedLegendTitle" },
{ QgsComposerObject::LegendColumnCount, "dataDefinedLegendColumns" },
};

View File

@ -78,6 +78,9 @@ class CORE_EXPORT QgsComposerObject: public QObject, public QgsExpressionContext
PictureSvgOutlineWidth, //!< SVG outline width
//html item
SourceUrl, //!< Html source url
//legend item
LegendTitle, //!< Legend title
LegendColumnCount, //!< Legend column count
};
static const QgsPropertyDefinition sPropertyNameMap;

View File

@ -83,13 +83,7 @@
<property name="collapsed" stdset="0">
<bool>false</bool>
</property>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="mTitleLabel">
<property name="text">
@ -100,8 +94,12 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="mTitleLineEdit"/>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Title alignment</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mMapLabel">
@ -110,8 +108,12 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QgsComposerItemComboBox" name="mMapComboBox"/>
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mCheckboxResizeContents">
<property name="text">
<string>Resize to fit contents</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
@ -120,21 +122,17 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="mWrapCharLineEdit">
<property name="frame">
<bool>true</bool>
</property>
</widget>
<item row="0" column="1">
<widget class="QLineEdit" name="mTitleLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<item row="0" column="2">
<widget class="QgsDataDefinedButtonV2" name="mLegendTitleDDBtn">
<property name="text">
<string>Title alignment</string>
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="mTitleAlignCombo">
<item>
<property name="text">
@ -153,10 +151,13 @@
</item>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="mCheckboxResizeContents">
<property name="text">
<string>Resize to fit contents</string>
<item row="2" column="1" colspan="2">
<widget class="QgsComposerItemComboBox" name="mMapComboBox"/>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLineEdit" name="mWrapCharLineEdit">
<property name="frame">
<bool>true</bool>
</property>
</widget>
</item>
@ -550,21 +551,8 @@
<property name="collapsed" stdset="0">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Count</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="1">
<widget class="QgsSpinBox" name="mColumnCountSpinBox">
<property name="prefix">
<string/>
@ -577,14 +565,41 @@
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Count</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QgsDataDefinedButtonV2" name="mColumnsDDBtn">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="mEqualColumnWidthCheckBox">
<property name="text">
<string>Equal column widths</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="3" column="0" colspan="4">
<widget class="QCheckBox" name="mSplitLayerCheckBox">
<property name="toolTip">
<string>Allow splitting layer items into multiple columns.</string>
@ -1013,18 +1028,17 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsCollapsibleGroupBoxBasic</class>
<extends>QGroupBox</extends>
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsColorButton</class>
<extends>QToolButton</extends>
<header>qgscolorbutton.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsDataDefinedButtonV2</class>
<extends>QToolButton</extends>
<header>qgsdatadefinedbuttonv2.h</header>
</customwidget>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
@ -1035,6 +1049,12 @@
<extends>QSpinBox</extends>
<header>qgsspinbox.h</header>
</customwidget>
<customwidget>
<class>QgsCollapsibleGroupBoxBasic</class>
<extends>QGroupBox</extends>
<header location="global">qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsComposerItemComboBox</class>
<extends>QComboBox</extends>
@ -1055,6 +1075,7 @@
<tabstop>scrollArea</tabstop>
<tabstop>mMainPropertiesColGroupBox</tabstop>
<tabstop>mTitleLineEdit</tabstop>
<tabstop>mLegendTitleDDBtn</tabstop>
<tabstop>mTitleAlignCombo</tabstop>
<tabstop>mMapComboBox</tabstop>
<tabstop>mWrapCharLineEdit</tabstop>
@ -1080,6 +1101,7 @@
<tabstop>mItemFontButton</tabstop>
<tabstop>mFontColorButton</tabstop>
<tabstop>mColumnsColGroupBox</tabstop>
<tabstop>mColumnsDDBtn</tabstop>
<tabstop>mColumnCountSpinBox</tabstop>
<tabstop>mEqualColumnWidthCheckBox</tabstop>
<tabstop>mSplitLayerCheckBox</tabstop>
@ -1100,6 +1122,7 @@
<tabstop>mIconLabelSpaceSpinBox</tabstop>
<tabstop>mBoxSpaceSpinBox</tabstop>
<tabstop>mColumnSpaceSpinBox</tabstop>
<tabstop>mLineSpacingSpinBox</tabstop>
</tabstops>
<resources>
<include location="../../../images/images.qrc"/>

View File

@ -24,7 +24,9 @@ from qgis.core import (QgsComposerLegend,
QgsMarkerSymbol,
QgsSingleSymbolRenderer,
QgsRectangle,
QgsProject
QgsProject,
QgsComposerObject,
QgsExpressionBasedProperty
)
from qgis.testing import (start_app,
unittest
@ -200,5 +202,41 @@ class TestQgsComposerLegend(unittest.TestCase):
QgsProject.instance().removeMapLayers([point_layer.id()])
def testDataDefinedTitle(self):
mapSettings = QgsMapSettings()
composition = QgsComposition(mapSettings, QgsProject.instance())
composition.setPaperSize(297, 210)
legend = QgsComposerLegend(composition)
composition.addComposerLegend(legend)
legend.setTitle('original')
self.assertEqual(legend.title(), 'original')
self.assertEqual(legend.legendSettings().title(), 'original')
legend.dataDefinedProperties().setProperty(QgsComposerObject.LegendTitle, QgsExpressionBasedProperty("'new'"))
legend.refreshDataDefinedProperty()
self.assertEqual(legend.title(), 'original')
self.assertEqual(legend.legendSettings().title(), 'new')
def testDataDefinedColumnCount(self):
mapSettings = QgsMapSettings()
composition = QgsComposition(mapSettings, QgsProject.instance())
composition.setPaperSize(297, 210)
legend = QgsComposerLegend(composition)
composition.addComposerLegend(legend)
legend.setColumnCount(2)
self.assertEqual(legend.columnCount(), 2)
self.assertEqual(legend.legendSettings().columnCount(), 2)
legend.dataDefinedProperties().setProperty(QgsComposerObject.LegendColumnCount, QgsExpressionBasedProperty("5"))
legend.refreshDataDefinedProperty()
self.assertEqual(legend.columnCount(), 2)
self.assertEqual(legend.legendSettings().columnCount(), 5)
if __name__ == '__main__':
unittest.main()