Skip to content

Commit ec9ba9c

Browse files
committedJan 23, 2017
[FEATURE][composer] Data defined legend titles and column count
(fix #11913)
1 parent a67c84b commit ec9ba9c

File tree

9 files changed

+187
-56
lines changed

9 files changed

+187
-56
lines changed
 

‎python/core/composer/qgscomposerlegend.sip

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,13 @@ class QgsComposerLegend : QgsComposerItem
242242
//Overridden to show legend title
243243
virtual QString displayName() const;
244244

245+
const QgsLegendSettings& legendSettings() const;
246+
245247
public slots:
246248
/** Data changed*/
247249
void synchronizeWithModel();
248250
/** Sets mCompositionMap to 0 if the map is deleted*/
249251
void invalidateCurrentMap();
252+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = nullptr );
253+
250254
};

‎python/core/composer/qgscomposerobject.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class QgsComposerObject : QObject, QgsExpressionContextGenerator
5151
PictureSvgOutlineWidth, //!< SVG outline width
5252
//html item
5353
SourceUrl /*!< html source url */
54+
//legend item
55+
LegendTitle, //!< Legend title
56+
LegendColumnCount, //!< Legend column count
5457
};
5558

5659
/** Specifies whether the value returned by a function should be the original, user

‎src/app/composer/qgscomposerlegendwidget.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ QgsComposerLegendWidget::QgsComposerLegendWidget( QgsComposerLegend* legend )
100100
connect( &legend->composition()->atlasComposition(), SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( updateFilterLegendByAtlasButton() ) );
101101
}
102102

103+
registerDataDefinedButton( mLegendTitleDDBtn, QgsComposerObject::LegendTitle,
104+
QgsDataDefinedButtonV2::AnyType, QgsDataDefinedButtonV2::anyStringDesc() );
105+
registerDataDefinedButton( mColumnsDDBtn, QgsComposerObject::LegendColumnCount,
106+
QgsDataDefinedButtonV2::AnyType, QgsDataDefinedButtonV2::intPosOneDesc() );
107+
103108
setGuiElements();
104109

105110
connect( mItemTreeView->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ),
@@ -160,6 +165,8 @@ void QgsComposerLegendWidget::setGuiElements()
160165
blockAllSignals( false );
161166

162167
on_mCheckBoxAutoUpdate_stateChanged( mLegend->autoUpdateModel() ? Qt::Checked : Qt::Unchecked );
168+
updateDataDefinedButton( mLegendTitleDDBtn );
169+
updateDataDefinedButton( mColumnsDDBtn );
163170
}
164171

165172
void QgsComposerLegendWidget::on_mWrapCharLineEdit_textChanged( const QString &text )

‎src/core/composer/qgscomposerlegend.cpp

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ void QgsComposerLegend::setLegendFilterByMapEnabled( bool enabled )
265265

266266
void QgsComposerLegend::setTitle( const QString& t )
267267
{
268+
mTitle = t;
268269
mSettings.setTitle( t );
269270

270271
if ( mComposition && id().isEmpty() )
@@ -273,7 +274,7 @@ void QgsComposerLegend::setTitle( const QString& t )
273274
mComposition->itemsModel()->updateItemDisplayName( this );
274275
}
275276
}
276-
QString QgsComposerLegend::title() const { return mSettings.title(); }
277+
QString QgsComposerLegend::title() const { return mTitle; }
277278

278279
Qt::AlignmentFlag QgsComposerLegend::titleAlignment() const { return mSettings.titleAlignment(); }
279280
void QgsComposerLegend::setTitleAlignment( Qt::AlignmentFlag alignment ) { mSettings.setTitleAlignment( alignment ); }
@@ -315,8 +316,8 @@ void QgsComposerLegend::setWmsLegendHeight( double h ) { mSettings.setWmsLegendS
315316
void QgsComposerLegend::setWrapChar( const QString& t ) { mSettings.setWrapChar( t ); }
316317
QString QgsComposerLegend::wrapChar() const {return mSettings.wrapChar(); }
317318

318-
int QgsComposerLegend::columnCount() const { return mSettings.columnCount(); }
319-
void QgsComposerLegend::setColumnCount( int c ) { mSettings.setColumnCount( c ); }
319+
int QgsComposerLegend::columnCount() const { return mColumnCount; }
320+
void QgsComposerLegend::setColumnCount( int c ) { mColumnCount = c; mSettings.setColumnCount( c ); }
320321

321322
bool QgsComposerLegend::splitLayer() const { return mSettings.splitLayer(); }
322323
void QgsComposerLegend::setSplitLayer( bool s ) { mSettings.setSplitLayer( s ); }
@@ -362,9 +363,9 @@ bool QgsComposerLegend::writeXml( QDomElement& elem, QDomDocument & doc ) const
362363
elem.appendChild( composerLegendElem );
363364

364365
//write general properties
365-
composerLegendElem.setAttribute( QStringLiteral( "title" ), mSettings.title() );
366+
composerLegendElem.setAttribute( QStringLiteral( "title" ), mTitle );
366367
composerLegendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
367-
composerLegendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mSettings.columnCount() ) );
368+
composerLegendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mColumnCount ) );
368369
composerLegendElem.setAttribute( QStringLiteral( "splitLayer" ), QString::number( mSettings.splitLayer() ) );
369370
composerLegendElem.setAttribute( QStringLiteral( "equalColumnWidth" ), QString::number( mSettings.equalColumnWidth() ) );
370371

@@ -462,14 +463,16 @@ bool QgsComposerLegend::readXml( const QDomElement& itemElem, const QDomDocument
462463
}
463464

464465
//read general properties
465-
mSettings.setTitle( itemElem.attribute( QStringLiteral( "title" ) ) );
466+
mTitle = itemElem.attribute( QStringLiteral( "title" ) );
467+
mSettings.setTitle( mTitle );
466468
if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
467469
{
468470
mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
469471
}
470472
int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
471473
if ( colCount < 1 ) colCount = 1;
472-
mSettings.setColumnCount( colCount );
474+
mColumnCount = colCount;
475+
mSettings.setColumnCount( mColumnCount );
473476
mSettings.setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
474477
mSettings.setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
475478

@@ -642,6 +645,42 @@ void QgsComposerLegend::invalidateCurrentMap()
642645
setComposerMap( nullptr );
643646
}
644647

648+
void QgsComposerLegend::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, const QgsExpressionContext* context )
649+
{
650+
QgsExpressionContext scopedContext = createExpressionContext();
651+
const QgsExpressionContext* evalContext = context ? context : &scopedContext;
652+
653+
bool forceUpdate = false;
654+
//updates data defined properties and redraws item to match
655+
if ( property == QgsComposerObject::LegendTitle || property == QgsComposerObject::AllProperties )
656+
{
657+
bool ok = false;
658+
QString t = mProperties.valueAsString( QgsComposerObject::LegendTitle, *evalContext, mTitle, &ok );
659+
if ( ok )
660+
{
661+
mSettings.setTitle( t );
662+
forceUpdate = true;
663+
}
664+
}
665+
if ( property == QgsComposerObject::LegendColumnCount || property == QgsComposerObject::AllProperties )
666+
{
667+
bool ok = false;
668+
int cols = mProperties.valueAsInt( QgsComposerObject::LegendColumnCount, *evalContext, mColumnCount, &ok );
669+
if ( ok && cols >= 0 )
670+
{
671+
mSettings.setColumnCount( cols );
672+
forceUpdate = true;
673+
}
674+
}
675+
if ( forceUpdate )
676+
{
677+
adjustBoxSize();
678+
update();
679+
}
680+
681+
QgsComposerObject::refreshDataDefinedProperty( property, context );
682+
}
683+
645684
void QgsComposerLegend::mapLayerStyleOverridesChanged()
646685
{
647686
if ( !mComposerMap )

‎src/core/composer/qgscomposerlegend.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,21 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
272272
//Overridden to show legend title
273273
virtual QString displayName() const override;
274274

275+
/**
276+
* Returns the legend's renderer settings object.
277+
* @note added in QGIS 3.0
278+
*/
279+
const QgsLegendSettings& legendSettings() const { return mSettings; }
280+
275281
public slots:
276282
//! Data changed
277283
void synchronizeWithModel();
278284
//! Sets mCompositionMap to 0 if the map is deleted
279285
void invalidateCurrentMap();
280286

