00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "qgscomposerlegend.h"
00019 #include "qgscomposerlegenditem.h"
00020 #include "qgsmaplayer.h"
00021 #include "qgsmaplayerregistry.h"
00022 #include "qgsmaprenderer.h"
00023 #include "qgsrenderer.h"
00024 #include "qgssymbol.h"
00025 #include "qgssymbolv2.h"
00026 #include <QDomDocument>
00027 #include <QDomElement>
00028 #include <QPainter>
00029
00030 QgsComposerLegend::QgsComposerLegend( QgsComposition* composition )
00031 : QgsComposerItem( composition )
00032 , mTitle( tr( "Legend" ) )
00033 , mBoxSpace( 2 )
00034 , mLayerSpace( 3 )
00035 , mSymbolSpace( 2 )
00036 , mIconLabelSpace( 2 )
00037 {
00038
00039
00040
00041 mTitleFont.setPointSizeF( 16.0 );
00042 mGroupFont.setPointSizeF( 14.0 );
00043 mLayerFont.setPointSizeF( 12.0 );
00044 mItemFont.setPointSizeF( 12.0 );
00045
00046 mSymbolWidth = 7;
00047 mSymbolHeight = 4;
00048 adjustBoxSize();
00049
00050 connect( &mLegendModel, SIGNAL( layersChanged() ), this, SLOT( synchronizeWithModel() ) );
00051 }
00052
00053 QgsComposerLegend::QgsComposerLegend(): QgsComposerItem( 0 )
00054 {
00055
00056 }
00057
00058 QgsComposerLegend::~QgsComposerLegend()
00059 {
00060
00061 }
00062
00063 void QgsComposerLegend::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
00064 {
00065 paintAndDetermineSize( painter );
00066 }
00067
00068 QSizeF QgsComposerLegend::paintAndDetermineSize( QPainter* painter )
00069 {
00070 QSizeF size;
00071 double maxXCoord = 0;
00072
00073
00074
00075
00076 QStandardItem* rootItem = mLegendModel.invisibleRootItem();
00077 if ( !rootItem )
00078 {
00079 return size;
00080 }
00081
00082
00083 if ( painter )
00084 {
00085 painter->save();
00086 drawBackground( painter );
00087 painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
00088 }
00089
00090 int numLayerItems = rootItem->rowCount();
00091 QStandardItem* currentLayerItem = 0;
00092 double currentYCoordinate = mBoxSpace;
00093
00094
00095
00096
00097 currentYCoordinate += fontAscentMillimeters( mTitleFont );
00098 if ( painter )
00099 {
00100 painter->setPen( QColor( 0, 0, 0 ) );
00101 drawText( painter, mBoxSpace, currentYCoordinate, mTitle, mTitleFont );
00102 }
00103
00104 maxXCoord = 2 * mBoxSpace + textWidthMillimeters( mTitleFont, mTitle );
00105
00106 for ( int i = 0; i < numLayerItems; ++i )
00107 {
00108 currentLayerItem = rootItem->child( i );
00109 QgsComposerLegendItem* currentLegendItem = dynamic_cast<QgsComposerLegendItem*>( currentLayerItem );
00110 if ( currentLegendItem )
00111 {
00112 QgsComposerLegendItem::ItemType type = currentLegendItem->itemType();
00113 if ( type == QgsComposerLegendItem::GroupItem )
00114 {
00115 drawGroupItem( painter, dynamic_cast<QgsComposerGroupItem*>( currentLegendItem ), currentYCoordinate, maxXCoord );
00116 }
00117 else if ( type == QgsComposerLegendItem::LayerItem )
00118 {
00119 drawLayerItem( painter, dynamic_cast<QgsComposerLayerItem*>( currentLegendItem ), currentYCoordinate, maxXCoord );
00120 }
00121 }
00122 }
00123
00124 currentYCoordinate += mBoxSpace;
00125
00126 size.setHeight( currentYCoordinate );
00127 size.setWidth( maxXCoord );
00128
00129
00130 if ( painter && currentYCoordinate > rect().height() )
00131 {
00132 setSceneRect( QRectF( transform().dx(), transform().dy(), rect().width(), currentYCoordinate ) );
00133 }
00134 if ( painter && maxXCoord > rect().width() )
00135 {
00136 setSceneRect( QRectF( transform().dx(), transform().dy(), maxXCoord, rect().height() ) );
00137 }
00138
00139 if ( painter )
00140 {
00141 painter->restore();
00142
00143
00144 drawFrame( painter );
00145 if ( isSelected() )
00146 {
00147 drawSelectionBoxes( painter );
00148 }
00149 }
00150
00151 return size;
00152 }
00153
00154 void QgsComposerLegend::drawGroupItem( QPainter* p, QgsComposerGroupItem* groupItem, double& currentYCoord, double& maxXCoord )
00155 {
00156 if ( !p || !groupItem )
00157 {
00158 return;
00159 }
00160
00161 currentYCoord += mLayerSpace;
00162 currentYCoord += fontAscentMillimeters( mGroupFont );
00163
00164 p->setPen( QColor( 0, 0, 0 ) );
00165 drawText( p, mBoxSpace, currentYCoord, groupItem->text(), mGroupFont );
00166 maxXCoord = std::max( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mGroupFont, groupItem->text() ) );
00167
00168
00169 int numChildItems = groupItem->rowCount();
00170 QStandardItem* currentChildItem = 0;
00171
00172 for ( int i = 0; i < numChildItems; ++i )
00173 {
00174 currentChildItem = groupItem->child( i );
00175 QgsComposerLegendItem* currentLegendItem = dynamic_cast<QgsComposerLegendItem*>( currentChildItem );
00176 QgsComposerLegendItem::ItemType type = currentLegendItem->itemType();
00177 if ( type == QgsComposerLegendItem::GroupItem )
00178 {
00179 drawGroupItem( p, dynamic_cast<QgsComposerGroupItem*>( currentLegendItem ), currentYCoord, maxXCoord );
00180 }
00181 else if ( type == QgsComposerLegendItem::LayerItem )
00182 {
00183 drawLayerItem( p, dynamic_cast<QgsComposerLayerItem*>( currentLegendItem ), currentYCoord, maxXCoord );
00184 }
00185 }
00186 }
00187
00188 void QgsComposerLegend::drawLayerItem( QPainter* p, QgsComposerLayerItem* layerItem, double& currentYCoord, double& maxXCoord )
00189 {
00190 if ( !layerItem )
00191 {
00192 return;
00193 }
00194
00195 int opacity = 255;
00196 QgsMapLayer* currentLayer = QgsMapLayerRegistry::instance()->mapLayer( layerItem->layerID() );
00197 if ( currentLayer )
00198 {
00199 opacity = currentLayer->getTransparency();
00200 }
00201
00202
00203 if ( !layerItem->text().isEmpty() )
00204 {
00205 currentYCoord += mLayerSpace;
00206 currentYCoord += fontAscentMillimeters( mLayerFont );
00207
00208
00209 if ( p )
00210 {
00211 p->setPen( QColor( 0, 0, 0 ) );
00212 drawText( p, mBoxSpace, currentYCoord, layerItem->text(), mLayerFont );
00213 }
00214
00215 maxXCoord = std::max( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mLayerFont, layerItem->text() ) );
00216 }
00217
00218 drawLayerChildItems( p, layerItem, currentYCoord, maxXCoord, opacity );
00219 }
00220
00221 void QgsComposerLegend::adjustBoxSize()
00222 {
00223 QSizeF size = paintAndDetermineSize( 0 );
00224 if ( size.isValid() )
00225 {
00226 setSceneRect( QRectF( transform().dx(), transform().dy(), size.width(), size.height() ) );
00227 }
00228 }
00229
00230 void QgsComposerLegend::drawLayerChildItems( QPainter* p, QStandardItem* layerItem, double& currentYCoord, double& maxXCoord, int layerOpacity )
00231 {
00232 if ( !layerItem )
00233 {
00234 return;
00235 }
00236
00237
00238 double itemHeight = std::max( mSymbolHeight, fontAscentMillimeters( mItemFont ) );
00239
00240 QStandardItem* currentItem;
00241
00242 int numChildren = layerItem->rowCount();
00243
00244 for ( int i = 0; i < numChildren; ++i )
00245 {
00246
00247 double realSymbolHeight;
00248 double realItemHeight = itemHeight;
00249
00250 currentYCoord += mSymbolSpace;
00251 double currentXCoord = mBoxSpace;
00252
00253 currentItem = layerItem->child( i, 0 );
00254
00255 if ( !currentItem )
00256 {
00257 continue;
00258 }
00259
00260 QgsSymbol* symbol = 0;
00261 QgsComposerSymbolItem* symbolItem = dynamic_cast<QgsComposerSymbolItem*>( currentItem );
00262 if ( symbolItem )
00263 {
00264 symbol = symbolItem->symbol();
00265 }
00266
00267 QgsSymbolV2* symbolNg = 0;
00268 QgsComposerSymbolV2Item* symbolV2Item = dynamic_cast<QgsComposerSymbolV2Item*>( currentItem );
00269 if ( symbolV2Item )
00270 {
00271 symbolNg = symbolV2Item->symbolV2();
00272 }
00273
00274 if ( symbol )
00275 {
00276
00277 drawSymbol( p, symbol, currentYCoord + ( itemHeight - mSymbolHeight ) / 2, currentXCoord, realSymbolHeight, layerOpacity );
00278 realItemHeight = std::max( realSymbolHeight, itemHeight );
00279 currentXCoord += mIconLabelSpace;
00280 }
00281 else if ( symbolNg )
00282 {
00283 drawSymbolV2( p, symbolNg, currentYCoord + ( itemHeight - mSymbolHeight ) / 2, currentXCoord, realSymbolHeight, layerOpacity );
00284 realItemHeight = std::max( realSymbolHeight, itemHeight );
00285 currentXCoord += mIconLabelSpace;
00286 }
00287 else
00288 {
00289 QIcon symbolIcon = currentItem->icon();
00290 if ( !symbolIcon.isNull() && p )
00291 {
00292 symbolIcon.paint( p, currentXCoord, currentYCoord, mSymbolWidth, mSymbolHeight );
00293 currentXCoord += mSymbolWidth;
00294 currentXCoord += mIconLabelSpace;
00295 }
00296 }
00297
00298
00299 if ( p )
00300 {
00301 p->setPen( QColor( 0, 0, 0 ) );
00302 drawText( p, currentXCoord, currentYCoord + fontAscentMillimeters( mItemFont ) + ( realItemHeight - fontAscentMillimeters( mItemFont ) ) / 2, currentItem->text(), mItemFont );
00303 currentXCoord += textWidthMillimeters( mItemFont, currentItem->text() );
00304 }
00305 currentXCoord += mBoxSpace;
00306
00307 maxXCoord = std::max( maxXCoord, currentXCoord );
00308
00309 currentYCoord += realItemHeight;
00310 }
00311 }
00312
00313 void QgsComposerLegend::drawSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, double& symbolHeight, int layerOpacity ) const
00314 {
00315 if ( !s )
00316 {
00317 return;
00318 }
00319
00320 QGis::GeometryType symbolType = s->type();
00321 switch ( symbolType )
00322 {
00323 case QGis::Point:
00324 drawPointSymbol( p, s, currentYCoord, currentXPosition, symbolHeight, layerOpacity );
00325 break;
00326 case QGis::Line:
00327 drawLineSymbol( p, s, currentYCoord, currentXPosition, layerOpacity );
00328 symbolHeight = mSymbolHeight;
00329 break;
00330 case QGis::Polygon:
00331 drawPolygonSymbol( p, s, currentYCoord, currentXPosition, layerOpacity );
00332 symbolHeight = mSymbolHeight;
00333 break;
00334 case QGis::UnknownGeometry:
00335 case QGis::NoGeometry:
00336
00337 break;
00338 }
00339 }
00340
00341 void QgsComposerLegend::drawSymbolV2( QPainter* p, QgsSymbolV2* s, double currentYCoord, double& currentXPosition, double& symbolHeight, int layerOpacity ) const
00342 {
00343 if ( !p || !s )
00344 {
00345 return;
00346 }
00347
00348 double rasterScaleFactor = 1.0;
00349 if ( p )
00350 {
00351 QPaintDevice* paintDevice = p->device();
00352 if ( !paintDevice )
00353 {
00354 return;
00355 }
00356 rasterScaleFactor = ( paintDevice->logicalDpiX() + paintDevice->logicalDpiY() ) / 2.0 / 25.4;
00357 }
00358 p->save();
00359 p->translate( currentXPosition, currentYCoord );
00360 p->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
00361 s->drawPreviewIcon( p, QSize( mSymbolWidth * rasterScaleFactor, mSymbolHeight * rasterScaleFactor ) );
00362 p->restore();
00363 currentXPosition += mSymbolWidth;
00364 symbolHeight = mSymbolHeight;
00365 }
00366
00367 void QgsComposerLegend::drawPointSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, double& symbolHeight, int opacity ) const
00368 {
00369 if ( !s )
00370 {
00371 return;
00372 }
00373
00374 QImage pointImage;
00375 double rasterScaleFactor = 1.0;
00376 if ( p )
00377 {
00378 QPaintDevice* paintDevice = p->device();
00379 if ( !paintDevice )
00380 {
00381 return;
00382 }
00383
00384 rasterScaleFactor = ( paintDevice->logicalDpiX() + paintDevice->logicalDpiY() ) / 2.0 / 25.4;
00385 }
00386
00387
00388 pointImage = s->getPointSymbolAsImage( 1.0, false, Qt::yellow, 1.0, 0.0, rasterScaleFactor, opacity / 255.0 );
00389
00390 if ( p )
00391 {
00392 p->save();
00393 p->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
00394
00395 QPointF imageTopLeft( currentXPosition * rasterScaleFactor, currentYCoord * rasterScaleFactor );
00396 p->drawImage( imageTopLeft, pointImage );
00397 p->restore();
00398 }
00399
00400 currentXPosition += s->pointSize();
00401 symbolHeight = s->pointSize();
00402 }
00403
00404 void QgsComposerLegend::drawLineSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, int opacity ) const
00405 {
00406 if ( !s )
00407 {
00408 return;
00409 }
00410
00411 double yCoord = currentYCoord + mSymbolHeight / 2;
00412
00413 if ( p )
00414 {
00415 p->save();
00416 QPen symbolPen = s->pen();
00417 QColor penColor = symbolPen.color();
00418 penColor.setAlpha( opacity );
00419 symbolPen.setColor( penColor );
00420 symbolPen.setCapStyle( Qt::FlatCap );
00421 p->setPen( symbolPen );
00422 p->drawLine( QPointF( currentXPosition, yCoord ), QPointF( currentXPosition + mSymbolWidth, yCoord ) );
00423 p->restore();
00424 }
00425
00426 currentXPosition += mSymbolWidth;
00427 }
00428
00429 void QgsComposerLegend::drawPolygonSymbol( QPainter* p, QgsSymbol* s, double currentYCoord, double& currentXPosition, int opacity ) const
00430 {
00431 if ( !s )
00432 {
00433 return;
00434 }
00435
00436 if ( p )
00437 {
00438
00439 QBrush symbolBrush = s->brush();
00440 QColor brushColor = symbolBrush.color();
00441 brushColor.setAlpha( opacity );
00442 symbolBrush.setColor( brushColor );
00443 QPaintDevice* paintDevice = p->device();
00444 if ( paintDevice )
00445 {
00446 double rasterScaleFactor = ( paintDevice->logicalDpiX() + paintDevice->logicalDpiY() ) / 2.0 / 25.4;
00447 QgsRenderer::scaleBrush( symbolBrush, rasterScaleFactor );
00448 }
00449 p->setBrush( symbolBrush );
00450
00451 QPen symbolPen = s->pen();
00452 QColor penColor = symbolPen.color();
00453 penColor.setAlpha( opacity );
00454 symbolPen.setColor( penColor );
00455 p->setPen( symbolPen );
00456
00457 p->drawRect( QRectF( currentXPosition, currentYCoord, mSymbolWidth, mSymbolHeight ) );
00458 }
00459
00460 currentXPosition += mSymbolWidth;
00461 }
00462
00463 QStringList QgsComposerLegend::layerIdList() const
00464 {
00465
00466 if ( mComposition )
00467 {
00468 QgsMapRenderer* r = mComposition->mapRenderer();
00469 if ( r )
00470 {
00471 return r->layerSet();
00472 }
00473 }
00474 return QStringList();
00475 }
00476
00477 void QgsComposerLegend::synchronizeWithModel()
00478 {
00479 adjustBoxSize();
00480 update();
00481 }
00482
00483 void QgsComposerLegend::setTitleFont( const QFont& f )
00484 {
00485 mTitleFont = f;
00486 adjustBoxSize();
00487 update();
00488 }
00489
00490 void QgsComposerLegend::setGroupFont( const QFont& f )
00491 {
00492 mGroupFont = f;
00493 adjustBoxSize();
00494 update();
00495 }
00496
00497 void QgsComposerLegend::setLayerFont( const QFont& f )
00498 {
00499 mLayerFont = f;
00500 adjustBoxSize();
00501 update();
00502 }
00503
00504 void QgsComposerLegend::setItemFont( const QFont& f )
00505 {
00506 mItemFont = f;
00507 adjustBoxSize();
00508 update();
00509 }
00510
00511 QFont QgsComposerLegend::titleFont() const
00512 {
00513 return mTitleFont;
00514 }
00515
00516 QFont QgsComposerLegend::groupFont() const
00517 {
00518 return mGroupFont;
00519 }
00520
00521 QFont QgsComposerLegend::layerFont() const
00522 {
00523 return mLayerFont;
00524 }
00525
00526 QFont QgsComposerLegend::itemFont() const
00527 {
00528 return mItemFont;
00529 }
00530
00531 void QgsComposerLegend::updateLegend()
00532 {
00533 mLegendModel.setLayerSet( layerIdList() );
00534 adjustBoxSize();
00535 update();
00536 }
00537
00538 bool QgsComposerLegend::writeXML( QDomElement& elem, QDomDocument & doc ) const
00539 {
00540 if ( elem.isNull() )
00541 {
00542 return false;
00543 }
00544
00545 QDomElement composerLegendElem = doc.createElement( "ComposerLegend" );
00546
00547
00548 composerLegendElem.setAttribute( "title", mTitle );
00549 composerLegendElem.setAttribute( "titleFont", mTitleFont.toString() );
00550 composerLegendElem.setAttribute( "groupFont", mGroupFont.toString() );
00551 composerLegendElem.setAttribute( "layerFont", mLayerFont.toString() );
00552 composerLegendElem.setAttribute( "itemFont", mItemFont.toString() );
00553 composerLegendElem.setAttribute( "boxSpace", QString::number( mBoxSpace ) );
00554 composerLegendElem.setAttribute( "layerSpace", QString::number( mLayerSpace ) );
00555 composerLegendElem.setAttribute( "symbolSpace", QString::number( mSymbolSpace ) );
00556 composerLegendElem.setAttribute( "iconLabelSpace", QString::number( mIconLabelSpace ) );
00557 composerLegendElem.setAttribute( "symbolWidth", mSymbolWidth );
00558 composerLegendElem.setAttribute( "symbolHeight", mSymbolHeight );
00559
00560
00561 mLegendModel.writeXML( composerLegendElem, doc );
00562
00563 elem.appendChild( composerLegendElem );
00564 return _writeXML( composerLegendElem, doc );
00565 }
00566
00567 bool QgsComposerLegend::readXML( const QDomElement& itemElem, const QDomDocument& doc )
00568 {
00569 if ( itemElem.isNull() )
00570 {
00571 return false;
00572 }
00573
00574
00575 mTitle = itemElem.attribute( "title" );
00576
00577 QString titleFontString = itemElem.attribute( "titleFont" );
00578 if ( !titleFontString.isEmpty() )
00579 {
00580 mTitleFont.fromString( titleFontString );
00581 }
00582
00583 QString groupFontString = itemElem.attribute( "groupFont" );
00584 if ( !groupFontString.isEmpty() )
00585 {
00586 mGroupFont.fromString( groupFontString );
00587 }
00588
00589
00590 QString layerFontString = itemElem.attribute( "layerFont" );
00591 if ( !layerFontString.isEmpty() )
00592 {
00593 mLayerFont.fromString( layerFontString );
00594 }
00595
00596 QString itemFontString = itemElem.attribute( "itemFont" );
00597 if ( !itemFontString.isEmpty() )
00598 {
00599 mItemFont.fromString( itemFontString );
00600 }
00601
00602
00603 mBoxSpace = itemElem.attribute( "boxSpace", "2.0" ).toDouble();
00604 mLayerSpace = itemElem.attribute( "layerSpace", "3.0" ).toDouble();
00605 mSymbolSpace = itemElem.attribute( "symbolSpace", "2.0" ).toDouble();
00606 mIconLabelSpace = itemElem.attribute( "iconLabelSpace", "2.0" ).toDouble();
00607 mSymbolWidth = itemElem.attribute( "symbolWidth", "7.0" ).toDouble();
00608 mSymbolHeight = itemElem.attribute( "symbolHeight", "14.0" ).toDouble();
00609
00610
00611 QDomNodeList modelNodeList = itemElem.elementsByTagName( "Model" );
00612 if ( modelNodeList.size() > 0 )
00613 {
00614 QDomElement modelElem = modelNodeList.at( 0 ).toElement();
00615 mLegendModel.readXML( modelElem, doc );
00616 }
00617
00618
00619 QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
00620 if ( composerItemList.size() > 0 )
00621 {
00622 QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
00623 _readXML( composerItemElem, doc );
00624 }
00625
00626 return true;
00627 }