QGIS API Documentation  2.15.0-Master (5f66276)
qgscomposerlegend.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerlegend.cpp - description
3  ---------------------
4  begin : June 2008
5  copyright : (C) 2008 by Marco Hugentobler
6  email : marco dot hugentobler at karto dot baug dot ethz dot ch
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 #include <limits>
18 
19 #include "qgscomposerlegendstyle.h"
20 #include "qgscomposerlegend.h"
21 #include "qgscomposerlegenditem.h"
22 #include "qgscomposermap.h"
23 #include "qgscomposition.h"
24 #include "qgscomposermodel.h"
25 #include "qgsmaplayerregistry.h"
26 #include "qgslayertree.h"
27 #include "qgslayertreemodel.h"
28 #include "qgslegendrenderer.h"
29 #include "qgslogger.h"
30 #include "qgsproject.h"
31 #include "qgssymbollayerv2utils.h"
32 #include "qgslayertreeutils.h"
33 #include <QDomDocument>
34 #include <QDomElement>
35 #include <QPainter>
36 
38  : QgsComposerItem( composition )
39  , mCustomLayerTree( nullptr )
40  , mComposerMap( nullptr )
41  , mLegendFilterByMap( false )
42  , mFilterOutAtlas( false )
43  , mFilterAskedForUpdate( false )
44  , mInAtlas( false )
45 {
46  mLegendModel2 = new QgsLegendModelV2( QgsProject::instance()->layerTreeRoot() );
47 
48  adjustBoxSize();
49 
50  connect( &mLegendModel, SIGNAL( layersChanged() ), this, SLOT( synchronizeWithModel() ) );
51 
52  connect( &composition->atlasComposition(), SIGNAL( renderEnded() ), this, SLOT( onAtlasEnded() ) );
53  connect( &composition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( onAtlasFeature( QgsFeature* ) ) );
54 
55  // Connect to the main layertreeroot.
56  // It serves in "auto update mode" as a medium between the main app legend and this one
57  connect( QgsProject::instance()->layerTreeRoot(), SIGNAL( customPropertyChanged( QgsLayerTreeNode*, QString ) ), this, SLOT( nodeCustomPropertyChanged( QgsLayerTreeNode*, QString ) ) );
58 }
59 
61  : QgsComposerItem( nullptr )
62  , mLegendModel2( nullptr )
63  , mCustomLayerTree( nullptr )
64  , mComposerMap( nullptr )
65  , mLegendFilterByMap( false )
66  , mLegendFilterByExpression( false )
67  , mFilterOutAtlas( false )
68  , mFilterAskedForUpdate( false )
69  , mInAtlas( false )
70 {
71 
72 }
73 
75 {
76  delete mLegendModel2;
77  delete mCustomLayerTree;
78 }
79 
80 void QgsComposerLegend::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
81 {
82  Q_UNUSED( itemStyle );
83  Q_UNUSED( pWidget );
84 
85  if ( !painter )
86  return;
87 
88  if ( !shouldDrawItem() )
89  {
90  return;
91  }
92 
93  if ( mFilterAskedForUpdate )
94  {
95  mFilterAskedForUpdate = false;
96  doUpdateFilterByMap();
97  }
98 
99  int dpi = painter->device()->logicalDpiX();
100  double dotsPerMM = dpi / 25.4;
101 
102  if ( mComposition )
103  {
105  mSettings.setDpi( dpi );
106  }
107  if ( mComposerMap )
108  {
109  mSettings.setMmPerMapUnit( mComposerMap->mapUnitsToMM() );
110 
111  // use a temporary QgsMapSettings to find out real map scale
112  QgsMapSettings ms = mComposerMap->composition()->mapSettings();
113  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
114  ms.setExtent( *mComposerMap->currentMapExtent() );
115  ms.setOutputDpi( dpi );
116  mSettings.setMapScale( ms.scale() );
117  }
118 
119  drawBackground( painter );
120  painter->save();
121  //antialiasing on
122  painter->setRenderHint( QPainter::Antialiasing, true );
123  painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
124 
125  QgsLegendRenderer legendRenderer( mLegendModel2, mSettings );
126  legendRenderer.setLegendSize( rect().size() );
127 
128  //adjust box if width or height is too small
129  QSizeF size = legendRenderer.minimumSize();
130  if ( size.height() > rect().height() || size.width() > rect().width() )
131  {
132  //need to resize box
133  QRectF targetRect = QRectF( pos().x(), pos().y(), rect().width(), rect().height() );
134  if ( size.height() > targetRect.height() )
135  targetRect.setHeight( size.height() );
136  if ( size.width() > rect().width() )
137  targetRect.setWidth( size.width() );
138 
139  //set new rect, respecting position mode and data defined size/position
140  setSceneRect( evalItemRect( targetRect, true ) );
141  }
142 
143  legendRenderer.drawLegend( painter );
144 
145  painter->restore();
146 
147  //draw frame and selection boxes if necessary
148  drawFrame( painter );
149  if ( isSelected() )
150  {
151  drawSelectionBoxes( painter );
152  }
153 }
154 
156 {
157  if ( mFilterAskedForUpdate )
158  {
159  mFilterAskedForUpdate = false;
160  doUpdateFilterByMap();
161  }
162 
163  QgsLegendRenderer legendRenderer( mLegendModel2, mSettings );
164  QSizeF size = legendRenderer.minimumSize();
165  if ( painter )
166  legendRenderer.drawLegend( painter );
167  return size;
168 }
169 
170 
172 {
173  QgsLegendRenderer legendRenderer( mLegendModel2, mSettings );
174  QSizeF size = legendRenderer.minimumSize();
175  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( size.width() ).arg( size.height() ) );
176  if ( size.isValid() )
177  {
178  QRectF targetRect = QRectF( pos().x(), pos().y(), size.width(), size.height() );
179  //set new rect, respecting position mode and data defined size/position
180  setSceneRect( evalItemRect( targetRect, true ) );
181  }
182 }
183 
184 
185 void QgsComposerLegend::setCustomLayerTree( QgsLayerTreeGroup* rootGroup )
186 {
187  mLegendModel2->setRootGroup( rootGroup ? rootGroup : QgsProject::instance()->layerTreeRoot() );
188 
189  delete mCustomLayerTree;
190  mCustomLayerTree = rootGroup;
191 }
192 
193 
195 {
196  if ( autoUpdate == autoUpdateModel() )
197  return;
198 
199  setCustomLayerTree( autoUpdate ? nullptr : QgsLayerTree::toGroup( QgsProject::instance()->layerTreeRoot()->clone() ) );
200  adjustBoxSize();
201  updateItem();
202 }
203 
204 void QgsComposerLegend::nodeCustomPropertyChanged( QgsLayerTreeNode*, const QString& )
205 {
206  if ( autoUpdateModel() )
207  {
208  // in "auto update" mode, some parameters on the main app legend may have been changed (expression filtering)
209  // we must then call updateItem to reflect the changes
210  updateItem();
211  }
212 }
213 
215 {
216  return !mCustomLayerTree;
217 }
218 
220 {
221  mLegendFilterByMap = enabled;
222  updateItem();
223 }
224 
226 {
227  mSettings.setTitle( t );
228 
229  if ( mComposition && id().isEmpty() )
230  {
231  //notify the model that the display name has changed
233  }
234 }
235 QString QgsComposerLegend::title() const { return mSettings.title(); }
236 
237 Qt::AlignmentFlag QgsComposerLegend::titleAlignment() const { return mSettings.titleAlignment(); }
238 void QgsComposerLegend::setTitleAlignment( Qt::AlignmentFlag alignment ) { mSettings.setTitleAlignment( alignment ); }
239 
243 
246 
249 
250 double QgsComposerLegend::boxSpace() const { return mSettings.boxSpace(); }
251 void QgsComposerLegend::setBoxSpace( double s ) { mSettings.setBoxSpace( s ); }
252 
253 double QgsComposerLegend::columnSpace() const { return mSettings.columnSpace(); }
254 void QgsComposerLegend::setColumnSpace( double s ) { mSettings.setColumnSpace( s ); }
255 
256 QColor QgsComposerLegend::fontColor() const { return mSettings.fontColor(); }
257 void QgsComposerLegend::setFontColor( const QColor& c ) { mSettings.setFontColor( c ); }
258 
259 double QgsComposerLegend::symbolWidth() const { return mSettings.symbolSize().width(); }
260 void QgsComposerLegend::setSymbolWidth( double w ) { mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) ); }
261 
262 double QgsComposerLegend::symbolHeight() const { return mSettings.symbolSize().height(); }
263 void QgsComposerLegend::setSymbolHeight( double h ) { mSettings.setSymbolSize( QSizeF( mSettings.symbolSize().width(), h ) ); }
264 
265 double QgsComposerLegend::wmsLegendWidth() const { return mSettings.wmsLegendSize().width(); }
266 void QgsComposerLegend::setWmsLegendWidth( double w ) { mSettings.setWmsLegendSize( QSizeF( w, mSettings.wmsLegendSize().height() ) ); }
267 
268 double QgsComposerLegend::wmsLegendHeight() const {return mSettings.wmsLegendSize().height(); }
269 void QgsComposerLegend::setWmsLegendHeight( double h ) { mSettings.setWmsLegendSize( QSizeF( mSettings.wmsLegendSize().width(), h ) ); }
270 
271 void QgsComposerLegend::setWrapChar( const QString& t ) { mSettings.setWrapChar( t ); }
272 QString QgsComposerLegend::wrapChar() const {return mSettings.wrapChar(); }
273 
274 int QgsComposerLegend::columnCount() const { return mSettings.columnCount(); }
275 void QgsComposerLegend::setColumnCount( int c ) { mSettings.setColumnCount( c ); }
276 
277 bool QgsComposerLegend::splitLayer() const { return mSettings.splitLayer(); }
278 void QgsComposerLegend::setSplitLayer( bool s ) { mSettings.setSplitLayer( s ); }
279 
280 bool QgsComposerLegend::equalColumnWidth() const { return mSettings.equalColumnWidth(); }
282 
283 bool QgsComposerLegend::drawRasterBorder() const { return mSettings.drawRasterBorder(); }
284 void QgsComposerLegend::setDrawRasterBorder( bool enabled ) { mSettings.setDrawRasterBorder( enabled ); }
285 
287 void QgsComposerLegend::setRasterBorderColor( const QColor& color ) { mSettings.setRasterBorderColor( color ); }
288 
289 double QgsComposerLegend::rasterBorderWidth() const { return mSettings.rasterBorderWidth(); }
290 void QgsComposerLegend::setRasterBorderWidth( double width ) { mSettings.setRasterBorderWidth( width ); }
291 
293 {
294  adjustBoxSize();
295  updateItem();
296 }
297 
299 {
300  // take layer list from map renderer (to have legend order)
302  adjustBoxSize();
303  updateItem();
304 }
305 
307 {
308  updateFilterByMap( false );
310 }
311 
313 {
314  if ( elem.isNull() )
315  {
316  return false;
317  }
318 
319  QDomElement composerLegendElem = doc.createElement( "ComposerLegend" );
320  elem.appendChild( composerLegendElem );
321 
322  //write general properties
323  composerLegendElem.setAttribute( "title", mSettings.title() );
324  composerLegendElem.setAttribute( "titleAlignment", QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
325  composerLegendElem.setAttribute( "columnCount", QString::number( mSettings.columnCount() ) );
326  composerLegendElem.setAttribute( "splitLayer", QString::number( mSettings.splitLayer() ) );
327  composerLegendElem.setAttribute( "equalColumnWidth", QString::number( mSettings.equalColumnWidth() ) );
328 
329  composerLegendElem.setAttribute( "boxSpace", QString::number( mSettings.boxSpace() ) );
330  composerLegendElem.setAttribute( "columnSpace", QString::number( mSettings.columnSpace() ) );
331 
332  composerLegendElem.setAttribute( "symbolWidth", QString::number( mSettings.symbolSize().width() ) );
333  composerLegendElem.setAttribute( "symbolHeight", QString::number( mSettings.symbolSize().height() ) );
334 
335  composerLegendElem.setAttribute( "rasterBorder", mSettings.drawRasterBorder() );
336  composerLegendElem.setAttribute( "rasterBorderColor", QgsSymbolLayerV2Utils::encodeColor( mSettings.rasterBorderColor() ) );
337  composerLegendElem.setAttribute( "rasterBorderWidth", QString::number( mSettings.rasterBorderWidth() ) );
338 
339  composerLegendElem.setAttribute( "wmsLegendWidth", QString::number( mSettings.wmsLegendSize().width() ) );
340  composerLegendElem.setAttribute( "wmsLegendHeight", QString::number( mSettings.wmsLegendSize().height() ) );
341  composerLegendElem.setAttribute( "wrapChar", mSettings.wrapChar() );
342  composerLegendElem.setAttribute( "fontColor", mSettings.fontColor().name() );
343 
344  if ( mComposerMap )
345  {
346  composerLegendElem.setAttribute( "map", mComposerMap->id() );
347  }
348 
349  QDomElement composerLegendStyles = doc.createElement( "styles" );
350  composerLegendElem.appendChild( composerLegendStyles );
351 
352  style( QgsComposerLegendStyle::Title ).writeXML( "title", composerLegendStyles, doc );
353  style( QgsComposerLegendStyle::Group ).writeXML( "group", composerLegendStyles, doc );
354  style( QgsComposerLegendStyle::Subgroup ).writeXML( "subgroup", composerLegendStyles, doc );
355  style( QgsComposerLegendStyle::Symbol ).writeXML( "symbol", composerLegendStyles, doc );
356  style( QgsComposerLegendStyle::SymbolLabel ).writeXML( "symbolLabel", composerLegendStyles, doc );
357 
358  if ( mCustomLayerTree )
359  {
360  // if not using auto-update - store the custom layer tree
361  mCustomLayerTree->writeXML( composerLegendElem );
362  }
363 
364  if ( mLegendFilterByMap )
365  {
366  composerLegendElem.setAttribute( "legendFilterByMap", "1" );
367  }
368 
369  return _writeXML( composerLegendElem, doc );
370 }
371 
372 static void _readOldLegendGroup( QDomElement& elem, QgsLayerTreeGroup* parentGroup )
373 {
374  QDomElement itemElem = elem.firstChildElement();
375 
376  while ( !itemElem.isNull() )
377  {
378 
379  if ( itemElem.tagName() == "LayerItem" )
380  {
381  QString layerId = itemElem.attribute( "layerId" );
382  if ( QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerId ) )
383  {
384  QgsLayerTreeLayer* nodeLayer = parentGroup->addLayer( layer );
385  QString userText = itemElem.attribute( "userText" );
386  if ( !userText.isEmpty() )
387  nodeLayer->setCustomProperty( "legend/title-label", userText );
388  QString style = itemElem.attribute( "style" );
389  if ( !style.isEmpty() )
390  nodeLayer->setCustomProperty( "legend/title-style", style );
391  QString showFeatureCount = itemElem.attribute( "showFeatureCount" );
392  if ( showFeatureCount.toInt() )
393  nodeLayer->setCustomProperty( "showFeatureCount", 1 );
394 
395  // support for individual legend items (user text, order) not implemented yet
396  }
397  }
398  else if ( itemElem.tagName() == "GroupItem" )
399  {
400  QgsLayerTreeGroup* nodeGroup = parentGroup->addGroup( itemElem.attribute( "userText" ) );
401  QString style = itemElem.attribute( "style" );
402  if ( !style.isEmpty() )
403  nodeGroup->setCustomProperty( "legend/title-style", style );
404 
405  _readOldLegendGroup( itemElem, nodeGroup );
406  }
407 
408  itemElem = itemElem.nextSiblingElement();
409  }
410 }
411 
412 bool QgsComposerLegend::readXML( const QDomElement& itemElem, const QDomDocument& doc )
413 {
414  if ( itemElem.isNull() )
415  {
416  return false;
417  }
418 
419  //read general properties
420  mSettings.setTitle( itemElem.attribute( "title" ) );
421  if ( !itemElem.attribute( "titleAlignment" ).isEmpty() )
422  {
423  mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( "titleAlignment" ).toInt() ) );
424  }
425  int colCount = itemElem.attribute( "columnCount", "1" ).toInt();
426  if ( colCount < 1 ) colCount = 1;
427  mSettings.setColumnCount( colCount );
428  mSettings.setSplitLayer( itemElem.attribute( "splitLayer", "0" ).toInt() == 1 );
429  mSettings.setEqualColumnWidth( itemElem.attribute( "equalColumnWidth", "0" ).toInt() == 1 );
430 
431  QDomNodeList stylesNodeList = itemElem.elementsByTagName( "styles" );
432  if ( !stylesNodeList.isEmpty() )
433  {
434  QDomNode stylesNode = stylesNodeList.at( 0 );
435  for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
436  {
437  QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
439  style.readXML( styleElem, doc );
440  QString name = styleElem.attribute( "name" );
442  if ( name == "title" ) s = QgsComposerLegendStyle::Title;
443  else if ( name == "group" ) s = QgsComposerLegendStyle::Group;
444  else if ( name == "subgroup" ) s = QgsComposerLegendStyle::Subgroup;
445  else if ( name == "symbol" ) s = QgsComposerLegendStyle::Symbol;
446  else if ( name == "symbolLabel" ) s = QgsComposerLegendStyle::SymbolLabel;
447  else continue;
448  setStyle( s, style );
449  }
450  }
451 
452  //font color
453  QColor fontClr;
454  fontClr.setNamedColor( itemElem.attribute( "fontColor", "#000000" ) );
455  mSettings.setFontColor( fontClr );
456 
457  //spaces
458  mSettings.setBoxSpace( itemElem.attribute( "boxSpace", "2.0" ).toDouble() );
459  mSettings.setColumnSpace( itemElem.attribute( "columnSpace", "2.0" ).toDouble() );
460 
461  mSettings.setSymbolSize( QSizeF( itemElem.attribute( "symbolWidth", "7.0" ).toDouble(), itemElem.attribute( "symbolHeight", "14.0" ).toDouble() ) );
462  mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( "wmsLegendWidth", "50" ).toDouble(), itemElem.attribute( "wmsLegendHeight", "25" ).toDouble() ) );
463 
464  mSettings.setDrawRasterBorder( itemElem.attribute( "rasterBorder", "1" ) != "0" );
465  mSettings.setRasterBorderColor( QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "rasterBorderColor", "0,0,0" ) ) );
466  mSettings.setRasterBorderWidth( itemElem.attribute( "rasterBorderWidth", "0" ).toDouble() );
467 
468  mSettings.setWrapChar( itemElem.attribute( "wrapChar" ) );
469 
470  //composer map
471  mLegendFilterByMap = itemElem.attribute( "legendFilterByMap", "0" ).toInt();
472  if ( !itemElem.attribute( "map" ).isEmpty() )
473  {
474  setComposerMap( mComposition->getComposerMapById( itemElem.attribute( "map" ).toInt() ) );
475  }
476 
477  QDomElement oldLegendModelElem = itemElem.firstChildElement( "Model" );
478  if ( !oldLegendModelElem.isNull() )
479  {
480  // QGIS <= 2.4
481  QgsLayerTreeGroup* nodeRoot = new QgsLayerTreeGroup();
482  _readOldLegendGroup( oldLegendModelElem, nodeRoot );
483  setCustomLayerTree( nodeRoot );
484  }
485  else
486  {
487  // QGIS >= 2.6
488  QDomElement layerTreeElem = itemElem.firstChildElement( "layer-tree-group" );
489  setCustomLayerTree( QgsLayerTreeGroup::readXML( layerTreeElem ) );
490  }
491 
492  //restore general composer item properties
493  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
494  if ( !composerItemList.isEmpty() )
495  {
496  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
497  _readXML( composerItemElem, doc );
498  }
499 
500  // < 2.0 projects backward compatibility >>>>>
501  //title font
502  QString titleFontString = itemElem.attribute( "titleFont" );
503  if ( !titleFontString.isEmpty() )
504  {
505  rstyle( QgsComposerLegendStyle::Title ).rfont().fromString( titleFontString );
506  }
507  //group font
508  QString groupFontString = itemElem.attribute( "groupFont" );
509  if ( !groupFontString.isEmpty() )
510  {
511  rstyle( QgsComposerLegendStyle::Group ).rfont().fromString( groupFontString );
512  }
513 
514  //layer font
515  QString layerFontString = itemElem.attribute( "layerFont" );
516  if ( !layerFontString.isEmpty() )
517  {
519  }
520  //item font
521  QString itemFontString = itemElem.attribute( "itemFont" );
522  if ( !itemFontString.isEmpty() )
523  {
525  }
526 
527  if ( !itemElem.attribute( "groupSpace" ).isEmpty() )
528  {
530  }
531  if ( !itemElem.attribute( "layerSpace" ).isEmpty() )
532  {
534  }
535  if ( !itemElem.attribute( "symbolSpace" ).isEmpty() )
536  {
539  }
540  // <<<<<<< < 2.0 projects backward compatibility
541 
542  emit itemChanged();
543  return true;
544 }
545 
547 {
548  if ( !id().isEmpty() )
549  {
550  return id();
551  }
552 
553  //if no id, default to portion of title text
554  QString text = mSettings.title();
555  if ( text.isEmpty() )
556  {
557  return tr( "<legend>" );
558  }
559  if ( text.length() > 25 )
560  {
561  return QString( tr( "%1..." ) ).arg( text.left( 25 ) );
562  }
563  else
564  {
565  return text;
566  }
567 }
568 
570 {
571  if ( mComposerMap )
572  {
573  disconnect( mComposerMap, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
574  disconnect( mComposerMap, SIGNAL( itemChanged() ), this, SLOT( updateFilterByMap() ) );
575  disconnect( mComposerMap, SIGNAL( extentChanged() ), this, SLOT( updateFilterByMap() ) );
576  disconnect( mComposerMap, SIGNAL( layerStyleOverridesChanged() ), this, SLOT( mapLayerStyleOverridesChanged() ) );
577  }
578 
579  mComposerMap = map;
580 
581  if ( map )
582  {
583  QObject::connect( map, SIGNAL( destroyed( QObject* ) ), this, SLOT( invalidateCurrentMap() ) );
584  QObject::connect( map, SIGNAL( itemChanged() ), this, SLOT( updateFilterByMap() ) );
585  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( updateFilterByMap() ) );
586  QObject::connect( map, SIGNAL( layerStyleOverridesChanged() ), this, SLOT( mapLayerStyleOverridesChanged() ) );
587  }
588 
589  updateItem();
590 }
591 
593 {
594  setComposerMap( nullptr );
595 }
596 
597 void QgsComposerLegend::mapLayerStyleOverridesChanged()
598 {
599  if ( !mComposerMap )
600  return;
601 
602  // map's style has been changed, so make sure to update the legend here
603  if ( mLegendFilterByMap )
604  {
605  // legend is being filtered by map, so we need to re run the hit test too
606  // as the style overrides may also have affected the visible symbols
607  updateFilterByMap( false );
608  }
609  else
610  {
611  mLegendModel2->setLayerStyleOverrides( mComposerMap->layerStyleOverrides() );
612 
613  Q_FOREACH ( QgsLayerTreeLayer* nodeLayer, mLegendModel2->rootGroup()->findLayers() )
614  mLegendModel2->refreshLayerLegend( nodeLayer );
615  }
616 
617  adjustBoxSize();
618  updateItem();
619 }
620 
621 void QgsComposerLegend::updateFilterByMap( bool redraw )
622 {
623  if ( isRemoved() )
624  return;
625  // ask for update
626  // the actual update will take place before the redraw.
627  // This is to avoid multiple calls to the filter
628  mFilterAskedForUpdate = true;
629 
630  if ( redraw )
632 }
633 
634 void QgsComposerLegend::doUpdateFilterByMap()
635 {
636  if ( mComposerMap )
637  mLegendModel2->setLayerStyleOverrides( mComposerMap->layerStyleOverrides() );
638  else
640 
641 
642  bool filterByExpression = QgsLayerTreeUtils::hasLegendFilterExpression( *( mCustomLayerTree ? mCustomLayerTree : QgsProject::instance()->layerTreeRoot() ) );
643 
644  if ( mComposerMap && ( mLegendFilterByMap || filterByExpression || mInAtlas ) )
645  {
646  int dpi = mComposition->printResolution();
647 
648  QgsRectangle requestRectangle;
649  mComposerMap->requestedExtent( requestRectangle );
650 
651  QSizeF theSize( requestRectangle.width(), requestRectangle.height() );
652  theSize *= mComposerMap->mapUnitsToMM() * dpi / 25.4;
653 
654  QgsMapSettings ms = mComposerMap->mapSettings( requestRectangle, theSize, dpi );
655 
656  QgsGeometry filterPolygon;
657  if ( mInAtlas )
658  {
659  filterPolygon = composition()->atlasComposition().currentGeometry( composition()->mapSettings().destinationCrs() );
660  }
661  mLegendModel2->setLegendFilter( &ms, /* useExtent */ mInAtlas || mLegendFilterByMap, filterPolygon, /* useExpressions */ true );
662  }
663  else
664  mLegendModel2->setLegendFilterByMap( nullptr );
665 }
666 
668 {
669  mFilterOutAtlas = doFilter;
670 }
671 
673 {
674  return mFilterOutAtlas;
675 }
676 
677 void QgsComposerLegend::onAtlasFeature( QgsFeature* feat )
678 {
679  if ( !feat )
680  return;
681  mInAtlas = mFilterOutAtlas;
682  updateFilterByMap();
683 }
684 
685 void QgsComposerLegend::onAtlasEnded()
686 {
687  mInAtlas = false;
688  updateFilterByMap();
689 }
690 
691 // -------------------------------------------------------------------------
693 #include "qgsvectorlayer.h"
694 
696  : QgsLayerTreeModel( rootNode, parent )
697 {
700 }
701 
703 {
704  // handle custom layer node labels
705  if ( QgsLayerTreeNode* node = index2node( index ) )
706  {
707  if ( QgsLayerTree::isLayer( node ) && ( role == Qt::DisplayRole || role == Qt::EditRole ) && !node->customProperty( "legend/title-label" ).isNull() )
708  {
709  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
710  QString name = node->customProperty( "legend/title-label" ).toString();
711  if ( nodeLayer->customProperty( "showFeatureCount", 0 ).toInt() && role == Qt::DisplayRole )
712  {
713  QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( nodeLayer->layer() );
714  if ( vlayer && vlayer->featureCount() >= 0 )
715  name += QString( " [%1]" ).arg( vlayer->featureCount() );
716  }
717  return name;
718  }
719  }
720 
721  return QgsLayerTreeModel::data( index, role );
722 }
723 
725 {
726  // make the legend nodes selectable even if they are not by default
727  if ( index2legendNode( index ) )
728  return QgsLayerTreeModel::flags( index ) | Qt::ItemIsSelectable;
729 
730  return QgsLayerTreeModel::flags( index );
731 }
double boxSpace() const
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
QString wrapChar() const
void setWrapChar(const QString &t)
Layer tree group node serves as a container for layers and further groups.
QDomNodeList elementsByTagName(const QString &tagname) const
void setLegendSize(QSizeF s)
Set the preferred resulting legend size.
QgsComposerLegend(QgsComposition *composition)
qreal x() const
qreal y() const
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:49
QgsComposerLegendStyle style(QgsComposerLegendStyle::Style s) const
Returns style.
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
bool legendFilterOutAtlas() const
Whether to filter out legend elements outside of the current atlas feature.
double boxSpace() const
void setEqualColumnWidth(bool s)
QgsLayerTreeGroup * addGroup(const QString &name)
Append a new group node with given name. Newly created node is owned by this group.
void setBoxSpace(double s)
void setMmPerMapUnit(double mmPerMapUnit)
double scale() const
Return the calculated scale of the map.
bool splitLayer() const
void readXML(const QDomElement &elem, const QDomDocument &doc)
void setRenderHint(RenderHint hint, bool on)
void setDrawRasterBorder(bool enabled)
Sets whether a border will be drawn around raster symbol items.
QgsLayerTreeGroup * rootGroup() const
Return pointer to the root node of the layer tree. Always a non-null pointer.
QDomNode appendChild(const QDomNode &newChild)
double mapUnitsToMM() const
Returns the conversion factor map units -> mm.
void writeXML(const QString &name, QDomElement &elem, QDomDocument &doc) const
QgsComposerLegendStyle & rstyle(QgsComposerLegendStyle::Style s)
Returns reference to modifiable style.
QString name() const
void setMargin(Side side, double margin)
Item model implementation based on layer tree model for composer legend.
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString attribute(const QString &name, const QString &defValue) const
int columnCount() const
static QgsLayerTreeGroup * readXML(QDomElement &element)
Read group (tree) from XML element <layer-tree-group> and return the newly created group (or null on ...
QgsMapLayer * layer() const
void setSplitLayer(bool s)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
QgsComposerModel * itemsModel()
Returns the items model attached to the composition.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void itemChanged()
Emitted when the item changes.
void requestedExtent(QgsRectangle &extent) const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
static QString encodeColor(const QColor &color)
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
void setSymbolSize(QSizeF s)
void drawLegend(QPainter *painter)
Draw the legend with given painter.
void setColumnSpace(double s)
A item that forms part of a map composition.
void setOutputDpi(double dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
bool isValid() const
QRectF evalItemRect(const QRectF &newRect, const bool resizeOnly=false, const QgsExpressionContext *context=nullptr)
Evaluates an item&#39;s bounding rect to consider data defined position and size of item and reference po...
void save()
QDomElement nextSiblingElement(const QString &tagName) const
double columnSpace() const
double columnSpace() const
Flags flags() const
Return OR-ed combination of model flags.
QMap< QString, QString > layerStyleOverrides() const
Getter for stored overrides of styles for layers.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
QVariant data(const QModelIndex &index, int role) const override
double wmsLegendWidth() const
virtual void drawFrame(QPainter *p)
Draw black frame around item.
QgsComposerLegendStyle style(QgsComposerLegendStyle::Style s) const
Returns style.
void setTitle(const QString &t)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QColor rasterBorderColor() const
Returns the border color for the border drawn around raster symbol items.
void setNamedColor(const QString &name)
double toDouble(bool *ok) const
void updateLegend()
Updates the model and all legend entries.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QDomNodeList childNodes() const
QString tr(const char *sourceText, const char *disambiguation, int n)
bool equalColumnWidth() const
void updateItemDisplayName(QgsComposerItem *item)
Must be called when an item&#39;s display name is modified.
QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group. No type checking is done - use isGroup() to find out whether this operation is ...
Definition: qgslayertree.h:46
void setWmsLegendHeight(double h)
Allow check boxes for legend nodes (if supported by layer&#39;s legend)
void setStyle(QgsComposerLegendStyle::Style s, const QgsComposerLegendStyle &style)
QgsComposerLegendStyle & rstyle(QgsComposerLegendStyle::Style s)
Returns reference to modifiable style.
QgsLayerTreeLayer * addLayer(QgsMapLayer *layer)
Append a new layer node for given map layer. Newly created node is owned by this group.
void setHeight(qreal height)
void adjustBoxSize()
Sets item box to the whole content.
The QgsMapSettings class contains configuration for rendering of the map.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
QColor fontColor() const
QDomElement toElement() const
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
bool isEmpty() const
The QgsLayerTreeModel class is model implementation for Qt item views framework.
double rasterBorderWidth() const
Returns the border width (in millimeters) for the border drawn around raster symbol items...
const char * name() const
QPointF pos() const
QString number(int n, int base)
void setOutputSize(QSize size)
Set the size of the resulting map image.
void setRasterBorderWidth(double width)
Sets the border width for the border drawn around raster symbol items.
bool fromString(const QString &descrip)
int toInt(bool *ok) const
void setRasterBorderWidth(double width)
Sets the border width for the border drawn around raster symbol items.
virtual void updateItem()
Updates item, with the possibility to do custom update for subclasses.
QColor rasterBorderColor() const
Returns the border color for the border drawn around raster symbol items.
bool equalColumnWidth() const
void setSymbolHeight(double h)
void setLegendFilterOutAtlas(bool doFilter)
When set to true, during an atlas rendering, it will filter out legend elements where features are ou...
virtual void drawSelectionBoxes(QPainter *p)
Draws additional graphics on selected items.
int printResolution() const
void setPen(const QColor &color)
void setAttribute(const QString &name, const QString &value)
bool isSelected() const
void setLegendFilterByMap(const QgsMapSettings *settings)
Force only display of legend nodes which are valid for given map settings.
QColor fontColor() const
const QgsComposition * composition() const
Returns the composition the item is attached to.
int toInt(bool *ok, int base) const
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Return legend node for given index.
QList< QgsLayerTreeLayer * > findLayers() const
Find all layer nodes. Searches recursively the whole sub-tree.
void setMapScale(double scale)
bool isEmpty() const
void setComposerMap(const QgsComposerMap *map)
QPaintDevice * device() const
void synchronizeWithModel()
Data changed.
bool drawRasterBorder() const
Returns whether a border will be drawn around raster symbol items.
void setStyleFont(QgsComposerLegendStyle::Style s, const QFont &f)
Set style font.
QString wrapChar() const
void setTitle(const QString &t)
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
This class is a base class for nodes in a layer tree.
QString title() const
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom node.
void setDrawRasterBorder(bool enabled)
Sets whether a border will be drawn around raster symbol items.
void setDpi(int dpi)
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
void setFontColor(const QColor &c)
static bool hasLegendFilterExpression(const QgsLayerTreeGroup &group)
Test if one of the layers in a group has an expression filter.
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:40
void setColumnSpace(double s)
bool autoUpdateModel() const
void setFlag(Flag f, bool on=true)
Enable or disable a model flag.
virtual void writeXML(QDomElement &parentElement) override
Write group (tree) as XML element <layer-tree-group> and add it to the given parent element...
Graphics scene for map printing.
virtual void updateItem() override
Update() overloading.
QSizeF minimumSize()
Run the layout algorithm and determine the size required for legend.
QFont styleFont(QgsComposerLegendStyle::Style s) const
void setLegendFilterByMapEnabled(bool enabled)
Set whether legend items should be filtered to show just the ones visible in the associated map...
Object representing map window.
void setSymbolWidth(double w)
QSizeF paintAndDetermineSize(QPainter *painter)
Paints the legend and calculates its size.
int logicalDpiX() const
void setRasterBorderColor(const QColor &color)
Sets the border color for the border drawn around raster symbol items.
void setRootGroup(QgsLayerTreeGroup *newRootGroup)
Reset the model and use a new root group node.
void invalidateCurrentMap()
Sets mCompositionMap to 0 if the map is deleted.
QgsGeometry currentGeometry(const QgsCoordinateReferenceSystem &projectedTo=QgsCoordinateReferenceSystem()) const
Returns the current atlas geometry in the given projection system (default to the coverage layer&#39;s CR...
virtual QString displayName() const override
Get item display name.
void refreshLayerLegend(QgsLayerTreeLayer *nodeLayer)
Force a refresh of legend nodes of a layer node.
double symbolWidth() const
virtual bool isRemoved() const
Returns whether this item has been removed from the composition.
void setWmsLegendWidth(double w)
bool isNull() const
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
void restore()
bool useAdvancedEffects() const
Returns true if a composition should use advanced effects such as blend modes.
int id() const
Get identification number.
QgsLegendModelV2(QgsLayerTreeGroup *rootNode, QObject *parent=nullptr)
QgsComposition * mComposition
Composer legend components style.
void setWmsLegendSize(QSizeF s)
void setUseAdvancedEffects(bool use)
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
bool drawRasterBorder() const
Returns whether a border will be drawn around raster symbol items.
qreal width() const
bool splitLayer() const
void setAutoUpdateModel(bool autoUpdate)
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
void setStyleMargin(QgsComposerLegendStyle::Style s, double margin)
Set style margin.
double rasterBorderWidth() const
Returns the border width (in millimeters) for the border drawn around raster symbol items...
QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer. No type checking is done - use isLayer() to find out whether this operation is ...
Definition: qgslayertree.h:52
void setWrapChar(const QString &t)
void setWidth(qreal width)
virtual void drawBackground(QPainter *p)
Draw background.
void setColumnCount(int c)
double wmsLegendHeight() const
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
QDomElement firstChildElement(const QString &tagName) const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
void setEqualColumnWidth(bool s)
QString title() const
int length() const
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
QString left(int n) const
QStringList layers() const
Get list of layer IDs for map rendering The layers are stored in the reverse order of how they are re...
void setStyle(QgsComposerLegendStyle::Style s, const QgsComposerLegendStyle &style)
qreal height() const
QgsAtlasComposition & atlasComposition()
static QColor decodeColor(const QString &str)
void setLayerSet(const QStringList &layerIds, double scaleDenominator=-1, const QString &rule="")
QString tagName() const
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Set map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
int size() const
QgsComposerItem(QgsComposition *composition, bool manageZValue=true)
Constructor.
QDomElement createElement(const QString &tagName)
QSizeF symbolSize() const
QSizeF wmsLegendSize() const
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Return layer tree node for given index.
void setFontColor(const QColor &c)
qreal height() const
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
void setLegendFilter(const QgsMapSettings *settings, bool useExtent=true, const QgsGeometry &polygon=QgsGeometry(), bool useExpressions=true)
Filter display of legend nodes for given map settings.
Represents a vector layer which manages a vector based data sets.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
const QgsRectangle * currentMapExtent() const
Returns a pointer to the current map extent, which is either the original user specified extent or th...
QgsMapSettings mapSettings(const QgsRectangle &extent, QSizeF size, int dpi) const
Return map settings that would be used for drawing of the map.
void setBoxSpace(double s)
Allow reordering with drag&#39;n&#39;drop.
double symbolHeight() const
void destroyed(QObject *obj)
qreal width() const
static void _readOldLegendGroup(QDomElement &elem, QgsLayerTreeGroup *parentGroup)
void setSplitLayer(bool s)
void setRasterBorderColor(const QColor &color)
Sets the border color for the border drawn around raster symbol items.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:212
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the node.
Layer tree node points to a map layer.
The QgsLegendRenderer class handles automatic layout and rendering of legend.
QDomNode at(int index) const
QRectF rect() const
typedef ItemFlags
void setFont(const QFont &font)
QString id() const
Get item&#39;s id (which is not necessarly unique)