287+
virtual void refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property = QgsComposerObject::AllProperties, const QgsExpressionContext* context = nullptr ) override;
288+
289+
281290
private slots:
282291
void updateFilterByMap( bool redraw = true );
283292

@@ -301,6 +310,9 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem
301310

302311
QgsLegendSettings mSettings;
303312

313+
QString mTitle;
314+
int mColumnCount = 1;
315+
304316
const QgsComposerMap* mComposerMap;
305317

306318
bool mLegendFilterByMap;

‎src/core/composer/qgscomposerobject.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ const QgsPropertyDefinition QgsComposerObject::sPropertyNameMap
6161
{ QgsComposerObject::PictureSvgBackgroundColor, "dataDefinedSvgBackgroundColor" },
6262
{ QgsComposerObject::PictureSvgOutlineColor, "dataDefinedSvgOutlineColor" },
6363
{ QgsComposerObject::PictureSvgOutlineWidth, "dataDefinedSvgOutlineWidth" },
64+
{ QgsComposerObject::LegendTitle, "dataDefinedLegendTitle" },
65+
{ QgsComposerObject::LegendColumnCount, "dataDefinedLegendColumns" },
6466
};
6567

6668

‎src/core/composer/qgscomposerobject.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class CORE_EXPORT QgsComposerObject: public QObject, public QgsExpressionContext
7878
PictureSvgOutlineWidth, //!< SVG outline width
7979
//html item
8080
SourceUrl, //!< Html source url
81+
//legend item
82+
LegendTitle, //!< Legend title
83+
LegendColumnCount, //!< Legend column count
8184
};
8285

