Skip to content

Commit afc90ab

Browse files
committed
[FEATURE] Add multi line support for legend title, groups, and items. Semi fix for #3484
1 parent 1d09182 commit afc90ab

File tree

5 files changed

+124
-39
lines changed

5 files changed

+124
-39
lines changed

src/app/composer/qgscomposerlegendwidget.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ QgsComposerLegendWidget::QgsComposerLegendWidget( QgsComposerLegend* legend ): m
5555
mItemTreeView->setAcceptDrops( true );
5656
mItemTreeView->setDropIndicatorShown( true );
5757
mItemTreeView->setDragDropMode( QAbstractItemView::InternalMove );
58+
mWrapCharLineEdit->setText( legend->wrapChar() );
5859

5960
setGuiElements();
6061
connect( mItemTreeView, SIGNAL( itemChanged() ), this, SLOT( setGuiElements() ) );
@@ -105,6 +106,18 @@ void QgsComposerLegendWidget::setGuiElements()
105106
blockAllSignals( false );
106107
}
107108

109+
void QgsComposerLegendWidget::on_mWrapCharLineEdit_textChanged( const QString &text )
110+
{
111+
if ( mLegend )
112+
{
113+
mLegend->beginCommand( tr( "Item wrapping changed" ), QgsComposerMergeCommand::ComposerLegendText );
114+
mLegend->setWrapChar( text );
115+
mLegend->adjustBoxSize();
116+
mLegend->update();
117+
mLegend->endCommand();
118+
}
119+
}
120+
108121
void QgsComposerLegendWidget::on_mTitleLineEdit_textChanged( const QString& text )
109122
{
110123
if ( mLegend )

src/app/composer/qgscomposerlegendwidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class QgsComposerLegendWidget: public QWidget, private Ui::QgsComposerLegendWidg
3939

4040
public slots:
4141

42+
void on_mWrapCharLineEdit_textChanged( const QString& text );
4243
void on_mTitleLineEdit_textChanged( const QString& text );
4344
void on_mSymbolWidthSpinBox_valueChanged( double d );
4445
void on_mSymbolHeightSpinBox_valueChanged( double d );

src/core/composer/qgscomposerlegend.cpp

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ QgsComposerLegend::QgsComposerLegend( QgsComposition* composition )
3535
, mGroupSpace( 2 )
3636
, mLayerSpace( 2 )
3737
, mSymbolSpace( 2 )
38-
, mIconLabelSpace( 2 ), mComposerMap( 0 )
38+
, mIconLabelSpace( 2 )
39+
, mComposerMap( 0 )
40+
3941
{
4042
//QStringList idList = layerIdList();
4143
//mLegendModel.setLayerSet( idList );
@@ -47,6 +49,8 @@ QgsComposerLegend::QgsComposerLegend( QgsComposition* composition )
4749

4850
mSymbolWidth = 7;
4951
mSymbolHeight = 4;
52+
mWrapChar = "";
53+
mlineSpacing = 1.5;
5054
adjustBoxSize();
5155

5256
connect( &mLegendModel, SIGNAL( layersChanged() ), this, SLOT( synchronizeWithModel() ) );
@@ -98,17 +102,22 @@ QSizeF QgsComposerLegend::paintAndDetermineSize( QPainter* painter )
98102
//font metrics
99103

100104
//draw title
101-
currentYCoordinate += fontAscentMillimeters( mTitleFont );
105+
double currentItemMaxX = 0; //maximum x-coordinate for current item
102106
if ( painter )
103107
{
104108
painter->setPen( QColor( 0, 0, 0 ) );
105-
drawText( painter, mBoxSpace, currentYCoordinate, mTitle, mTitleFont );
109+
QStringList lines = splitStringForWrapping( mTitle );
110+
for ( QStringList::Iterator titlePart = lines.begin(); titlePart != lines.end(); ++titlePart )
111+
{
112+
currentYCoordinate += fontAscentMillimeters( mTitleFont );
113+
drawText( painter, mBoxSpace, currentYCoordinate, *titlePart, mTitleFont );
114+
currentItemMaxX = 2 * mBoxSpace + textWidthMillimeters( mTitleFont, *titlePart );
115+
maxXCoord = qMax( maxXCoord, currentItemMaxX );
116+
if ( titlePart != lines.end() )
117+
currentYCoordinate += mlineSpacing;
118+
}
106119
}
107120

108-
109-
maxXCoord = 2 * mBoxSpace + textWidthMillimeters( mTitleFont, mTitle );
110-
111-
double currentItemMaxX = 0; //maximum x-coordinate for current item
112121
for ( int i = 0; i < numLayerItems; ++i )
113122
{
114123
currentLayerItem = rootItem->child( i );
@@ -167,14 +176,20 @@ void QgsComposerLegend::drawGroupItem( QPainter* p, QgsComposerGroupItem* groupI
167176
}
168177

169178
currentYCoord += mGroupSpace;
170-
currentYCoord += fontAscentMillimeters( mGroupFont );
179+
double currentMaxXCoord = 0;
171180

172181
p->setPen( QColor( 0, 0, 0 ) );
173-
drawText( p, mBoxSpace, currentYCoord, groupItem->text(), mGroupFont );
174182

175-
//maximum x-coordinate of current item
176-
double currentMaxXCoord = 2 * mBoxSpace + textWidthMillimeters( mGroupFont, groupItem->text() );
177-
maxXCoord = qMax( currentMaxXCoord, maxXCoord );
183+
QStringList lines = splitStringForWrapping( groupItem->text() );
184+
for ( QStringList::Iterator groupPart = lines.begin(); groupPart != lines.end(); ++groupPart )
185+
{
186+
currentYCoord += fontAscentMillimeters( mGroupFont );
187+
drawText( p, mBoxSpace, currentYCoord, *groupPart, mGroupFont );
188+
currentMaxXCoord = 2 * mBoxSpace + textWidthMillimeters( mGroupFont, *groupPart );
189+
maxXCoord = qMax( currentMaxXCoord, maxXCoord );
190+
if ( groupPart != lines.end() )
191+
currentYCoord += mlineSpacing;
192+
}
178193

179194
//children can be other group items or layer items
180195
int numChildItems = groupItem->rowCount();
@@ -216,16 +231,22 @@ void QgsComposerLegend::drawLayerItem( QPainter* p, QgsComposerLayerItem* layerI
216231
if ( !layerItem->text().isEmpty() )
217232
{
218233
currentYCoord += mLayerSpace;
219-
currentYCoord += fontAscentMillimeters( mLayerFont );
220234

221235
//draw layer Item
222236
if ( p )
223237
{
224238
p->setPen( QColor( 0, 0, 0 ) );
225-
drawText( p, mBoxSpace, currentYCoord, layerItem->text(), mLayerFont );
226-
}
227239

228-
maxXCoord = qMax( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mLayerFont, layerItem->text() ) );
240+
QStringList lines = splitStringForWrapping( layerItem->text() );
241+
for ( QStringList::Iterator layerItemPart = lines.begin(); layerItemPart != lines.end(); ++layerItemPart )
242+
{
243+
currentYCoord += fontAscentMillimeters( mLayerFont );
244+
drawText( p, mBoxSpace, currentYCoord, *layerItemPart , mLayerFont );
245+
maxXCoord = qMax( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mLayerFont, *layerItemPart ) );
246+
if ( layerItemPart != lines.end() )
247+
currentYCoord += mlineSpacing ;
248+
}
249+
}
229250
}
230251
else //layer title omited
231252
{
@@ -282,6 +303,8 @@ void QgsComposerLegend::drawLayerChildItems( QPainter* p, QStandardItem* layerIt
282303
continue;
283304
}
284305

306+
int lineCount = splitStringForWrapping( currentItem->text() ).count();
307+
285308
QgsSymbol* symbol = 0;
286309
QgsComposerSymbolItem* symbolItem = dynamic_cast<QgsComposerSymbolItem*>( currentItem );
287310
if ( symbolItem )
@@ -333,7 +356,7 @@ void QgsComposerLegend::drawLayerChildItems( QPainter* p, QStandardItem* layerIt
333356

334357
childYCoords.push_back( currentYCoord );
335358
realItemHeights.push_back( realItemHeight );
336-
currentYCoord += realItemHeight;
359+
currentYCoord += lineCount > 0 ? ( realItemHeight + mlineSpacing ) * lineCount : realItemHeight;
337360
textAlignCoord = qMax( currentXCoord, textAlignCoord );
338361
}
339362

@@ -343,8 +366,16 @@ void QgsComposerLegend::drawLayerChildItems( QPainter* p, QStandardItem* layerIt
343366
if ( p )
344367
{
345368
p->setPen( QColor( 0, 0, 0 ) );
346-
drawText( p, textAlignCoord, childYCoords.at( i ) + textHeight + ( realItemHeights.at( i ) - textHeight ) / 2, layerItem->child( i, 0 )->text(), mItemFont );
347-
maxXCoord = qMax( maxXCoord, textAlignCoord + mBoxSpace + textWidthMillimeters( mItemFont, layerItem->child( i, 0 )->text() ) );
369+
370+
QStringList lines = splitStringForWrapping( layerItem->child( i, 0 )->text() );
371+
double textY = childYCoords.at( i ) + textHeight + ( realItemHeights.at( i ) - textHeight ) / 2;
372+
for ( QStringList::Iterator itemPart = lines.begin(); itemPart != lines.end(); ++itemPart )
373+
{
374+
drawText( p, textAlignCoord, textY , *itemPart , mItemFont );
375+
maxXCoord = qMax( maxXCoord, textAlignCoord + mBoxSpace + textWidthMillimeters( mItemFont, *itemPart ) );
376+
if ( itemPart != lines.end() )
377+
textY += mlineSpacing + textHeight + ( realItemHeights.at( i ) - textHeight ) / 2;
378+
}
348379
}
349380
}
350381
}
@@ -649,6 +680,7 @@ bool QgsComposerLegend::writeXML( QDomElement& elem, QDomDocument & doc ) const
649680
composerLegendElem.setAttribute( "iconLabelSpace", QString::number( mIconLabelSpace ) );
650681
composerLegendElem.setAttribute( "symbolWidth", mSymbolWidth );
651682
composerLegendElem.setAttribute( "symbolHeight", mSymbolHeight );
683+
composerLegendElem.setAttribute( "wrapChar", mWrapChar );
652684

653685
if ( mComposerMap )
654686
{
@@ -706,6 +738,8 @@ bool QgsComposerLegend::readXML( const QDomElement& itemElem, const QDomDocument
706738
mSymbolWidth = itemElem.attribute( "symbolWidth", "7.0" ).toDouble();
707739
mSymbolHeight = itemElem.attribute( "symbolHeight", "14.0" ).toDouble();
708740

741+
mWrapChar = itemElem.attribute( "wrapChar" );
742+
709743
//composer map
710744
if ( !itemElem.attribute( "map" ).isEmpty() )
711745
{
@@ -743,3 +777,14 @@ void QgsComposerLegend::invalidateCurrentMap()
743777
disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
744778
mComposerMap = 0;
745779
}
780+
781+
QStringList QgsComposerLegend::splitStringForWrapping( QString stringToSplt )
782+
{
783+
QStringList list;
784+
// If the string contains nothing then just return the string without spliting.
785+
if ( mWrapChar.count() == 0 )
786+
list << stringToSplt;
787+
else
788+
list = stringToSplt.split( mWrapChar );
789+
return list;
790+
}

src/core/composer/qgscomposerlegend.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ class CORE_EXPORT QgsComposerLegend: public QgsComposerItem
9090
double symbolHeight() const {return mSymbolHeight;}
9191
void setSymbolHeight( double h ) {mSymbolHeight = h;}
9292

93+
void setWrapChar( const QString& t ) {mWrapChar = t;}
94+
QString wrapChar() const {return mWrapChar;}
95+
9396
void setComposerMap( const QgsComposerMap* map );
9497
const QgsComposerMap* composerMap() const { return mComposerMap; }
9598

@@ -116,6 +119,7 @@ class CORE_EXPORT QgsComposerLegend: public QgsComposerItem
116119

117120
protected:
118121
QString mTitle;
122+
QString mWrapChar;
119123

120124
//different fonts for entries
121125
QFont mTitleFont;
@@ -138,6 +142,9 @@ class CORE_EXPORT QgsComposerLegend: public QgsComposerItem
138142
/**Height of symbol icon*/
139143
double mSymbolHeight;
140144

145+
/** Spacing between lines when wrapped */
146+
double mlineSpacing;
147+
141148
QgsLegendModel mLegendModel;
142149

143150
/**Reference to map (because symbols are sometimes in map units)*/
@@ -171,6 +178,11 @@ class CORE_EXPORT QgsComposerLegend: public QgsComposerItem
171178

172179
/**Helper function that lists ids of layers contained in map canvas*/
173180
QStringList layerIdList() const;
181+
182+
private:
183+
/** Splits a string using the the wrap char taking into account handling empty
184+
wrap char which means no wrapping */
185+
QStringList splitStringForWrapping( QString stringToSplt );
174186
};
175187

176188
#endif

0 commit comments

Comments
 (0)