1 /*************************************************************************** 2 qgslayoutitemlegend.h 3 --------------------- 4 begin : October 2017 5 copyright : (C) 2017 by Nyall Dawson 6 email : nyall dot dawson at gmail dot com 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 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. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef QGSLAYOUTITEMLEGEND_H 19 #define QGSLAYOUTITEMLEGEND_H 20 21 #include "qgis_core.h" 22 #include "qgis_sip.h" 23 #include "qgslayoutitem.h" 24 #include "qgslayertreemodel.h" 25 #include "qgslegendsettings.h" 26 #include "qgslayertreegroup.h" 27 #include "qgsexpressioncontext.h" 28 29 class QgsLayerTreeModel; 30 class QgsSymbol; 31 class QgsLayoutItemMap; 32 class QgsLegendRenderer; 33 class QgsLayoutItemLegend; 34 35 /** 36 * \ingroup core 37 * \brief Item model implementation based on layer tree model for layout legend. 38 * 39 * Overrides some functionality of QgsLayerTreeModel to better fit the needs of layout legends. 40 * 41 * \since QGIS 2.6 42 */ 43 class CORE_EXPORT QgsLegendModel : public QgsLayerTreeModel 44 { 45 Q_OBJECT 46 47 public: 48 //! Construct the model based on the given layer tree 49 QgsLegendModel( QgsLayerTree *rootNode, QObject *parent SIP_TRANSFERTHIS = nullptr, QgsLayoutItemLegend *layout = nullptr ); 50 51 //! Alternative constructor. 52 QgsLegendModel( QgsLayerTree *rootNode, QgsLayoutItemLegend *layout ); 53 54 QVariant data( const QModelIndex &index, int role ) const override; 55 56 Qt::ItemFlags flags( const QModelIndex &index ) const override; 57 58 /** 59 * Returns filtered list of active legend nodes attached to a particular layer node 60 * (by default it returns also legend node embedded in parent layer node (if any) unless skipNodeEmbeddedInParent is TRUE) 61 * \note Parameter skipNodeEmbeddedInParent added in QGIS 2.18 62 * \note Not available in Python bindings 63 * \see layerOriginalLegendNodes() 64 * \since QGIS 3.10 65 */ 66 QList<QgsLayerTreeModelLegendNode *> layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent = false ) const SIP_SKIP; 67 68 /** 69 * Clears any previously cached data for the specified \a node. 70 * \since QGIS 3.14 71 */ 72 void clearCachedData( QgsLayerTreeNode *node ) const; 73 74 signals: 75 76 /** 77 * Emitted to refresh the legend. 78 * \since QGIS 3.10 79 */ 80 void refreshLegend(); 81 82 private slots: 83 84 /** 85 * Handle incoming signal to refresh the legend. 86 * \since QGIS 3.10 87 */ 88 void forceRefresh(); 89 90 private: 91 92 /** 93 * Pointer to the QgsLayoutItemLegend class that made the model. 94 * \since QGIS 3.10 95 */ 96 QgsLayoutItemLegend *mLayoutLegend = nullptr; 97 98 /** 99 * Evaluate the expression or symbol expressions of a given layer node. 100 * \since QGIS 3.14 101 */ 102 QString evaluateLayerExpressions( QgsLayerTreeLayer *nodeLayer ) const; 103 104 }; 105 106 107 108 /** 109 * \ingroup core 110 * \brief A layout item subclass for map legends. 111 * \since QGIS 3.0 112 */ 113 class CORE_EXPORT QgsLayoutItemLegend : public QgsLayoutItem 114 { 115 Q_OBJECT 116 117 public: 118 119 /** 120 * Constructor for QgsLayoutItemLegend, with the specified parent \a layout. 121 */ 122 QgsLayoutItemLegend( QgsLayout *layout ); 123 124 /** 125 * Returns a new legend item for the specified \a layout. 126 * 127 * The caller takes responsibility for deleting the returned object. 128 */ 129 static QgsLayoutItemLegend *create( QgsLayout *layout ) SIP_FACTORY; 130 131 int type() const override; 132 QIcon icon() const override; 133 QgsLayoutItem::Flags itemFlags() const override; 134 //Overridden to show legend title 135 QString displayName() const override; 136 137 /** 138 * Sets the legend's item bounds to fit the whole legend content. 139 */ 140 void adjustBoxSize(); 141 142 /** 143 * Sets whether the legend should automatically resize to fit its contents. 144 * \param enabled set to FALSE to disable automatic resizing. The legend frame will not 145 * be expanded to fit legend items, and items may be cropped from display. 146 * \see resizeToContents() 147 */ 148 void setResizeToContents( bool enabled ); 149 150 /** 151 * Returns whether the legend should automatically resize to fit its contents. 152 * \see setResizeToContents() 153 */ 154 bool resizeToContents() const; 155 156 /** 157 * Returns the legend model. 158 */ model()159 QgsLegendModel *model() { return mLegendModel.get(); } 160 161 /** 162 * Sets whether the legend content should auto update to reflect changes in the project's 163 * layer tree. 164 * \see autoUpdateModel() 165 */ 166 void setAutoUpdateModel( bool autoUpdate ); 167 168 /** 169 * Returns whether the legend content should auto update to reflect changes in the project's 170 * layer tree. 171 * \see setAutoUpdateModel() 172 */ 173 bool autoUpdateModel() const; 174 175 /** 176 * Set whether legend items should be filtered to show just the ones visible in the associated map. 177 * \see legendFilterByMapEnabled() 178 */ 179 void setLegendFilterByMapEnabled( bool enabled ); 180 181 /** 182 * Find out whether legend items are filtered to show just the ones visible in the associated map 183 * \see setLegendFilterByMapEnabled() 184 */ legendFilterByMapEnabled()185 bool legendFilterByMapEnabled() const { return mLegendFilterByMap; } 186 187 /** 188 * When set to TRUE, during an atlas rendering, it will filter out legend elements 189 * where features are outside the current atlas feature. 190 * \see legendFilterOutAtlas() 191 */ 192 void setLegendFilterOutAtlas( bool doFilter ); 193 194 /** 195 * Returns whether to filter out legend elements outside of the current atlas feature. 196 * \see setLegendFilterOutAtlas() 197 */ 198 bool legendFilterOutAtlas() const; 199 200 /** 201 * Sets the legend \a title. 202 * \see title() 203 */ 204 void setTitle( const QString &title ); 205 206 /** 207 * Returns the legend title. 208 * \see setTitle() 209 */ 210 QString title() const; 211 212 /** 213 * Returns the alignment of the legend title. 214 * \see setTitleAlignment() 215 */ 216 Qt::AlignmentFlag titleAlignment() const; 217 218 /** 219 * Sets the \a alignment of the legend title. 220 * \see titleAlignment() 221 */ 222 void setTitleAlignment( Qt::AlignmentFlag alignment ); 223 224 /** 225 * Returns reference to modifiable legend style. 226 */ 227 QgsLegendStyle &rstyle( QgsLegendStyle::Style s ); 228 229 /** 230 * Returns legend style. 231 */ 232 QgsLegendStyle style( QgsLegendStyle::Style s ) const; 233 234 /** 235 * Sets the style of \a component to \a style for the legend. 236 */ 237 void setStyle( QgsLegendStyle::Style component, const QgsLegendStyle &style ); 238 239 /** 240 * Returns the font settings for a legend \a component. 241 * \see setStyleFont() 242 */ 243 QFont styleFont( QgsLegendStyle::Style component ) const; 244 245 /** 246 * Sets the style \a font for a legend \a component. 247 * \see styleFont() 248 */ 249 void setStyleFont( QgsLegendStyle::Style component, const QFont &font ); 250 251 /** 252 * Set the \a margin for a legend \a component. 253 */ 254 void setStyleMargin( QgsLegendStyle::Style component, double margin ); 255 256 /** 257 * Set the \a margin for a particular \a side of a legend \a component. 258 */ 259 void setStyleMargin( QgsLegendStyle::Style component, QgsLegendStyle::Side side, double margin ); 260 261 /** 262 * Returns the spacing in-between lines in layout units. 263 * \see setLineSpacing() 264 */ 265 double lineSpacing() const; 266 267 /** 268 * Sets the \a spacing in-between multiple lines. 269 * \see lineSpacing() 270 */ 271 void setLineSpacing( double spacing ); 272 273 /** 274 * Returns the legend box space. 275 * \see setBoxSpace() 276 */ 277 double boxSpace() const; 278 279 /** 280 * Sets the legend box \a space. 281 * \see boxSpace() 282 */ 283 void setBoxSpace( double space ); 284 285 /** 286 * Returns the legend column spacing. 287 * \see setColumnSpace() 288 */ 289 double columnSpace() const; 290 291 /** 292 * Sets the legend column \a spacing. 293 * \see columnSpace() 294 */ 295 void setColumnSpace( double spacing ); 296 297 /** 298 * Returns the legend font color. 299 * \see setFontColor() 300 */ 301 QColor fontColor() const; 302 303 /** 304 * Sets the legend font \a color. 305 * \see fontColor() 306 */ 307 void setFontColor( const QColor &color ); 308 309 /** 310 * Returns the legend symbol width. 311 * \see setSymbolWidth() 312 */ 313 double symbolWidth() const; 314 315 /** 316 * Sets the legend symbol \a width. 317 * \see symbolWidth() 318 */ 319 void setSymbolWidth( double width ); 320 321 /** 322 * Returns the maximum symbol size (in mm). 0.0 means there is no maximum set. 323 * 324 * \see setMaximumSymbolSize() 325 * \since QGIS 3.16 326 */ 327 double maximumSymbolSize() const; 328 329 /** 330 * Set the maximum symbol \a size for symbol (in millimeters). 331 * 332 * A symbol size of 0.0 indicates no maximum is set. 333 * 334 * \see maximumSymbolSize() 335 * \since QGIS 3.16 336 */ 337 void setMaximumSymbolSize( double size ); 338 339 /** 340 * Returns the minimum symbol size (in mm). A value 0.0 means there is no minimum set. 341 * 342 * \see setMinimumSymbolSize 343 * \since QGIS 3.16 344 */ 345 double minimumSymbolSize() const; 346 347 /** 348 * Set the minimum symbol \a size for symbol (in millimeters). 349 * 350 * A symbol size of 0.0 indicates no minimum is set. 351 * 352 * \see minimumSymbolSize() 353 * \since QGIS 3.16 354 */ 355 void setMinimumSymbolSize( double size ); 356 357 /** 358 * Sets the \a alignment for placement of legend symbols. 359 * 360 * Only Qt::AlignLeft or Qt::AlignRight are supported values. 361 * 362 * \see symbolAlignment() 363 * \since QGIS 3.10 364 */ 365 void setSymbolAlignment( Qt::AlignmentFlag alignment ); 366 367 /** 368 * Returns the alignment for placement of legend symbols. 369 * 370 * Only Qt::AlignLeft or Qt::AlignRight are supported values. 371 * 372 * \see setSymbolAlignment() 373 * \since QGIS 3.10 374 */ 375 Qt::AlignmentFlag symbolAlignment() const; 376 377 /** 378 * Returns the legend symbol height. 379 * \see setSymbolHeight() 380 */ 381 double symbolHeight() const; 382 383 /** 384 * Sets the legend symbol \a height. 385 * \see symbolHeight() 386 */ 387 void setSymbolHeight( double height ); 388 389 /** 390 * Returns the WMS legend width. 391 * \see setWmsLegendWidth() 392 */ 393 double wmsLegendWidth() const; 394 395 /** 396 * Sets the WMS legend \a width. 397 * \see wmsLegendWidth() 398 */ 399 void setWmsLegendWidth( double width ); 400 401 /** 402 * Returns the WMS legend height. 403 * \see setWmsLegendHeight() 404 */ 405 double wmsLegendHeight() const; 406 407 /** 408 * Sets the WMS legend \a height. 409 * \see wmsLegendHeight() 410 */ 411 void setWmsLegendHeight( double height ); 412 413 /** 414 * Sets the legend text wrapping \a string. 415 * \see wrapString() 416 */ 417 void setWrapString( const QString &string ); 418 419 /** 420 * Returns the legend text wrapping string. 421 * \see setWrapString() 422 */ 423 QString wrapString() const; 424 425 /** 426 * Returns the legend column count. 427 * \see setColumnCount() 428 */ 429 int columnCount() const; 430 431 /** 432 * Sets the legend column \a count. 433 * \see columnCount() 434 */ 435 void setColumnCount( int count ); 436 437 /** 438 * Returns whether the legend items from a single layer can be split 439 * over multiple columns. 440 * \see setSplitLayer() 441 */ 442 bool splitLayer() const; 443 444 /** 445 * Sets whether the legend items from a single layer can be split 446 * over multiple columns. 447 * \see splitLayer() 448 */ 449 void setSplitLayer( bool enabled ); 450 451 /** 452 * Returns whether column widths should be equalized. 453 * \see setEqualColumnWidth() 454 */ 455 bool equalColumnWidth() const; 456 457 /** 458 * Sets whether column widths should be equalized. 459 * \see equalColumnWidth() 460 */ 461 void setEqualColumnWidth( bool equalize ); 462 463 /** 464 * Returns whether a stroke will be drawn around raster symbol items. 465 * \see setDrawRasterStroke() 466 * \see rasterStrokeColor() 467 * \see rasterStrokeWidth() 468 */ 469 bool drawRasterStroke() const; 470 471 /** 472 * Sets whether a stroke will be drawn around raster symbol items. 473 * \param enabled set to TRUE to draw borders 474 * \see drawRasterStroke() 475 * \see setRasterStrokeColor() 476 * \see setRasterStrokeWidth() 477 */ 478 void setDrawRasterStroke( bool enabled ); 479 480 /** 481 * Returns the stroke color for the stroke drawn around raster symbol items. The stroke is 482 * only drawn if drawRasterStroke() is TRUE. 483 * \see setRasterStrokeColor() 484 * \see drawRasterStroke() 485 * \see rasterStrokeWidth() 486 */ 487 QColor rasterStrokeColor() const; 488 489 /** 490 * Sets the stroke \a color for the stroke drawn around raster symbol items. The stroke is 491 * only drawn if drawRasterStroke() is TRUE. 492 * \see rasterStrokeColor() 493 * \see setDrawRasterStroke() 494 * \see setRasterStrokeWidth() 495 */ 496 void setRasterStrokeColor( const QColor &color ); 497 498 /** 499 * Returns the stroke width (in layout units) for the stroke drawn around raster symbol items. The stroke is 500 * only drawn if drawRasterStroke() is TRUE. 501 * \see setRasterStrokeWidth() 502 * \see drawRasterStroke() 503 * \see rasterStrokeColor() 504 */ 505 double rasterStrokeWidth() const; 506 507 /** 508 * Sets the stroke width for the stroke drawn around raster symbol items. The stroke is 509 * only drawn if drawRasterStroke() is TRUE. 510 * \see rasterStrokeWidth() 511 * \see setDrawRasterStroke() 512 * \see setRasterStrokeColor() 513 */ 514 void setRasterStrokeWidth( double width ); 515 516 /** 517 * Sets the \a map to associate with the legend. 518 * \see linkedMap() 519 */ 520 void setLinkedMap( QgsLayoutItemMap *map ); 521 522 /** 523 * Returns the associated map. 524 * \see setLinkedMap() 525 */ linkedMap()526 QgsLayoutItemMap *linkedMap() const { return mMap; } 527 528 /** 529 * Returns the name of the theme currently linked to the legend. 530 * 531 * This usually equates to the theme rendered in the linkedMap(). 532 * 533 * \since QGIS 3.14 534 */ 535 QString themeName() const; 536 537 /** 538 * Updates the model and all legend entries. 539 */ 540 void updateLegend(); 541 542 /** 543 * Updates the legend content when filtered by map. 544 */ 545 void updateFilterByMap( bool redraw = true ); 546 547 /** 548 * Returns the legend's renderer settings object. 549 */ legendSettings()550 const QgsLegendSettings &legendSettings() const { return mSettings; } 551 552 void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override; 553 554 void finalizeRestoreFromXml() override; 555 556 QgsExpressionContext createExpressionContext() const override; 557 ExportLayerBehavior exportLayerBehavior() const override; 558 bool accept( QgsStyleEntityVisitorInterface *visitor ) const override; 559 560 public slots: 561 562 void refresh() override; 563 void refreshDataDefinedProperty( QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties ) override; 564 565 protected: 566 void draw( QgsLayoutItemRenderContext &context ) override; 567 bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override; 568 bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ) override; 569 570 private slots: 571 572 //! Removes the associated map if the map is deleted. 573 void invalidateCurrentMap(); 574 575 void updateFilterByMapAndRedraw(); 576 577 578 //! update legend in case style of associated map has changed 579 void mapLayerStyleOverridesChanged(); 580 //! update legend in case theme of associated map has changed 581 void mapThemeChanged( const QString &theme ); 582 583 //! react to atlas 584 void onAtlasEnded(); 585 void onAtlasFeature(); 586 587 void nodeCustomPropertyChanged( QgsLayerTreeNode *node, const QString &key ); 588 589 //! Clears any data cached for the legend model 590 void clearLegendCachedData(); 591 592 private: 593 QgsLayoutItemLegend() = delete; 594 595 //! use new custom layer tree and update model. if new root is NULLPTR, will use project's tree 596 void setCustomLayerTree( QgsLayerTree *rootGroup ); 597 598 void setupMapConnections( QgsLayoutItemMap *map, bool connect = true ); 599 600 void setModelStyleOverrides( const QMap<QString, QString> &overrides ); 601 602 std::unique_ptr< QgsLegendModel > mLegendModel; 603 std::unique_ptr< QgsLayerTreeGroup > mCustomLayerTree; 604 605 QgsLegendSettings mSettings; 606 607 QString mTitle; 608 int mColumnCount = 1; 609 610 QString mMapUuid; 611 QgsLayoutItemMap *mMap = nullptr; 612 613 bool mLegendFilterByMap = false; 614 bool mLegendFilterByExpression = false; 615 616 //! whether to filter out legend elements outside of the atlas feature 617 bool mFilterOutAtlas = false; 618 619 //! tag for update request 620 bool mFilterAskedForUpdate = false; 621 //! actual filter update 622 void doUpdateFilterByMap(); 623 624 bool mInAtlas = false; 625 626 //! Will be FALSE until the associated map scale and DPI have been calculated 627 bool mInitialMapScaleCalculated = false; 628 629 //! Will be TRUE if the legend size should be totally reset at next paint 630 bool mForceResize = false; 631 632 //! Will be TRUE if the legend should be resized automatically to fit contents 633 bool mSizeToContents = true; 634 635 //! Name of theme for legend -- usually the theme associated with the linked map. 636 QString mThemeName; 637 638 friend class QgsCompositionConverter; 639 640 }; 641 642 #endif // QGSLAYOUTITEMLEGEND_H 643 644