8386
static const QgsPropertyDefinition sPropertyNameMap;

‎src/ui/composer/qgscomposerlegendwidgetbase.ui

Lines changed: 71 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,7 @@
8383
<property name="collapsed" stdset="0">
8484
<bool>false</bool>
8585
</property>
86-
<layout class="QFormLayout" name="formLayout">
87-
<property name="fieldGrowthPolicy">
88-
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
89-
</property>
90-
<property name="labelAlignment">
91-
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
92-
</property>
86+
<layout class="QGridLayout" name="gridLayout_2">
9387
<item row="0" column="0">
9488
<widget class="QLabel" name="mTitleLabel">
9589
<property name="text">
@@ -100,8 +94,12 @@
10094
</property>
10195
</widget>
10296
</item>
103-
<item row="0" column="1">
104-
<widget class="QLineEdit" name="mTitleLineEdit"/>
97+
<item row="1" column="0">
98+
<widget class="QLabel" name="label_15">
99+
<property name="text">
100+
<string>Title alignment</string>
101+
</property>
102+
</widget>
105103
</item>
106104
<item row="2" column="0">
107105
<widget class="QLabel" name="mMapLabel">
@@ -110,8 +108,12 @@
110108
</property>
111109
</widget>
112110
</item>
113-
<item row="2" column="1">
114-
<widget class="QgsComposerItemComboBox" name="mMapComboBox"/>
111+
<item row="5" column="0" colspan="2">
112+
<widget class="QCheckBox" name="mCheckboxResizeContents">
113+
<property name="text">
114+
<string>Resize to fit contents</string>
115+
</property>
116+
</widget>
115117
</item>
116118
<item row="3" column="0">
117119
<widget class="QLabel" name="label">
@@ -120,21 +122,17 @@
120122
</property>
121123
</widget>
122124
</item>
123-
<item row="3" column="1">
124-
<widget class="QLineEdit" name="mWrapCharLineEdit">
125-
<property name="frame">
126-
<bool>true</bool>
127-
</property>
128-
</widget>
125+
<item row="0" column="1">
126+
<widget class="QLineEdit" name="mTitleLineEdit"/>
129127
</item>
130-
<item row="1" column="0">
131-
<widget class="QLabel" name="label_15">
128+
<item row="0" column="2">
129+
<widget class="QgsDataDefinedButtonV2" name="mLegendTitleDDBtn">
132130
<property name="text">
133-
<string>Title alignment</string>
131+
<string>...</string>
134132
</property>
135133
</widget>
136134
</item>
137-
<item row="1" column="1">
135+
<item row="1" column="1" colspan="2">
138136
<widget class="QComboBox" name="mTitleAlignCombo">
139137
<item>
140138
<property name="text">
@@ -153,10 +151,13 @@
153151
</item>
154152
</widget>
155153
</item>
156-
<item row="4" column="0" colspan="2">
157-
<widget class="QCheckBox" name="mCheckboxResizeContents">
158-
<property name="text">
159-
<string>Resize to fit contents</string>
154+
<item row="2" column="1" colspan="2">
155+
<widget class="QgsComposerItemComboBox" name="mMapComboBox"/>
156+
</item>
157+
<item row="3" column="1" colspan="2">
158+
<widget class="QLineEdit" name="mWrapCharLineEdit">
159+
<property name="frame">
160+
<bool>true</bool>
160161
</property>
161162
</widget>
162163
</item>
@@ -550,21 +551,8 @@
550551
<property name="collapsed" stdset="0">
551552
<bool>true</bool>
552553
</property>
553-
<layout class="QFormLayout" name="formLayout_2">
554-
<property name="fieldGrowthPolicy">
555-
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
556-
</property>
557-
<property name="labelAlignment">
558-
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
559-
</property>
560-
<item row="1" column="0">
561-
<widget class="QLabel" name="label_2">
562-
<property name="text">
563-
<string>Count</string>
564-
</property>
565-
</widget>
566-
</item>
567-
<item row="1" column="1">
554+
<layout class="QGridLayout" name="gridLayout_3">
555+
<item row="0" column="1">
568556
<widget class="QgsSpinBox" name="mColumnCountSpinBox">
569557
<property name="prefix">
570558
<string/>
@@ -577,14 +565,41 @@
577565
</property>
578566
</widget>
579567
</item>
580-
<item row="3" column="0" colspan="2">
568+
<item row="0" column="0">
569+
<widget class="QLabel" name="label_2">
570+
<property name="text">
571+
<string>Count</string>
572+
</property>
573+
</widget>
574+
</item>
575+
<item row="0" column="2">
576+
<widget class="QgsDataDefinedButtonV2" name="mColumnsDDBtn">
577+
<property name="text">
578+
<string>...</string>
579+
</property>
580+
</widget>
581+
</item>
582+
<item row="0" column="3">
583+
<spacer name="horizontalSpacer_5">
584+
<property name="orientation">
585+
<enum>Qt::Horizontal</enum>
586+
</property>
587+
<property name="sizeHint" stdset="0">
588+
<size>
589+
<width>40</width>
590+
<height>20</height>
591+
</size>
592+
</property>
593+
</spacer>
594+
</item>
595+
<item row="2" column="0" colspan="4">
581596
<widget class="QCheckBox" name="mEqualColumnWidthCheckBox">
582597
<property name="text">
583598
<string>Equal column widths</string>
584599
</property>
585600
</widget>
586601
</item>
587-
<item row="4" column="0" colspan="2">
602+
<item row="3" column="0" colspan="4">
588603
<widget class="QCheckBox" name="mSplitLayerCheckBox">
589604
<property name="toolTip">
590605
<string>Allow splitting layer items into multiple columns.</string>
@@ -1013,18 +1028,17 @@
10131028
</widget>
10141029
<layoutdefault spacing="6" margin="11"/>
10151030
<customwidgets>
1016-
<customwidget>
1017-
<class>QgsCollapsibleGroupBoxBasic</class>
1018-
<extends>QGroupBox</extends>
1019-
<header>qgscollapsiblegroupbox.h</header>
1020-
<container>1</container>
1021-
</customwidget>
10221031
<customwidget>
10231032
<class>QgsColorButton</class>
10241033
<extends>QToolButton</extends>
10251034
<header>qgscolorbutton.h</header>
10261035
<container>1</container>
10271036
</customwidget>
1037+
<customwidget>
1038+
<class>QgsDataDefinedButtonV2</class>
1039+
<extends>QToolButton</extends>
1040+
<header>qgsdatadefinedbuttonv2.h</header>
1041+
</customwidget>
10281042
<customwidget>
10291043
<class>QgsDoubleSpinBox</class>
10301044
<extends>QDoubleSpinBox</extends>
@@ -1035,6 +1049,12 @@
10351049
<extends>QSpinBox</extends>
10361050
<header>qgsspinbox.h</header>
10371051
</customwidget>
1052+
<customwidget>
1053+
<class>QgsCollapsibleGroupBoxBasic</class>
1054+
<extends>QGroupBox</extends>
1055+
<header location="global">qgscollapsiblegroupbox.h</header>
1056+
<container>1</container>
1057+
</customwidget>
10381058
<customwidget>
10391059
<class>QgsComposerItemComboBox</class>
10401060
<extends>QComboBox</extends>
@@ -1055,6 +1075,7 @@
10551075
<tabstop>scrollArea</tabstop>
10561076
<tabstop>mMainPropertiesColGroupBox</tabstop>
10571077
<tabstop>mTitleLineEdit</tabstop>
1078+
<tabstop>mLegendTitleDDBtn</tabstop>
10581079
<tabstop>mTitleAlignCombo</tabstop>
10591080
<tabstop>mMapComboBox</tabstop>
10601081
<tabstop>mWrapCharLineEdit</tabstop>
@@ -1080,6 +1101,7 @@
10801101
<tabstop>mItemFontButton</tabstop>
10811102
<tabstop>mFontColorButton</tabstop>
10821103
<tabstop>mColumnsColGroupBox</tabstop>
1104+
<tabstop>mColumnsDDBtn</tabstop>
10831105
<tabstop>mColumnCountSpinBox</tabstop>
10841106
<tabstop>mEqualColumnWidthCheckBox</tabstop>
10851107
<tabstop>mSplitLayerCheckBox</tabstop>
@@ -1100,6 +1122,7 @@
11001122
<tabstop>mIconLabelSpaceSpinBox</tabstop>
11011123
<tabstop>mBoxSpaceSpinBox</tabstop>
11021124
<tabstop>mColumnSpaceSpinBox</tabstop>
1125+
<tabstop>mLineSpacingSpinBox</tabstop>
11031126
</tabstops>
11041127
<resources>
11051128
<include location="../../../images/images.qrc"/>

