1
/***************************************************************************
2
qgscomposerlegend.cpp - description
5
copyright : (C) 2008 by Marco Hugentobler
6
email : marco dot hugentobler at karto dot baug dot ethz dot ch
7
***************************************************************************/
9
/***************************************************************************
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
***************************************************************************/
18
#include "qgscomposerlegend.h"
19
#include "qgsmaplayer.h"
20
#include "qgsmaplayerregistry.h"
21
#include "qgsmaprenderer.h"
22
#include "qgsrenderer.h" //for brush scaling
23
#include "qgssymbol.h"
24
#include <QDomDocument>
25
#include <QDomElement>
28
QgsComposerLegend::QgsComposerLegend( QgsComposition* composition ): QgsComposerItem( composition ), mTitle( tr( "Legend" ) ), mBoxSpace( 2 ), mLayerSpace( 3 ), mSymbolSpace( 2 ), mIconLabelSpace( 2 )
30
QStringList idList = layerIdList();
31
mLegendModel.setLayerSet( idList );
33
mTitleFont.setPointSizeF( 14.0 );
34
mLayerFont.setPointSizeF( 12.0 );
35
mItemFont.setPointSizeF( 12.0 );
41
connect( &mLegendModel, SIGNAL( layersChanged() ), this, SLOT( synchronizeWithModel() ) );
44
QgsComposerLegend::QgsComposerLegend(): QgsComposerItem( 0 )
49
QgsComposerLegend::~QgsComposerLegend()
54
void QgsComposerLegend::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
56
paintAndDetermineSize( painter );
59
QSizeF QgsComposerLegend::paintAndDetermineSize( QPainter* painter )
67
QStandardItem* rootItem = mLegendModel.invisibleRootItem();
77
drawBackground( painter );
78
painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
81
int numLayerItems = rootItem->rowCount();
82
QStandardItem* currentLayerItem = 0;
83
double currentYCoordinate = mBoxSpace;
88
currentYCoordinate += fontAscentMillimeters( mTitleFont );
91
painter->setPen( QColor( 0, 0, 0 ) );
92
drawText( painter, mBoxSpace, currentYCoordinate, mTitle, mTitleFont );
95
maxXCoord = 2 * mBoxSpace + textWidthMillimeters( mTitleFont, mTitle );
97
//draw only visible layer items
98
QgsMapRenderer* theMapRenderer = mComposition->mapRenderer();
99
QStringList visibleLayerIds;
100
if ( theMapRenderer )
102
visibleLayerIds = theMapRenderer->layerSet();
106
for ( int i = 0; i < numLayerItems; ++i )
108
currentLayerItem = rootItem->child( i );
109
if ( currentLayerItem )
111
QString currentLayerId = currentLayerItem->data().toString();
113
QgsMapLayer* currentLayer = QgsMapLayerRegistry::instance()->mapLayer( currentLayerId );
116
opacity = currentLayer->getTransparency();
119
if ( visibleLayerIds.contains( currentLayerId ) )
121
//Let the user omit the layer title item by having an empty layer title string
122
if ( !currentLayerItem->text().isEmpty() )
124
currentYCoordinate += mLayerSpace;
125
currentYCoordinate += fontAscentMillimeters( mLayerFont );
130
painter->setPen( QColor( 0, 0, 0 ) );
131
drawText( painter, mBoxSpace, currentYCoordinate, currentLayerItem->text(), mLayerFont );
135
maxXCoord = std::max( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mLayerFont, currentLayerItem->text() ) );
138
drawLayerChildItems( painter, currentLayerItem, currentYCoordinate, maxXCoord, opacity );
143
currentYCoordinate += mBoxSpace;
149
//draw frame and selection boxes if necessary
150
drawFrame( painter );
153
drawSelectionBoxes( painter );
157
size.setHeight( currentYCoordinate );
158
size.setWidth( maxXCoord );
160
//adjust box if width or height is to small
161
if ( painter && currentYCoordinate > rect().width() )
163
setSceneRect( QRectF( transform().dx(), transform().dy(), rect().width(), currentYCoordinate ) );
165
if ( painter && maxXCoord > rect().height() )
167
setSceneRect( QRectF( transform().dx(), transform().dy(), maxXCoord, rect().height() ) );
173
void QgsComposerLegend::adjustBoxSize()
175
QSizeF size = paintAndDetermineSize( 0 );
176
if ( size.isValid() )
178
setSceneRect( QRectF( transform().dx(), transform().dy(), size.width(), size.height() ) );
182
void QgsComposerLegend::drawLayerChildItems( QPainter* p, QStandardItem* layerItem, double& currentYCoord, double& maxXCoord, int layerOpacity )
189
//standerd item height
190
double itemHeight = std::max( mSymbolHeight, fontAscentMillimeters( mItemFont ) );
192
QStandardItem* currentItem;
194
int numChildren = layerItem->rowCount();
196
for ( int i = 0; i < numChildren; ++i )
198
//real symbol height. Can be different from standard height in case of point symbols
199
double realSymbolHeight;
200
double realItemHeight = itemHeight; //will be adjusted if realSymbolHeight turns out to be larger
202
currentYCoord += mSymbolSpace;
203
double currentXCoord = mBoxSpace;
205
currentItem = layerItem->child( i, 0 );
212
//take QgsSymbol* from user data
213
QVariant symbolVariant = currentItem->data();
214
QgsSymbol* symbol = 0;
215
if ( symbolVariant.canConvert<void*>() )
217
void* symbolData = symbolVariant.value<void*>();
218
symbol = ( QgsSymbol* )( symbolData );
221
if ( symbol ) //item with symbol?
224
drawSymbol( p, symbol, currentYCoord + ( itemHeight - mSymbolHeight ) / 2, currentXCoord, realSymbolHeight, layerOpacity );
225
realItemHeight = std::max( realSymbolHeight, itemHeight );
226
currentXCoord += mIconLabelSpace;
228
else //item with icon?
230
QIcon symbolIcon = currentItem->icon();
231
if ( !symbolIcon.isNull() && p )
233
symbolIcon.paint( p, currentXCoord, currentYCoord, mSymbolWidth, mSymbolHeight );
234
currentXCoord += mSymbolWidth;
235
currentXCoord += mIconLabelSpace;
242
p->setPen( QColor( 0, 0, 0 ) );
243
drawText( p, currentXCoord, currentYCoord + fontAscentMillimeters( mItemFont ) + ( realItemHeight - fontAscentMillimeters( mItemFont ) ) / 2, currentItem->text(), mItemFont );
246
maxXCoord = std::max( maxXCoord, currentXCoord + textWidthMillimeters( mItemFont, currentItem->text() ) + mBoxSpace );
248
currentYCoord += realItemHeight;
252
void QgsComposerLegend::drawSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, double& symbolHeight, int layerOpacity ) const
259
QGis::GeometryType symbolType = s->type();
260
switch ( symbolType )
263
drawPointSymbol( p, s, currentYCoord, currentXPosition, symbolHeight, layerOpacity );
266
drawLineSymbol( p, s, currentYCoord, currentXPosition, layerOpacity );
267
symbolHeight = mSymbolHeight;
270
drawPolygonSymbol( p, s, currentYCoord, currentXPosition, layerOpacity );
271
symbolHeight = mSymbolHeight;
273
case QGis::UnknownGeometry:
279
void QgsComposerLegend::drawPointSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, double& symbolHeight, int opacity ) const
287
double rasterScaleFactor = 1.0;
290
QPaintDevice* paintDevice = p->device();
296
rasterScaleFactor = ( paintDevice->logicalDpiX() + paintDevice->logicalDpiY() ) / 2.0 / 25.4;
300
pointImage = s->getPointSymbolAsImage( 1.0, false, Qt::yellow, 1.0, 0.0, rasterScaleFactor, opacity / 255.0 );
305
p->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
307
QPointF imageTopLeft( currentXPosition * rasterScaleFactor, currentYCoord * rasterScaleFactor );
308
p->drawImage( imageTopLeft, pointImage );
312
currentXPosition += s->pointSize(); //pointImage.width() / rasterScaleFactor;
313
symbolHeight = s->pointSize(); //pointImage.height() / rasterScaleFactor;
316
void QgsComposerLegend::drawLineSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, int opacity ) const
323
double yCoord = currentYCoord + mSymbolHeight / 2;
328
QPen symbolPen = s->pen();
329
QColor penColor = symbolPen.color();
330
penColor.setAlpha( opacity );
331
symbolPen.setColor( penColor );
332
symbolPen.setCapStyle( Qt::FlatCap );
333
p->setPen( symbolPen );
334
p->drawLine( QPointF( currentXPosition, yCoord ), QPointF( currentXPosition + mSymbolWidth, yCoord ) );
338
currentXPosition += mSymbolWidth;
341
void QgsComposerLegend::drawPolygonSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, int opacity ) const
350
//scale brush and set transparencies
351
QBrush symbolBrush = s->brush();
352
QColor brushColor = symbolBrush.color();
353
brushColor.setAlpha( opacity );
354
symbolBrush.setColor( brushColor );
355
QPaintDevice* paintDevice = p->device();
358
double rasterScaleFactor = ( paintDevice->logicalDpiX() + paintDevice->logicalDpiY() ) / 2.0 / 25.4;
359
QgsRenderer::scaleBrush( symbolBrush, rasterScaleFactor );
361
p->setBrush( symbolBrush );
363
QPen symbolPen = s->pen();
364
QColor penColor = symbolPen.color();
365
penColor.setAlpha( opacity );
366
symbolPen.setColor( penColor );
367
p->setPen( symbolPen );
369
p->drawRect( QRectF( currentXPosition, currentYCoord, mSymbolWidth, mSymbolHeight ) );
372
currentXPosition += mSymbolWidth;
375
QStringList QgsComposerLegend::layerIdList() const
377
QStringList layerIdList;
378
QMap<QString, QgsMapLayer*> layerMap = QgsMapLayerRegistry::instance()->mapLayers();
379
QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();
381
for ( ; mapIt != layerMap.constEnd(); ++mapIt )
383
layerIdList.push_back( mapIt.key() );
389
void QgsComposerLegend::synchronizeWithModel()
395
void QgsComposerLegend::setTitleFont( const QFont& f )
402
void QgsComposerLegend::setLayerFont( const QFont& f )
409
void QgsComposerLegend::setItemFont( const QFont& f )
416
QFont QgsComposerLegend::titleFont() const
421
QFont QgsComposerLegend::layerFont() const
426
QFont QgsComposerLegend::itemFont() const
431
void QgsComposerLegend::updateLegend()
433
mLegendModel.setLayerSet( layerIdList() );
438
bool QgsComposerLegend::writeXML( QDomElement& elem, QDomDocument & doc ) const
445
QDomElement composerLegendElem = doc.createElement( "ComposerLegend" );
447
//write general properties
448
composerLegendElem.setAttribute( "title", mTitle );
449
composerLegendElem.setAttribute( "titleFont", mTitleFont.toString() );
450
composerLegendElem.setAttribute( "layerFont", mLayerFont.toString() );
451
composerLegendElem.setAttribute( "itemFont", mItemFont.toString() );
452
composerLegendElem.setAttribute( "boxSpace", QString::number( mBoxSpace ) );
453
composerLegendElem.setAttribute( "layerSpace", QString::number( mLayerSpace ) );
454
composerLegendElem.setAttribute( "symbolSpace", QString::number( mSymbolSpace ) );
455
composerLegendElem.setAttribute( "iconLabelSpace", QString::number( mIconLabelSpace ) );
456
composerLegendElem.setAttribute( "symbolWidth", mSymbolWidth );
457
composerLegendElem.setAttribute( "symbolHeight", mSymbolHeight );
459
//write model properties
460
mLegendModel.writeXML( composerLegendElem, doc );
462
elem.appendChild( composerLegendElem );
463
return _writeXML( composerLegendElem, doc );
466
bool QgsComposerLegend::readXML( const QDomElement& itemElem, const QDomDocument& doc )
468
if ( itemElem.isNull() )
473
//read general properties
474
mTitle = itemElem.attribute( "title" );
476
QString titleFontString = itemElem.attribute( "titleFont" );
477
if ( !titleFontString.isEmpty() )
479
mTitleFont.fromString( titleFontString );
482
QString layerFontString = itemElem.attribute( "layerFont" );
483
if ( !layerFontString.isEmpty() )
485
mLayerFont.fromString( layerFontString );
488
QString itemFontString = itemElem.attribute( "itemFont" );
489
if ( !itemFontString.isEmpty() )
491
mItemFont.fromString( itemFontString );
495
mBoxSpace = itemElem.attribute( "boxSpace", "2.0" ).toDouble();
496
mLayerSpace = itemElem.attribute( "layerSpace", "3.0" ).toDouble();
497
mSymbolSpace = itemElem.attribute( "symbolSpace", "2.0" ).toDouble();
498
mIconLabelSpace = itemElem.attribute( "iconLabelSpace", "2.0" ).toDouble();
499
mSymbolWidth = itemElem.attribute( "symbolWidth", "7.0" ).toDouble();
500
mSymbolHeight = itemElem.attribute( "symbolHeight", "14.0" ).toDouble();
502
//read model properties
503
QDomNodeList modelNodeList = itemElem.elementsByTagName( "Model" );
504
if ( modelNodeList.size() > 0 )
506
QDomElement modelElem = modelNodeList.at( 0 ).toElement();
507
mLegendModel.clear();
508
mLegendModel.readXML( modelElem, doc );
511
//restore general composer item properties
512
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
513
if ( composerItemList.size() > 0 )
515
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
516
_readXML( composerItemElem, doc );