‎tests/src/python/test_qgscomposerlegend.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
QgsMarkerSymbol,
2525
QgsSingleSymbolRenderer,
2626
QgsRectangle,
27-
QgsProject
27+
QgsProject,
28+
QgsComposerObject,
29+
QgsExpressionBasedProperty
2830
)
2931
from qgis.testing import (start_app,
3032
unittest
@@ -200,5 +202,41 @@ def testResizeDisabledCrop(self):
200202

201203
QgsProject.instance().removeMapLayers([point_layer.id()])
202204

205+
def testDataDefinedTitle(self):
206+
mapSettings = QgsMapSettings()
207+
208+
composition = QgsComposition(mapSettings, QgsProject.instance())
209+
composition.setPaperSize(297, 210)
210+
211+
legend = QgsComposerLegend(composition)
212+
composition.addComposerLegend(legend)
213+
214+
legend.setTitle('original')
215+
self.assertEqual(legend.title(), 'original')
216+
self.assertEqual(legend.legendSettings().title(), 'original')
217+
218+
legend.dataDefinedProperties().setProperty(QgsComposerObject.LegendTitle, QgsExpressionBasedProperty("'new'"))
219+
legend.refreshDataDefinedProperty()
220+
self.assertEqual(legend.title(), 'original')
221+
self.assertEqual(legend.legendSettings().title(), 'new')
222+
223+
def testDataDefinedColumnCount(self):
224+
mapSettings = QgsMapSettings()
225+
226+
composition = QgsComposition(mapSettings, QgsProject.instance())
227+
composition.setPaperSize(297, 210)
228+
229+
legend = QgsComposerLegend(composition)
230+
composition.addComposerLegend(legend)
231+
232+
legend.setColumnCount(2)
233+
self.assertEqual(legend.columnCount(), 2)
234+
self.assertEqual(legend.legendSettings().columnCount(), 2)
235+
236+
legend.dataDefinedProperties().setProperty(QgsComposerObject.LegendColumnCount, QgsExpressionBasedProperty("5"))
237+
legend.refreshDataDefinedProperty()
238+
self.assertEqual(legend.columnCount(), 2)
239+
self.assertEqual(legend.legendSettings().columnCount(), 5)
240+
203241
if __name__ == '__main__':
204242
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.